corrade-nucleus-nucleons – Blame information for rev 4

Subversion Repositories:
Rev:
Rev Author Line No. Line
2 office 1 /*!
2 * QUnit 2.0.1
3 * https://qunitjs.com/
4 *
5 * Copyright jQuery Foundation and other contributors
6 * Released under the MIT license
7 * https://jquery.org/license
8 *
9 * Date: 2016-07-23T19:39Z
10 */
11  
12 ( function( global ) {
13  
14 var QUnit = {};
15  
16 var Date = global.Date;
17 var now = Date.now || function() {
18 return new Date().getTime();
19 };
20  
21 var setTimeout = global.setTimeout;
22 var clearTimeout = global.clearTimeout;
23  
24 // Store a local window from the global to allow direct references.
25 var window = global.window;
26  
27 var defined = {
28 document: window && window.document !== undefined,
29 setTimeout: setTimeout !== undefined,
30 sessionStorage: ( function() {
31 var x = "qunit-test-string";
32 try {
33 sessionStorage.setItem( x, x );
34 sessionStorage.removeItem( x );
35 return true;
36 } catch ( e ) {
37 return false;
38 }
39 }() )
40 };
41  
42 var fileName = ( sourceFromStacktrace( 0 ) || "" ).replace( /(:\d+)+\)?/, "" ).replace( /.+\//, "" );
43 var globalStartCalled = false;
44 var runStarted = false;
45  
46 var autorun = false;
47  
48 var toString = Object.prototype.toString,
49 hasOwn = Object.prototype.hasOwnProperty;
50  
51 // Returns a new Array with the elements that are in a but not in b
52 function diff( a, b ) {
53 var i, j,
54 result = a.slice();
55  
56 for ( i = 0; i < result.length; i++ ) {
57 for ( j = 0; j < b.length; j++ ) {
58 if ( result[ i ] === b[ j ] ) {
59 result.splice( i, 1 );
60 i--;
61 break;
62 }
63 }
64 }
65 return result;
66 }
67  
68 // From jquery.js
69 function inArray( elem, array ) {
70 if ( array.indexOf ) {
71 return array.indexOf( elem );
72 }
73  
74 for ( var i = 0, length = array.length; i < length; i++ ) {
75 if ( array[ i ] === elem ) {
76 return i;
77 }
78 }
79  
80 return -1;
81 }
82  
83 /**
84 * Makes a clone of an object using only Array or Object as base,
85 * and copies over the own enumerable properties.
86 *
87 * @param {Object} obj
88 * @return {Object} New object with only the own properties (recursively).
89 */
90 function objectValues ( obj ) {
91 var key, val,
92 vals = QUnit.is( "array", obj ) ? [] : {};
93 for ( key in obj ) {
94 if ( hasOwn.call( obj, key ) ) {
95 val = obj[ key ];
96 vals[ key ] = val === Object( val ) ? objectValues( val ) : val;
97 }
98 }
99 return vals;
100 }
101  
102 function extend( a, b, undefOnly ) {
103 for ( var prop in b ) {
104 if ( hasOwn.call( b, prop ) ) {
105 if ( b[ prop ] === undefined ) {
106 delete a[ prop ];
107 } else if ( !( undefOnly && typeof a[ prop ] !== "undefined" ) ) {
108 a[ prop ] = b[ prop ];
109 }
110 }
111 }
112  
113 return a;
114 }
115  
116 function objectType( obj ) {
117 if ( typeof obj === "undefined" ) {
118 return "undefined";
119 }
120  
121 // Consider: typeof null === object
122 if ( obj === null ) {
123 return "null";
124 }
125  
126 var match = toString.call( obj ).match( /^\[object\s(.*)\]$/ ),
127 type = match && match[ 1 ];
128  
129 switch ( type ) {
130 case "Number":
131 if ( isNaN( obj ) ) {
132 return "nan";
133 }
134 return "number";
135 case "String":
136 case "Boolean":
137 case "Array":
138 case "Set":
139 case "Map":
140 case "Date":
141 case "RegExp":
142 case "Function":
143 case "Symbol":
144 return type.toLowerCase();
145 }
146 if ( typeof obj === "object" ) {
147 return "object";
148 }
149 }
150  
151 // Safe object type checking
152 function is( type, obj ) {
153 return QUnit.objectType( obj ) === type;
154 }
155  
156 // Doesn't support IE9, it will return undefined on these browsers
157 // See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
158 function extractStacktrace( e, offset ) {
159 offset = offset === undefined ? 4 : offset;
160  
161 var stack, include, i;
162  
163 if ( e.stack ) {
164 stack = e.stack.split( "\n" );
165 if ( /^error$/i.test( stack[ 0 ] ) ) {
166 stack.shift();
167 }
168 if ( fileName ) {
169 include = [];
170 for ( i = offset; i < stack.length; i++ ) {
171 if ( stack[ i ].indexOf( fileName ) !== -1 ) {
172 break;
173 }
174 include.push( stack[ i ] );
175 }
176 if ( include.length ) {
177 return include.join( "\n" );
178 }
179 }
180 return stack[ offset ];
181 }
182 }
183  
184 function sourceFromStacktrace( offset ) {
185 var error = new Error();
186  
187 // Support: Safari <=7 only, IE <=10 - 11 only
188 // Not all browsers generate the `stack` property for `new Error()`, see also #636
189 if ( !error.stack ) {
190 try {
191 throw error;
192 } catch ( err ) {
193 error = err;
194 }
195 }
196  
197 return extractStacktrace( error, offset );
198 }
199  
200 /**
201 * Config object: Maintain internal state
202 * Later exposed as QUnit.config
203 * `config` initialized at top of scope
204 */
205 var config = {
206  
207 // The queue of tests to run
208 queue: [],
209  
210 // Block until document ready
211 blocking: true,
212  
213 // By default, run previously failed tests first
214 // very useful in combination with "Hide passed tests" checked
215 reorder: true,
216  
217 // By default, modify document.title when suite is done
218 altertitle: true,
219  
220 // HTML Reporter: collapse every test except the first failing test
221 // If false, all failing tests will be expanded
222 collapse: true,
223  
224 // By default, scroll to top of the page when suite is done
225 scrolltop: true,
226  
227 // Depth up-to which object will be dumped
228 maxDepth: 5,
229  
230 // When enabled, all tests must call expect()
231 requireExpects: false,
232  
233 // Placeholder for user-configurable form-exposed URL parameters
234 urlConfig: [],
235  
236 // Set of all modules.
237 modules: [],
238  
239 // Stack of nested modules
240 moduleStack: [],
241  
242 // The first unnamed module
243 currentModule: {
244 name: "",
245 tests: []
246 },
247  
248 callbacks: {}
249 };
250  
251 // Push a loose unnamed module to the modules collection
252 config.modules.push( config.currentModule );
253  
254 // Register logging callbacks
255 function registerLoggingCallbacks( obj ) {
256 var i, l, key,
257 callbackNames = [ "begin", "done", "log", "testStart", "testDone",
258 "moduleStart", "moduleDone" ];
259  
260 function registerLoggingCallback( key ) {
261 var loggingCallback = function( callback ) {
262 if ( objectType( callback ) !== "function" ) {
263 throw new Error(
264 "QUnit logging methods require a callback function as their first parameters."
265 );
266 }
267  
268 config.callbacks[ key ].push( callback );
269 };
270  
271 return loggingCallback;
272 }
273  
274 for ( i = 0, l = callbackNames.length; i < l; i++ ) {
275 key = callbackNames[ i ];
276  
277 // Initialize key collection of logging callback
278 if ( objectType( config.callbacks[ key ] ) === "undefined" ) {
279 config.callbacks[ key ] = [];
280 }
281  
282 obj[ key ] = registerLoggingCallback( key );
283 }
284 }
285  
286 function runLoggingCallbacks( key, args ) {
287 var i, l, callbacks;
288  
289 callbacks = config.callbacks[ key ];
290 for ( i = 0, l = callbacks.length; i < l; i++ ) {
291 callbacks[ i ]( args );
292 }
293 }
294  
295 ( function() {
296 if ( !defined.document ) {
297 return;
298 }
299  
300 // `onErrorFnPrev` initialized at top of scope
301 // Preserve other handlers
302 var onErrorFnPrev = window.onerror;
303  
304 // Cover uncaught exceptions
305 // Returning true will suppress the default browser handler,
306 // returning false will let it run.
307 window.onerror = function( error, filePath, linerNr ) {
308 var ret = false;
309 if ( onErrorFnPrev ) {
310 ret = onErrorFnPrev( error, filePath, linerNr );
311 }
312  
313 // Treat return value as window.onerror itself does,
314 // Only do our handling if not suppressed.
315 if ( ret !== true ) {
316 if ( QUnit.config.current ) {
317 if ( QUnit.config.current.ignoreGlobalErrors ) {
318 return true;
319 }
320 QUnit.pushFailure( error, filePath + ":" + linerNr );
321 } else {
322 QUnit.test( "global failure", extend( function() {
323 QUnit.pushFailure( error, filePath + ":" + linerNr );
324 }, { validTest: true } ) );
325 }
326 return false;
327 }
328  
329 return ret;
330 };
331 }() );
332  
333 // Figure out if we're running the tests from a server or not
334 QUnit.isLocal = !( defined.document && window.location.protocol !== "file:" );
335  
336 // Expose the current QUnit version
337 QUnit.version = "2.0.1";
338  
339 extend( QUnit, {
340  
341 // Call on start of module test to prepend name to all tests
342 module: function( name, testEnvironment, executeNow ) {
343 var module, moduleFns;
344 var currentModule = config.currentModule;
345  
346 if ( arguments.length === 2 ) {
347 if ( objectType( testEnvironment ) === "function" ) {
348 executeNow = testEnvironment;
349 testEnvironment = undefined;
350 }
351 }
352  
353 module = createModule();
354  
355 if ( testEnvironment && ( testEnvironment.setup || testEnvironment.teardown ) ) {
356 console.warn(
357 "Module's `setup` and `teardown` are not hooks anymore on QUnit 2.0, use " +
358 "`beforeEach` and `afterEach` instead\n" +
359 "Details in our upgrade guide at https://qunitjs.com/upgrade-guide-2.x/"
360 );
361 }
362  
363 moduleFns = {
364 before: setHook( module, "before" ),
365 beforeEach: setHook( module, "beforeEach" ),
366 afterEach: setHook( module, "afterEach" ),
367 after: setHook( module, "after" )
368 };
369  
370 if ( objectType( executeNow ) === "function" ) {
371 config.moduleStack.push( module );
372 setCurrentModule( module );
373 executeNow.call( module.testEnvironment, moduleFns );
374 config.moduleStack.pop();
375 module = module.parentModule || currentModule;
376 }
377  
378 setCurrentModule( module );
379  
380 function createModule() {
381 var parentModule = config.moduleStack.length ?
382 config.moduleStack.slice( -1 )[ 0 ] : null;
383 var moduleName = parentModule !== null ?
384 [ parentModule.name, name ].join( " > " ) : name;
385 var module = {
386 name: moduleName,
387 parentModule: parentModule,
388 tests: [],
389 moduleId: generateHash( moduleName ),
390 testsRun: 0
391 };
392  
393 var env = {};
394 if ( parentModule ) {
395 parentModule.childModule = module;
396 extend( env, parentModule.testEnvironment );
397 delete env.beforeEach;
398 delete env.afterEach;
399 }
400 extend( env, testEnvironment );
401 module.testEnvironment = env;
402  
403 config.modules.push( module );
404 return module;
405 }
406  
407 function setCurrentModule( module ) {
408 config.currentModule = module;
409 }
410  
411 },
412  
413 test: test,
414  
415 skip: skip,
416  
417 only: only,
418  
419 start: function( count ) {
420 var globalStartAlreadyCalled = globalStartCalled;
421  
422 if ( !config.current ) {
423 globalStartCalled = true;
424  
425 if ( runStarted ) {
426 throw new Error( "Called start() while test already started running" );
427 } else if ( globalStartAlreadyCalled || count > 1 ) {
428 throw new Error( "Called start() outside of a test context too many times" );
429 } else if ( config.autostart ) {
430 throw new Error( "Called start() outside of a test context when " +
431 "QUnit.config.autostart was true" );
432 } else if ( !config.pageLoaded ) {
433  
434 // The page isn't completely loaded yet, so bail out and let `QUnit.load` handle it
435 config.autostart = true;
436 return;
437 }
438 } else {
439 throw new Error(
440 "QUnit.start cannot be called inside a test context. This feature is removed in " +
441 "QUnit 2.0. For async tests, use QUnit.test() with assert.async() instead.\n" +
442 "Details in our upgrade guide at https://qunitjs.com/upgrade-guide-2.x/"
443 );
444 }
445  
446 scheduleBegin();
447 },
448  
449 config: config,
450  
451 is: is,
452  
453 objectType: objectType,
454  
455 extend: extend,
456  
457 load: function() {
458 config.pageLoaded = true;
459  
460 // Initialize the configuration options
461 extend( config, {
462 stats: { all: 0, bad: 0 },
463 moduleStats: { all: 0, bad: 0 },
464 started: 0,
465 updateRate: 1000,
466 autostart: true,
467 filter: ""
468 }, true );
469  
470 if ( !runStarted ) {
471 config.blocking = false;
472  
473 if ( config.autostart ) {
474 scheduleBegin();
475 }
476 }
477 },
478  
479 stack: function( offset ) {
480 offset = ( offset || 0 ) + 2;
481 return sourceFromStacktrace( offset );
482 }
483 } );
484  
485 registerLoggingCallbacks( QUnit );
486  
487 function scheduleBegin() {
488  
489 runStarted = true;
490  
491 // Add a slight delay to allow definition of more modules and tests.
492 if ( defined.setTimeout ) {
493 setTimeout( function() {
494 begin();
495 }, 13 );
496 } else {
497 begin();
498 }
499 }
500  
501 function begin() {
502 var i, l,
503 modulesLog = [];
504  
505 // If the test run hasn't officially begun yet
506 if ( !config.started ) {
507  
508 // Record the time of the test run's beginning
509 config.started = now();
510  
511 // Delete the loose unnamed module if unused.
512 if ( config.modules[ 0 ].name === "" && config.modules[ 0 ].tests.length === 0 ) {
513 config.modules.shift();
514 }
515  
516 // Avoid unnecessary information by not logging modules' test environments
517 for ( i = 0, l = config.modules.length; i < l; i++ ) {
518 modulesLog.push( {
519 name: config.modules[ i ].name,
520 tests: config.modules[ i ].tests
521 } );
522 }
523  
524 // The test run is officially beginning now
525 runLoggingCallbacks( "begin", {
526 totalTests: Test.count,
527 modules: modulesLog
528 } );
529 }
530  
531 config.blocking = false;
532 process( true );
533 }
534  
535 function process( last ) {
536 function next() {
537 process( last );
538 }
539 var start = now();
540 config.depth = ( config.depth || 0 ) + 1;
541  
542 while ( config.queue.length && !config.blocking ) {
543 if ( !defined.setTimeout || config.updateRate <= 0 ||
544 ( ( now() - start ) < config.updateRate ) ) {
545 if ( config.current ) {
546  
547 // Reset async tracking for each phase of the Test lifecycle
548 config.current.usedAsync = false;
549 }
550 config.queue.shift()();
551 } else {
552 setTimeout( next, 13 );
553 break;
554 }
555 }
556 config.depth--;
557 if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
558 done();
559 }
560 }
561  
562 function done() {
563 var runtime, passed;
564  
565 autorun = true;
566  
567 // Log the last module results
568 if ( config.previousModule ) {
569 runLoggingCallbacks( "moduleDone", {
570 name: config.previousModule.name,
571 tests: config.previousModule.tests,
572 failed: config.moduleStats.bad,
573 passed: config.moduleStats.all - config.moduleStats.bad,
574 total: config.moduleStats.all,
575 runtime: now() - config.moduleStats.started
576 } );
577 }
578 delete config.previousModule;
579  
580 runtime = now() - config.started;
581 passed = config.stats.all - config.stats.bad;
582  
583 runLoggingCallbacks( "done", {
584 failed: config.stats.bad,
585 passed: passed,
586 total: config.stats.all,
587 runtime: runtime
588 } );
589 }
590  
591 function setHook( module, hookName ) {
592 if ( module.testEnvironment === undefined ) {
593 module.testEnvironment = {};
594 }
595  
596 return function( callback ) {
597 module.testEnvironment[ hookName ] = callback;
598 };
599 }
600  
601 var unitSampler,
602 focused = false,
603 priorityCount = 0;
604  
605 function Test( settings ) {
606 var i, l;
607  
608 ++Test.count;
609  
610 this.expected = null;
611 extend( this, settings );
612 this.assertions = [];
613 this.semaphore = 0;
614 this.usedAsync = false;
615 this.module = config.currentModule;
616 this.stack = sourceFromStacktrace( 3 );
617  
618 // Register unique strings
619 for ( i = 0, l = this.module.tests; i < l.length; i++ ) {
620 if ( this.module.tests[ i ].name === this.testName ) {
621 this.testName += " ";
622 }
623 }
624  
625 this.testId = generateHash( this.module.name, this.testName );
626  
627 this.module.tests.push( {
628 name: this.testName,
629 testId: this.testId
630 } );
631  
632 if ( settings.skip ) {
633  
634 // Skipped tests will fully ignore any sent callback
635 this.callback = function() {};
636 this.async = false;
637 this.expected = 0;
638 } else {
639 this.assert = new Assert( this );
640 }
641 }
642  
643 Test.count = 0;
644  
645 Test.prototype = {
646 before: function() {
647 if (
648  
649 // Emit moduleStart when we're switching from one module to another
650 this.module !== config.previousModule ||
651  
652 // They could be equal (both undefined) but if the previousModule property doesn't
653 // yet exist it means this is the first test in a suite that isn't wrapped in a
654 // module, in which case we'll just emit a moduleStart event for 'undefined'.
655 // Without this, reporters can get testStart before moduleStart which is a problem.
656 !hasOwn.call( config, "previousModule" )
657 ) {
658 if ( hasOwn.call( config, "previousModule" ) ) {
659 runLoggingCallbacks( "moduleDone", {
660 name: config.previousModule.name,
661 tests: config.previousModule.tests,
662 failed: config.moduleStats.bad,
663 passed: config.moduleStats.all - config.moduleStats.bad,
664 total: config.moduleStats.all,
665 runtime: now() - config.moduleStats.started
666 } );
667 }
668 config.previousModule = this.module;
669 config.moduleStats = { all: 0, bad: 0, started: now() };
670 runLoggingCallbacks( "moduleStart", {
671 name: this.module.name,
672 tests: this.module.tests
673 } );
674 }
675  
676 config.current = this;
677  
678 if ( this.module.testEnvironment ) {
679 delete this.module.testEnvironment.before;
680 delete this.module.testEnvironment.beforeEach;
681 delete this.module.testEnvironment.afterEach;
682 delete this.module.testEnvironment.after;
683 }
684 this.testEnvironment = extend( {}, this.module.testEnvironment );
685  
686 this.started = now();
687 runLoggingCallbacks( "testStart", {
688 name: this.testName,
689 module: this.module.name,
690 testId: this.testId
691 } );
692  
693 if ( !config.pollution ) {
694 saveGlobal();
695 }
696 },
697  
698 run: function() {
699 var promise;
700  
701 config.current = this;
702  
703 this.callbackStarted = now();
704  
705 if ( config.notrycatch ) {
706 runTest( this );
707 return;
708 }
709  
710 try {
711 runTest( this );
712 } catch ( e ) {
713 this.pushFailure( "Died on test #" + ( this.assertions.length + 1 ) + " " +
714 this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
715  
716 // Else next test will carry the responsibility
717 saveGlobal();
718  
719 // Restart the tests if they're blocking
720 if ( config.blocking ) {
721 internalRecover( this );
722 }
723 }
724  
725 function runTest( test ) {
726 promise = test.callback.call( test.testEnvironment, test.assert );
727 test.resolvePromise( promise );
728 }
729 },
730  
731 after: function() {
732 checkPollution();
733 },
734  
735 queueHook: function( hook, hookName, hookOwner ) {
736 var promise,
737 test = this;
738 return function runHook() {
739 if ( hookName === "before" ) {
740 if ( hookOwner.testsRun !== 0 ) {
741 return;
742 }
743  
744 test.preserveEnvironment = true;
745 }
746  
747 if ( hookName === "after" && hookOwner.testsRun !== numberOfTests( hookOwner ) - 1 ) {
748 return;
749 }
750  
751 config.current = test;
752 if ( config.notrycatch ) {
753 callHook();
754 return;
755 }
756 try {
757 callHook();
758 } catch ( error ) {
759 test.pushFailure( hookName + " failed on " + test.testName + ": " +
760 ( error.message || error ), extractStacktrace( error, 0 ) );
761 }
762  
763 function callHook() {
764 promise = hook.call( test.testEnvironment, test.assert );
765 test.resolvePromise( promise, hookName );
766 }
767 };
768 },
769  
770 // Currently only used for module level hooks, can be used to add global level ones
771 hooks: function( handler ) {
772 var hooks = [];
773  
774 function processHooks( test, module ) {
775 if ( module.parentModule ) {
776 processHooks( test, module.parentModule );
777 }
778 if ( module.testEnvironment &&
779 QUnit.objectType( module.testEnvironment[ handler ] ) === "function" ) {
780 hooks.push( test.queueHook( module.testEnvironment[ handler ], handler, module ) );
781 }
782 }
783  
784 // Hooks are ignored on skipped tests
785 if ( !this.skip ) {
786 processHooks( this, this.module );
787 }
788 return hooks;
789 },
790  
791 finish: function() {
792 config.current = this;
793 if ( config.requireExpects && this.expected === null ) {
794 this.pushFailure( "Expected number of assertions to be defined, but expect() was " +
795 "not called.", this.stack );
796 } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
797 this.pushFailure( "Expected " + this.expected + " assertions, but " +
798 this.assertions.length + " were run", this.stack );
799 } else if ( this.expected === null && !this.assertions.length ) {
800 this.pushFailure( "Expected at least one assertion, but none were run - call " +
801 "expect(0) to accept zero assertions.", this.stack );
802 }
803  
804 var i,
805 skipped = !!this.skip,
806 bad = 0;
807  
808 this.runtime = now() - this.started;
809  
810 config.stats.all += this.assertions.length;
811 config.moduleStats.all += this.assertions.length;
812  
813 for ( i = 0; i < this.assertions.length; i++ ) {
814 if ( !this.assertions[ i ].result ) {
815 bad++;
816 config.stats.bad++;
817 config.moduleStats.bad++;
818 }
819 }
820  
821 notifyTestsRan( this.module );
822 runLoggingCallbacks( "testDone", {
823 name: this.testName,
824 module: this.module.name,
825 skipped: skipped,
826 failed: bad,
827 passed: this.assertions.length - bad,
828 total: this.assertions.length,
829 runtime: skipped ? 0 : this.runtime,
830  
831 // HTML Reporter use
832 assertions: this.assertions,
833 testId: this.testId,
834  
835 // Source of Test
836 source: this.stack
837 } );
838  
839 config.current = undefined;
840 },
841  
842 preserveTestEnvironment: function() {
843 if ( this.preserveEnvironment ) {
844 this.module.testEnvironment = this.testEnvironment;
845 this.testEnvironment = extend( {}, this.module.testEnvironment );
846 }
847 },
848  
849 queue: function() {
850 var priority,
851 test = this;
852  
853 if ( !this.valid() ) {
854 return;
855 }
856  
857 function run() {
858  
859 // Each of these can by async
860 synchronize( [
861 function() {
862 test.before();
863 },
864  
865 test.hooks( "before" ),
866  
867 function() {
868 test.preserveTestEnvironment();
869 },
870  
871 test.hooks( "beforeEach" ),
872  
873 function() {
874 test.run();
875 },
876  
877 test.hooks( "afterEach" ).reverse(),
878 test.hooks( "after" ).reverse(),
879  
880 function() {
881 test.after();
882 },
883  
884 function() {
885 test.finish();
886 }
887 ] );
888 }
889  
890 // Prioritize previously failed tests, detected from sessionStorage
891 priority = QUnit.config.reorder && defined.sessionStorage &&
892 +sessionStorage.getItem( "qunit-test-" + this.module.name + "-" + this.testName );
893  
894 return synchronize( run, priority, config.seed );
895 },
896  
897 pushResult: function( resultInfo ) {
898  
899 // Destructure of resultInfo = { result, actual, expected, message, negative }
900 var source,
901 details = {
902 module: this.module.name,
903 name: this.testName,
904 result: resultInfo.result,
905 message: resultInfo.message,
906 actual: resultInfo.actual,
907 expected: resultInfo.expected,
908 testId: this.testId,
909 negative: resultInfo.negative || false,
910 runtime: now() - this.started
911 };
912  
913 if ( !resultInfo.result ) {
914 source = sourceFromStacktrace();
915  
916 if ( source ) {
917 details.source = source;
918 }
919 }
920  
921 runLoggingCallbacks( "log", details );
922  
923 this.assertions.push( {
924 result: !!resultInfo.result,
925 message: resultInfo.message
926 } );
927 },
928  
929 pushFailure: function( message, source, actual ) {
930 if ( !( this instanceof Test ) ) {
931 throw new Error( "pushFailure() assertion outside test context, was " +
932 sourceFromStacktrace( 2 ) );
933 }
934  
935 var details = {
936 module: this.module.name,
937 name: this.testName,
938 result: false,
939 message: message || "error",
940 actual: actual || null,
941 testId: this.testId,
942 runtime: now() - this.started
943 };
944  
945 if ( source ) {
946 details.source = source;
947 }
948  
949 runLoggingCallbacks( "log", details );
950  
951 this.assertions.push( {
952 result: false,
953 message: message
954 } );
955 },
956  
957 resolvePromise: function( promise, phase ) {
958 var then, resume, message,
959 test = this;
960 if ( promise != null ) {
961 then = promise.then;
962 if ( QUnit.objectType( then ) === "function" ) {
963 resume = internalStop( test );
964 then.call(
965 promise,
966 function() { resume(); },
967 function( error ) {
968 message = "Promise rejected " +
969 ( !phase ? "during" : phase.replace( /Each$/, "" ) ) +
970 " " + test.testName + ": " + ( error.message || error );
971 test.pushFailure( message, extractStacktrace( error, 0 ) );
972  
973 // Else next test will carry the responsibility
974 saveGlobal();
975  
976 // Unblock
977 resume();
978 }
979 );
980 }
981 }
982 },
983  
984 valid: function() {
985 var filter = config.filter,
986 regexFilter = /^(!?)\/([\w\W]*)\/(i?$)/.exec( filter ),
987 module = config.module && config.module.toLowerCase(),
988 fullName = ( this.module.name + ": " + this.testName );
989  
990 function moduleChainNameMatch( testModule ) {
991 var testModuleName = testModule.name ? testModule.name.toLowerCase() : null;
992 if ( testModuleName === module ) {
993 return true;
994 } else if ( testModule.parentModule ) {
995 return moduleChainNameMatch( testModule.parentModule );
996 } else {
997 return false;
998 }
999 }
1000  
1001 function moduleChainIdMatch( testModule ) {
1002 return inArray( testModule.moduleId, config.moduleId ) > -1 ||
1003 testModule.parentModule && moduleChainIdMatch( testModule.parentModule );
1004 }
1005  
1006 // Internally-generated tests are always valid
1007 if ( this.callback && this.callback.validTest ) {
1008 return true;
1009 }
1010  
1011 if ( config.moduleId && config.moduleId.length > 0 &&
1012 !moduleChainIdMatch( this.module ) ) {
1013  
1014 return false;
1015 }
1016  
1017 if ( config.testId && config.testId.length > 0 &&
1018 inArray( this.testId, config.testId ) < 0 ) {
1019  
1020 return false;
1021 }
1022  
1023 if ( module && !moduleChainNameMatch( this.module ) ) {
1024 return false;
1025 }
1026  
1027 if ( !filter ) {
1028 return true;
1029 }
1030  
1031 return regexFilter ?
1032 this.regexFilter( !!regexFilter[ 1 ], regexFilter[ 2 ], regexFilter[ 3 ], fullName ) :
1033 this.stringFilter( filter, fullName );
1034 },
1035  
1036 regexFilter: function( exclude, pattern, flags, fullName ) {
1037 var regex = new RegExp( pattern, flags );
1038 var match = regex.test( fullName );
1039  
1040 return match !== exclude;
1041 },
1042  
1043 stringFilter: function( filter, fullName ) {
1044 filter = filter.toLowerCase();
1045 fullName = fullName.toLowerCase();
1046  
1047 var include = filter.charAt( 0 ) !== "!";
1048 if ( !include ) {
1049 filter = filter.slice( 1 );
1050 }
1051  
1052 // If the filter matches, we need to honour include
1053 if ( fullName.indexOf( filter ) !== -1 ) {
1054 return include;
1055 }
1056  
1057 // Otherwise, do the opposite
1058 return !include;
1059 }
1060 };
1061  
1062 QUnit.pushFailure = function() {
1063 if ( !QUnit.config.current ) {
1064 throw new Error( "pushFailure() assertion outside test context, in " +
1065 sourceFromStacktrace( 2 ) );
1066 }
1067  
1068 // Gets current test obj
1069 var currentTest = QUnit.config.current;
1070  
1071 return currentTest.pushFailure.apply( currentTest, arguments );
1072 };
1073  
1074 // Based on Java's String.hashCode, a simple but not
1075 // rigorously collision resistant hashing function
1076 function generateHash( module, testName ) {
1077 var hex,
1078 i = 0,
1079 hash = 0,
1080 str = module + "\x1C" + testName,
1081 len = str.length;
1082  
1083 for ( ; i < len; i++ ) {
1084 hash = ( ( hash << 5 ) - hash ) + str.charCodeAt( i );
1085 hash |= 0;
1086 }
1087  
1088 // Convert the possibly negative integer hash code into an 8 character hex string, which isn't
1089 // strictly necessary but increases user understanding that the id is a SHA-like hash
1090 hex = ( 0x100000000 + hash ).toString( 16 );
1091 if ( hex.length < 8 ) {
1092 hex = "0000000" + hex;
1093 }
1094  
1095 return hex.slice( -8 );
1096 }
1097  
1098 function synchronize( callback, priority, seed ) {
1099 var last = !priority,
1100 index;
1101  
1102 if ( QUnit.objectType( callback ) === "array" ) {
1103 while ( callback.length ) {
1104 synchronize( callback.shift() );
1105 }
1106 return;
1107 }
1108  
1109 if ( priority ) {
1110 config.queue.splice( priorityCount++, 0, callback );
1111 } else if ( seed ) {
1112 if ( !unitSampler ) {
1113 unitSampler = unitSamplerGenerator( seed );
1114 }
1115  
1116 // Insert into a random position after all priority items
1117 index = Math.floor( unitSampler() * ( config.queue.length - priorityCount + 1 ) );
1118 config.queue.splice( priorityCount + index, 0, callback );
1119 } else {
1120 config.queue.push( callback );
1121 }
1122  
1123 if ( autorun && !config.blocking ) {
1124 process( last );
1125 }
1126 }
1127  
1128 function unitSamplerGenerator( seed ) {
1129  
1130 // 32-bit xorshift, requires only a nonzero seed
1131 // http://excamera.com/sphinx/article-xorshift.html
1132 var sample = parseInt( generateHash( seed ), 16 ) || -1;
1133 return function() {
1134 sample ^= sample << 13;
1135 sample ^= sample >>> 17;
1136 sample ^= sample << 5;
1137  
1138 // ECMAScript has no unsigned number type
1139 if ( sample < 0 ) {
1140 sample += 0x100000000;
1141 }
1142  
1143 return sample / 0x100000000;
1144 };
1145 }
1146  
1147 function saveGlobal() {
1148 config.pollution = [];
1149  
1150 if ( config.noglobals ) {
1151 for ( var key in global ) {
1152 if ( hasOwn.call( global, key ) ) {
1153  
1154 // In Opera sometimes DOM element ids show up here, ignore them
1155 if ( /^qunit-test-output/.test( key ) ) {
1156 continue;
1157 }
1158 config.pollution.push( key );
1159 }
1160 }
1161 }
1162 }
1163  
1164 function checkPollution() {
1165 var newGlobals,
1166 deletedGlobals,
1167 old = config.pollution;
1168  
1169 saveGlobal();
1170  
1171 newGlobals = diff( config.pollution, old );
1172 if ( newGlobals.length > 0 ) {
1173 QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join( ", " ) );
1174 }
1175  
1176 deletedGlobals = diff( old, config.pollution );
1177 if ( deletedGlobals.length > 0 ) {
1178 QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join( ", " ) );
1179 }
1180 }
1181  
1182 // Will be exposed as QUnit.test
1183 function test( testName, callback ) {
1184 if ( focused ) { return; }
1185  
1186 var newTest;
1187  
1188 newTest = new Test( {
1189 testName: testName,
1190 callback: callback
1191 } );
1192  
1193 newTest.queue();
1194 }
1195  
1196 // Will be exposed as QUnit.skip
1197 function skip( testName ) {
1198 if ( focused ) { return; }
1199  
1200 var test = new Test( {
1201 testName: testName,
1202 skip: true
1203 } );
1204  
1205 test.queue();
1206 }
1207  
1208 // Will be exposed as QUnit.only
1209 function only( testName, callback ) {
1210 var newTest;
1211  
1212 if ( focused ) { return; }
1213  
1214 QUnit.config.queue.length = 0;
1215 focused = true;
1216  
1217 newTest = new Test( {
1218 testName: testName,
1219 callback: callback
1220 } );
1221  
1222 newTest.queue();
1223 }
1224  
1225 // Put a hold on processing and return a function that will release it.
1226 function internalStop( test ) {
1227 var released = false;
1228  
1229 test.semaphore += 1;
1230 config.blocking = true;
1231  
1232 // Set a recovery timeout, if so configured.
1233 if ( config.testTimeout && defined.setTimeout ) {
1234 clearTimeout( config.timeout );
1235 config.timeout = setTimeout( function() {
1236 QUnit.pushFailure( "Test timed out", sourceFromStacktrace( 2 ) );
1237 internalRecover( test );
1238 }, config.testTimeout );
1239 }
1240  
1241 return function resume() {
1242 if ( released ) {
1243 return;
1244 }
1245  
1246 released = true;
1247 test.semaphore -= 1;
1248 internalStart( test );
1249 };
1250 }
1251  
1252 // Forcefully release all processing holds.
1253 function internalRecover( test ) {
1254 test.semaphore = 0;
1255 internalStart( test );
1256 }
1257  
1258 // Release a processing hold, scheduling a resumption attempt if no holds remain.
1259 function internalStart( test ) {
1260  
1261 // If semaphore is non-numeric, throw error
1262 if ( isNaN( test.semaphore ) ) {
1263 test.semaphore = 0;
1264  
1265 QUnit.pushFailure(
1266 "Invalid value on test.semaphore",
1267 sourceFromStacktrace( 2 )
1268 );
1269 return;
1270 }
1271  
1272 // Don't start until equal number of stop-calls
1273 if ( test.semaphore > 0 ) {
1274 return;
1275 }
1276  
1277 // Throw an Error if start is called more often than stop
1278 if ( test.semaphore < 0 ) {
1279 < 0 ) { test.semaphore = 0;
1280  
1281 < 0 ) { QUnit.pushFailure(
1282 < 0 ) { "Tried to restart test while already started (test's semaphore was 0 already)",
1283 < 0 ) { sourceFromStacktrace( 2 )
1284 < 0 ) { );
1285 < 0 ) { return;
1286 < 0 ) { }
1287  
1288 < 0 ) { // Add a slight delay to allow more assertions etc.
1289 < 0 ) { if ( defined.setTimeout ) {
1290 < 0 ) { if ( config.timeout ) {
1291 < 0 ) { clearTimeout( config.timeout );
1292 < 0 ) { }
1293 < 0 ) { config.timeout = setTimeout( function() {
1294 < 0 ) { if ( test.semaphore > 0 ) {
1295 < 0 ) { return;
1296 < 0 ) { }
1297  
1298 < 0 ) { if ( config.timeout ) {
1299 < 0 ) { clearTimeout( config.timeout );
1300 < 0 ) { }
1301  
1302 < 0 ) { begin();
1303 < 0 ) { }, 13 );
1304 < 0 ) { } else {
1305 < 0 ) { begin();
1306 < 0 ) { }
1307 < 0 ) {}
1308  
1309 < 0 ) {function numberOfTests( module ) {
1310 < 0 ) { var count = module.tests.length;
1311 < 0 ) { while ( module = module.childModule ) {
1312 < 0 ) { count += module.tests.length;
1313 < 0 ) { }
1314 < 0 ) { return count;
1315 < 0 ) {}
1316  
1317 < 0 ) {function notifyTestsRan( module ) {
1318 < 0 ) { module.testsRun++;
1319 < 0 ) { while ( module = module.parentModule ) {
1320 < 0 ) { module.testsRun++;
1321 < 0 ) { }
1322 < 0 ) {}
1323  
1324 < 0 ) {function Assert( testContext ) {
1325 < 0 ) { this.test = testContext;
1326 < 0 ) {}
1327  
1328 < 0 ) {// Assert helpers
1329 < 0 ) {QUnit.assert = Assert.prototype = {
1330  
1331 < 0 ) { // Specify the number of expected assertions to guarantee that failed test
1332 < 0 ) { // (no assertions are run at all) don't slip through.
1333 < 0 ) { expect: function( asserts ) {
1334 < 0 ) { if ( arguments.length === 1 ) {
1335 < 0 ) { this.test.expected = asserts;
1336 < 0 ) { } else {
1337 < 0 ) { return this.test.expected;
1338 < 0 ) { }
1339 < 0 ) { },
1340  
1341 < 0 ) { // Put a hold on processing and return a function that will release it a maximum of once.
1342 < 0 ) { async: function( count ) {
1343 < 0 ) { var resume,
1344 < 0 ) { test = this.test,
1345 < 0 ) { popped = false,
1346 < 0 ) { acceptCallCount = count;
1347  
1348 < 0 ) { if ( typeof acceptCallCount === "undefined" ) {
1349 < 0 ) { acceptCallCount = 1;
1350 < 0 ) { }
1351  
1352 < 0 ) { test.usedAsync = true;
1353 < 0 ) { resume = internalStop( test );
1354  
1355 < 0 ) { return function done() {
1356  
1357 < 0 ) { if ( popped ) {
1358 < 0 ) { test.pushFailure( "Too many calls to the `assert.async` callback",
1359 < 0 ) { sourceFromStacktrace( 2 ) );
1360 < 0 ) { return;
1361 < 0 ) { }
1362 < 0 ) { acceptCallCount -= 1;
1363 < 0 ) { if ( acceptCallCount > 0 ) {
1364 < 0 ) { return;
1365 < 0 ) { }
1366  
1367 < 0 ) { popped = true;
1368 < 0 ) { resume();
1369 < 0 ) { };
1370 < 0 ) { },
1371  
1372 < 0 ) { // Exports test.push() to the user API
1373 < 0 ) { // Alias of pushResult.
1374 < 0 ) { push: function( result, actual, expected, message, negative ) {
1375 < 0 ) { var currentAssert = this instanceof Assert ? this : QUnit.config.current.assert;
1376 < 0 ) { return currentAssert.pushResult( {
1377 < 0 ) { result: result,
1378 < 0 ) { actual: actual,
1379 < 0 ) { expected: expected,
1380 < 0 ) { message: message,
1381 < 0 ) { negative: negative
1382 < 0 ) { } );
1383 < 0 ) { },
1384  
1385 < 0 ) { pushResult: function( resultInfo ) {
1386  
1387 < 0 ) { // Destructure of resultInfo = { result, actual, expected, message, negative }
1388 < 0 ) { var assert = this,
1389 < 0 ) { currentTest = ( assert instanceof Assert && assert.test ) || QUnit.config.current;
1390  
1391 < 0 ) { // Backwards compatibility fix.
1392 < 0 ) { // Allows the direct use of global exported assertions and QUnit.assert.*
1393 < 0 ) { // Although, it's use is not recommended as it can leak assertions
1394 < 0 ) { // to other tests from async tests, because we only get a reference to the current test,
1395 < 0 ) { // not exactly the test where assertion were intended to be called.
1396 < 0 ) { if ( !currentTest ) {
1397 < 0 ) { throw new Error( "assertion outside test context, in " + sourceFromStacktrace( 2 ) );
1398 < 0 ) { }
1399  
1400 < 0 ) { if ( currentTest.usedAsync === true && currentTest.semaphore === 0 ) {
1401 < 0 ) { currentTest.pushFailure( "Assertion after the final `assert.async` was resolved",
1402 < 0 ) { sourceFromStacktrace( 2 ) );
1403  
1404 < 0 ) { // Allow this assertion to continue running anyway...
1405 < 0 ) { }
1406  
1407 < 0 ) { if ( !( assert instanceof Assert ) ) {
1408 < 0 ) { assert = currentTest.assert;
1409 < 0 ) { }
1410  
1411 < 0 ) { return assert.test.pushResult( resultInfo );
1412 < 0 ) { },
1413  
1414 < 0 ) { ok: function( result, message ) {
1415 < 0 ) { message = message || ( result ? "okay" : "failed, expected argument to be truthy, was: " +
1416 < 0 ) { QUnit.dump.parse( result ) );
1417 < 0 ) { this.pushResult( {
1418 < 0 ) { result: !!result,
1419 < 0 ) { actual: result,
1420 < 0 ) { expected: true,
1421 < 0 ) { message: message
1422 < 0 ) { } );
1423 < 0 ) { },
1424  
1425 < 0 ) { notOk: function( result, message ) {
1426 < 0 ) { message = message || ( !result ? "okay" : "failed, expected argument to be falsy, was: " +
1427 < 0 ) { QUnit.dump.parse( result ) );
1428 < 0 ) { this.pushResult( {
1429 < 0 ) { result: !result,
1430 < 0 ) { actual: result,
1431 < 0 ) { expected: false,
1432 < 0 ) { message: message
1433 < 0 ) { } );
1434 < 0 ) { },
1435  
1436 < 0 ) { equal: function( actual, expected, message ) {
1437 < 0 ) { /*jshint eqeqeq:false */
1438 < 0 ) { this.pushResult( {
1439 < 0 ) { result: expected == actual,
1440 < 0 ) { actual: actual,
1441 < 0 ) { expected: expected,
1442 < 0 ) { message: message
1443 < 0 ) { } );
1444 < 0 ) { },
1445  
1446 < 0 ) { notEqual: function( actual, expected, message ) {
1447 < 0 ) { /*jshint eqeqeq:false */
1448 < 0 ) { this.pushResult( {
1449 < 0 ) { result: expected != actual,
1450 < 0 ) { actual: actual,
1451 < 0 ) { expected: expected,
1452 < 0 ) { message: message,
1453 < 0 ) { negative: true
1454 < 0 ) { } );
1455 < 0 ) { },
1456  
1457 < 0 ) { propEqual: function( actual, expected, message ) {
1458 < 0 ) { actual = objectValues( actual );
1459 < 0 ) { expected = objectValues( expected );
1460 < 0 ) { this.pushResult( {
1461 < 0 ) { result: QUnit.equiv( actual, expected ),
1462 < 0 ) { actual: actual,
1463 < 0 ) { expected: expected,
1464 < 0 ) { message: message
1465 < 0 ) { } );
1466 < 0 ) { },
1467  
1468 < 0 ) { notPropEqual: function( actual, expected, message ) {
1469 < 0 ) { actual = objectValues( actual );
1470 < 0 ) { expected = objectValues( expected );
1471 < 0 ) { this.pushResult( {
1472 < 0 ) { result: !QUnit.equiv( actual, expected ),
1473 < 0 ) { actual: actual,
1474 < 0 ) { expected: expected,
1475 < 0 ) { message: message,
1476 < 0 ) { negative: true
1477 < 0 ) { } );
1478 < 0 ) { },
1479  
1480 < 0 ) { deepEqual: function( actual, expected, message ) {
1481 < 0 ) { this.pushResult( {
1482 < 0 ) { result: QUnit.equiv( actual, expected ),
1483 < 0 ) { actual: actual,
1484 < 0 ) { expected: expected,
1485 < 0 ) { message: message
1486 < 0 ) { } );
1487 < 0 ) { },
1488  
1489 < 0 ) { notDeepEqual: function( actual, expected, message ) {
1490 < 0 ) { this.pushResult( {
1491 < 0 ) { result: !QUnit.equiv( actual, expected ),
1492 < 0 ) { actual: actual,
1493 < 0 ) { expected: expected,
1494 < 0 ) { message: message,
1495 < 0 ) { negative: true
1496 < 0 ) { } );
1497 < 0 ) { },
1498  
1499 < 0 ) { strictEqual: function( actual, expected, message ) {
1500 < 0 ) { this.pushResult( {
1501 < 0 ) { result: expected === actual,
1502 < 0 ) { actual: actual,
1503 < 0 ) { expected: expected,
1504 < 0 ) { message: message
1505 < 0 ) { } );
1506 < 0 ) { },
1507  
1508 < 0 ) { notStrictEqual: function( actual, expected, message ) {
1509 < 0 ) { this.pushResult( {
1510 < 0 ) { result: expected !== actual,
1511 < 0 ) { actual: actual,
1512 < 0 ) { expected: expected,
1513 < 0 ) { message: message,
1514 < 0 ) { negative: true
1515 < 0 ) { } );
1516 < 0 ) { },
1517  
1518 < 0 ) { "throws": function( block, expected, message ) {
1519 < 0 ) { var actual, expectedType,
1520 < 0 ) { expectedOutput = expected,
1521 < 0 ) { ok = false,
1522 < 0 ) { currentTest = ( this instanceof Assert && this.test ) || QUnit.config.current;
1523  
1524 < 0 ) { // 'expected' is optional unless doing string comparison
1525 < 0 ) { if ( QUnit.objectType( expected ) === "string" ) {
1526 < 0 ) { if ( message == null ) {
1527 < 0 ) { message = expected;
1528 < 0 ) { expected = null;
1529 < 0 ) { } else {
1530 < 0 ) { throw new Error(
1531 < 0 ) { "throws/raises does not accept a string value for the expected argument.\n" +
1532 < 0 ) { "Use a non-string object value (e.g. regExp) instead if it's necessary." +
1533 < 0 ) { "Details in our upgrade guide at https://qunitjs.com/upgrade-guide-2.x/"
1534 < 0 ) { );
1535 < 0 ) { }
1536 < 0 ) { }
1537  
1538 < 0 ) { currentTest.ignoreGlobalErrors = true;
1539 < 0 ) { try {
1540 < 0 ) { block.call( currentTest.testEnvironment );
1541 < 0 ) { } catch ( e ) {
1542 < 0 ) { actual = e;
1543 < 0 ) { }
1544 < 0 ) { currentTest.ignoreGlobalErrors = false;
1545  
1546 < 0 ) { if ( actual ) {
1547 < 0 ) { expectedType = QUnit.objectType( expected );
1548  
1549 < 0 ) { // We don't want to validate thrown error
1550 < 0 ) { if ( !expected ) {
1551 < 0 ) { ok = true;
1552 < 0 ) { expectedOutput = null;
1553  
1554 < 0 ) { // Expected is a regexp
1555 < 0 ) { } else if ( expectedType === "regexp" ) {
1556 < 0 ) { ok = expected.test( errorString( actual ) );
1557  
1558 < 0 ) { // Expected is a constructor, maybe an Error constructor
1559 < 0 ) { } else if ( expectedType === "function" && actual instanceof expected ) {
1560 < 0 ) { ok = true;
1561  
1562 < 0 ) { // Expected is an Error object
1563 < 0 ) { } else if ( expectedType === "object" ) {
1564 < 0 ) { ok = actual instanceof expected.constructor &&
1565 < 0 ) { actual.name === expected.name &&
1566 < 0 ) { actual.message === expected.message;
1567  
1568 < 0 ) { // Expected is a validation function which returns true if validation passed
1569 < 0 ) { } else if ( expectedType === "function" && expected.call( {}, actual ) === true ) {
1570 < 0 ) { expectedOutput = null;
1571 < 0 ) { ok = true;
1572 < 0 ) { }
1573 < 0 ) { }
1574  
1575 < 0 ) { currentTest.assert.pushResult( {
1576 < 0 ) { result: ok,
1577 < 0 ) { actual: actual,
1578 < 0 ) { expected: expectedOutput,
1579 < 0 ) { message: message
1580 < 0 ) { } );
1581 < 0 ) { }
1582 < 0 ) {};
1583  
1584 < 0 ) {// Provide an alternative to assert.throws(), for environments that consider throws a reserved word
1585 < 0 ) {// Known to us are: Closure Compiler, Narwhal
1586 < 0 ) {( function() {
1587 < 0 ) { /*jshint sub:true */
1588 < 0 ) { Assert.prototype.raises = Assert.prototype [ "throws" ]; //jscs:ignore requireDotNotation
1589 < 0 ) {}() );
1590  
1591 < 0 ) {function errorString( error ) {
1592 < 0 ) { var name, message,
1593 < 0 ) { resultErrorString = error.toString();
1594 < 0 ) { if ( resultErrorString.substring( 0, 7 ) === "[object" ) {
1595 < 0 ) { name = error.name ? error.name.toString() : "Error";
1596 < 0 ) { message = error.message ? error.message.toString() : "";
1597 < 0 ) { if ( name && message ) {
1598 < 0 ) { return name + ": " + message;
1599 < 0 ) { } else if ( name ) {
1600 < 0 ) { return name;
1601 < 0 ) { } else if ( message ) {
1602 < 0 ) { return message;
1603 < 0 ) { } else {
1604 < 0 ) { return "Error";
1605 < 0 ) { }
1606 < 0 ) { } else {
1607 < 0 ) { return resultErrorString;
1608 < 0 ) { }
1609 < 0 ) {}
1610  
1611 < 0 ) {// Test for equality any JavaScript type.
1612 < 0 ) {// Author: Philippe Rathé <prathe@gmail.com>
1613 < 0 ) {QUnit.equiv = ( function() {
1614  
1615 < 0 ) { // Stack to decide between skip/abort functions
1616 < 0 ) { var callers = [];
1617  
1618 < 0 ) { // Stack to avoiding loops from circular referencing
1619 < 0 ) { var parents = [];
1620 < 0 ) { var parentsB = [];
1621  
1622 < 0 ) { var getProto = Object.getPrototypeOf || function( obj ) {
1623  
1624 < 0 ) { /*jshint proto: true */
1625 < 0 ) { return obj.__proto__;
1626 < 0 ) { };
1627  
1628 < 0 ) { function useStrictEquality( b, a ) {
1629  
1630 < 0 ) { // To catch short annotation VS 'new' annotation of a declaration. e.g.:
1631 < 0 ) { // `var i = 1;`
1632 < 0 ) { // `var j = new Number(1);`
1633 < 0 ) { if ( typeof a === "object" ) {
1634 < 0 ) { a = a.valueOf();
1635 < 0 ) { }
1636 < 0 ) { if ( typeof b === "object" ) {
1637 < 0 ) { b = b.valueOf();
1638 < 0 ) { }
1639  
1640 < 0 ) { return a === b;
1641 < 0 ) { }
1642  
1643 < 0 ) { function compareConstructors( a, b ) {
1644 < 0 ) { var protoA = getProto( a );
1645 < 0 ) { var protoB = getProto( b );
1646  
1647 < 0 ) { // Comparing constructors is more strict than using `instanceof`
1648 < 0 ) { if ( a.constructor === b.constructor ) {
1649 < 0 ) { return true;
1650 < 0 ) { }
1651  
1652 < 0 ) { // Ref #851
1653 < 0 ) { // If the obj prototype descends from a null constructor, treat it
1654 < 0 ) { // as a null prototype.
1655 < 0 ) { if ( protoA && protoA.constructor === null ) {
1656 < 0 ) { protoA = null;
1657 < 0 ) { }
1658 < 0 ) { if ( protoB && protoB.constructor === null ) {
1659 < 0 ) { protoB = null;
1660 < 0 ) { }
1661  
1662 < 0 ) { // Allow objects with no prototype to be equivalent to
1663 < 0 ) { // objects with Object as their constructor.
1664 < 0 ) { if ( ( protoA === null && protoB === Object.prototype ) ||
1665 < 0 ) { ( protoB === null && protoA === Object.prototype ) ) {
1666 < 0 ) { return true;
1667 < 0 ) { }
1668  
1669 < 0 ) { return false;
1670 < 0 ) { }
1671  
1672 < 0 ) { function getRegExpFlags( regexp ) {
1673 < 0 ) { return "flags" in regexp ? regexp.flags : regexp.toString().match( /[gimuy]*$/ )[ 0 ];
1674 < 0 ) { }
1675  
1676 < 0 ) { var callbacks = {
1677 < 0 ) { "string": useStrictEquality,
1678 < 0 ) { "boolean": useStrictEquality,
1679 < 0 ) { "number": useStrictEquality,
1680 < 0 ) { "null": useStrictEquality,
1681 < 0 ) { "undefined": useStrictEquality,
1682 < 0 ) { "symbol": useStrictEquality,
1683 < 0 ) { "date": useStrictEquality,
1684  
1685 < 0 ) { "nan": function() {
1686 < 0 ) { return true;
1687 < 0 ) { },
1688  
1689 < 0 ) { "regexp": function( b, a ) {
1690 < 0 ) { return a.source === b.source &&
1691  
1692 < 0 ) { // Include flags in the comparison
1693 < 0 ) { getRegExpFlags( a ) === getRegExpFlags( b );
1694 < 0 ) { },
1695  
1696 < 0 ) { // - skip when the property is a method of an instance (OOP)
1697 < 0 ) { // - abort otherwise,
1698 < 0 ) { // initial === would have catch identical references anyway
1699 < 0 ) { "function": function() {
1700 < 0 ) { var caller = callers[ callers.length - 1 ];
1701 < 0 ) { return caller !== Object && typeof caller !== "undefined";
1702 < 0 ) { },
1703  
1704 < 0 ) { "array": function( b, a ) {
1705 < 0 ) { var i, j, len, loop, aCircular, bCircular;
1706  
1707 < 0 ) { len = a.length;
1708 < 0 ) { if ( len !== b.length ) {
1709  
1710 < 0 ) { // Safe and faster
1711 < 0 ) { return false;
1712 < 0 ) { }
1713  
1714 < 0 ) { // Track reference to avoid circular references
1715 < 0 ) { parents.push( a );
1716 < 0 ) { parentsB.push( b );
1717 < 0 ) { for ( i = 0; i < len; i++ ) {
1718 < 0 ) { loop = false;
1719 < 0 ) { for ( j = 0; j < parents.length; j++ ) {
1720 < 0 ) { aCircular = parents[ j ] === a[ i ];
1721 < 0 ) { bCircular = parentsB[ j ] === b[ i ];
1722 < 0 ) { if ( aCircular || bCircular ) {
1723 < 0 ) { if ( a[ i ] === b[ i ] || aCircular && bCircular ) {
1724 < 0 ) { loop = true;
1725 < 0 ) { } else {
1726 < 0 ) { parents.pop();
1727 < 0 ) { parentsB.pop();
1728 < 0 ) { return false;
1729 < 0 ) { }
1730 < 0 ) { }
1731 < 0 ) { }
1732 < 0 ) { if ( !loop && !innerEquiv( a[ i ], b[ i ] ) ) {
1733 < 0 ) { parents.pop();
1734 < 0 ) { parentsB.pop();
1735 < 0 ) { return false;
1736 < 0 ) { }
1737 < 0 ) { }
1738 < 0 ) { parents.pop();
1739 < 0 ) { parentsB.pop();
1740 < 0 ) { return true;
1741 < 0 ) { },
1742  
1743 < 0 ) { "set": function( b, a ) {
1744 < 0 ) { var innerEq,
1745 < 0 ) { outerEq = true;
1746  
1747 < 0 ) { if ( a.size !== b.size ) {
1748 < 0 ) { return false;
1749 < 0 ) { }
1750  
1751 < 0 ) { a.forEach( function( aVal ) {
1752 < 0 ) { innerEq = false;
1753  
1754 < 0 ) { b.forEach( function( bVal ) {
1755 < 0 ) { if ( innerEquiv( bVal, aVal ) ) {
1756 < 0 ) { innerEq = true;
1757 < 0 ) { }
1758 < 0 ) { } );
1759  
1760 < 0 ) { if ( !innerEq ) {
1761 < 0 ) { outerEq = false;
1762 < 0 ) { }
1763 < 0 ) { } );
1764  
1765 < 0 ) { return outerEq;
1766 < 0 ) { },
1767  
1768 < 0 ) { "map": function( b, a ) {
1769 < 0 ) { var innerEq,
1770 < 0 ) { outerEq = true;
1771  
1772 < 0 ) { if ( a.size !== b.size ) {
1773 < 0 ) { return false;
1774 < 0 ) { }
1775  
1776 < 0 ) { a.forEach( function( aVal, aKey ) {
1777 < 0 ) { innerEq = false;
1778  
1779 < 0 ) { b.forEach( function( bVal, bKey ) {
1780 < 0 ) { if ( innerEquiv( [ bVal, bKey ], [ aVal, aKey ] ) ) {
1781 < 0 ) { innerEq = true;
1782 < 0 ) { }
1783 < 0 ) { } );
1784  
1785 < 0 ) { if ( !innerEq ) {
1786 < 0 ) { outerEq = false;
1787 < 0 ) { }
1788 < 0 ) { } );
1789  
1790 < 0 ) { return outerEq;
1791 < 0 ) { },
1792  
1793 < 0 ) { "object": function( b, a ) {
1794 < 0 ) { var i, j, loop, aCircular, bCircular;
1795  
1796 < 0 ) { // Default to true
1797 < 0 ) { var eq = true;
1798 < 0 ) { var aProperties = [];
1799 < 0 ) { var bProperties = [];
1800  
1801 < 0 ) { if ( compareConstructors( a, b ) === false ) {
1802 < 0 ) { return false;
1803 < 0 ) { }
1804  
1805 < 0 ) { // Stack constructor before traversing properties
1806 < 0 ) { callers.push( a.constructor );
1807  
1808 < 0 ) { // Track reference to avoid circular references
1809 < 0 ) { parents.push( a );
1810 < 0 ) { parentsB.push( b );
1811  
1812 < 0 ) { // Be strict: don't ensure hasOwnProperty and go deep
1813 < 0 ) { for ( i in a ) {
1814 < 0 ) { loop = false;
1815 < 0 ) { for ( j = 0; j < parents.length; j++ ) {
1816 < 0 ) { aCircular = parents[ j ] === a[ i ];
1817 < 0 ) { bCircular = parentsB[ j ] === b[ i ];
1818 < 0 ) { if ( aCircular || bCircular ) {
1819 < 0 ) { if ( a[ i ] === b[ i ] || aCircular && bCircular ) {
1820 < 0 ) { loop = true;
1821 < 0 ) { } else {
1822 < 0 ) { eq = false;
1823 < 0 ) { break;
1824 < 0 ) { }
1825 < 0 ) { }
1826 < 0 ) { }
1827 < 0 ) { aProperties.push( i );
1828 < 0 ) { if ( !loop && !innerEquiv( a[ i ], b[ i ] ) ) {
1829 < 0 ) { eq = false;
1830 < 0 ) { break;
1831 < 0 ) { }
1832 < 0 ) { }
1833  
1834 < 0 ) { parents.pop();
1835 < 0 ) { parentsB.pop();
1836  
1837 < 0 ) { // Unstack, we are done
1838 < 0 ) { callers.pop();
1839  
1840 < 0 ) { for ( i in b ) {
1841  
1842 < 0 ) { // Collect b's properties
1843 < 0 ) { bProperties.push( i );
1844 < 0 ) { }
1845  
1846 < 0 ) { // Ensures identical properties name
1847 < 0 ) { return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
1848 < 0 ) { }
1849 < 0 ) { };
1850  
1851 < 0 ) { function typeEquiv( a, b ) {
1852 < 0 ) { var type = QUnit.objectType( a );
1853 < 0 ) { return QUnit.objectType( b ) === type && callbacks[ type ]( b, a );
1854 < 0 ) { }
1855  
1856 < 0 ) { // The real equiv function
1857 < 0 ) { function innerEquiv( a, b ) {
1858  
1859 < 0 ) { // We're done when there's nothing more to compare
1860 < 0 ) { if ( arguments.length < 2 ) {
1861 < 0 ) { return true;
1862 < 0 ) { }
1863  
1864 < 0 ) { // Require type-specific equality
1865 < 0 ) { return ( a === b || typeEquiv( a, b ) ) &&
1866  
1867 < 0 ) { // ...across all consecutive argument pairs
1868 < 0 ) { ( arguments.length === 2 || innerEquiv.apply( this, [].slice.call( arguments, 1 ) ) );
1869 < 0 ) { }
1870  
1871 < 0 ) { return innerEquiv;
1872 < 0 ) {}() );
1873  
1874 < 0 ) {// Based on jsDump by Ariel Flesler
1875 < 0 ) {// http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html
1876 < 0 ) {QUnit.dump = ( function() {
1877 < 0 ) { function quote( str ) {
1878 < 0 ) { return "\"" + str.toString().replace( /\\/g, "\\\\" ).replace( /"/g, "\\\"" ) + "\"";
1879 < 0 ) { }
1880 < 0 ) { function literal( o ) {
1881 < 0 ) { return o + "";
1882 < 0 ) { }
1883 < 0 ) { function join( pre, arr, post ) {
1884 < 0 ) { var s = dump.separator(),
1885 < 0 ) { base = dump.indent(),
1886 < 0 ) { inner = dump.indent( 1 );
1887 < 0 ) { if ( arr.join ) {
1888 < 0 ) { arr = arr.join( "," + s + inner );
1889 < 0 ) { }
1890 < 0 ) { if ( !arr ) {
1891 < 0 ) { return pre + post;
1892 < 0 ) { }
1893 < 0 ) { return [ pre, inner + arr, base + post ].join( s );
1894 < 0 ) { }
1895 < 0 ) { function array( arr, stack ) {
1896 < 0 ) { var i = arr.length,
1897 < 0 ) { ret = new Array( i );
1898  
1899 < 0 ) { if ( dump.maxDepth && dump.depth > dump.maxDepth ) {
1900 < 0 ) { return "[object Array]";
1901 < 0 ) { }
1902  
1903 < 0 ) { this.up();
1904 < 0 ) { while ( i-- ) {
1905 < 0 ) { ret[ i ] = this.parse( arr[ i ], undefined, stack );
1906 < 0 ) { }
1907 < 0 ) { this.down();
1908 < 0 ) { return join( "[", ret, "]" );
1909 < 0 ) { }
1910  
1911 < 0 ) { function isArray( obj ) {
1912 < 0 ) { return (
1913  
1914 < 0 ) { //Native Arrays
1915 < 0 ) { toString.call( obj ) === "[object Array]" ||
1916  
1917 < 0 ) { // NodeList objects
1918 < 0 ) { ( typeof obj.length === "number" && obj.item !== undefined ) &&
1919 < 0 ) { ( obj.length ?
1920 < 0 ) { obj.item( 0 ) === obj[ 0 ] :
1921 < 0 ) { ( obj.item( 0 ) === null && obj[ 0 ] === undefined )
1922 < 0 ) { )
1923 < 0 ) { );
1924 < 0 ) { }
1925  
1926 < 0 ) { var reName = /^function (\w+)/,
1927 < 0 ) { dump = {
1928  
1929 < 0 ) { // The objType is used mostly internally, you can fix a (custom) type in advance
1930 < 0 ) { parse: function( obj, objType, stack ) {
1931 < 0 ) { stack = stack || [];
1932 < 0 ) { var res, parser, parserType,
1933 < 0 ) { inStack = inArray( obj, stack );
1934  
1935 < 0 ) { if ( inStack !== -1 ) {
1936 < 0 ) { return "recursion(" + ( inStack - stack.length ) + ")";
1937 < 0 ) { }
1938  
1939 < 0 ) { objType = objType || this.typeOf( obj );
1940 < 0 ) { parser = this.parsers[ objType ];
1941 < 0 ) { parserType = typeof parser;
1942  
1943 < 0 ) { if ( parserType === "function" ) {
1944 < 0 ) { stack.push( obj );
1945 < 0 ) { res = parser.call( this, obj, stack );
1946 < 0 ) { stack.pop();
1947 < 0 ) { return res;
1948 < 0 ) { }
1949 < 0 ) { return ( parserType === "string" ) ? parser : this.parsers.error;
1950 < 0 ) { },
1951 < 0 ) { typeOf: function( obj ) {
1952 < 0 ) { var type;
1953  
1954 < 0 ) { if ( obj === null ) {
1955 < 0 ) { type = "null";
1956 < 0 ) { } else if ( typeof obj === "undefined" ) {
1957 < 0 ) { type = "undefined";
1958 < 0 ) { } else if ( QUnit.is( "regexp", obj ) ) {
1959 < 0 ) { type = "regexp";
1960 < 0 ) { } else if ( QUnit.is( "date", obj ) ) {
1961 < 0 ) { type = "date";
1962 < 0 ) { } else if ( QUnit.is( "function", obj ) ) {
1963 < 0 ) { type = "function";
1964 < 0 ) { } else if ( obj.setInterval !== undefined &&
1965 < 0 ) { obj.document !== undefined &&
1966 < 0 ) { obj.nodeType === undefined ) {
1967 < 0 ) { type = "window";
1968 < 0 ) { } else if ( obj.nodeType === 9 ) {
1969 < 0 ) { type = "document";
1970 < 0 ) { } else if ( obj.nodeType ) {
1971 < 0 ) { type = "node";
1972 < 0 ) { } else if ( isArray( obj ) ) {
1973 < 0 ) { type = "array";
1974 < 0 ) { } else if ( obj.constructor === Error.prototype.constructor ) {
1975 < 0 ) { type = "error";
1976 < 0 ) { } else {
1977 < 0 ) { type = typeof obj;
1978 < 0 ) { }
1979 < 0 ) { return type;
1980 < 0 ) { },
1981  
1982 < 0 ) { separator: function() {
1983 < 0 ) { return this.multiline ? this.HTML ? "<br />" : "\n" : this.HTML ? "&#160;" : " ";
1984 < 0 ) { },
1985  
1986 < 0 ) { // Extra can be a number, shortcut for increasing-calling-decreasing
1987 < 0 ) { indent: function( extra ) {
1988 < 0 ) { if ( !this.multiline ) {
1989 < 0 ) { return "";
1990 < 0 ) { }
1991 < 0 ) { var chr = this.indentChar;
1992 < 0 ) { if ( this.HTML ) {
1993 < 0 ) { chr = chr.replace( /\t/g, " " ).replace( / /g, "&#160;" );
1994 < 0 ) { }
1995 < 0 ) { return new Array( this.depth + ( extra || 0 ) ).join( chr );
1996 < 0 ) { },
1997 < 0 ) { up: function( a ) {
1998 < 0 ) { this.depth += a || 1;
1999 < 0 ) { },
2000 < 0 ) { down: function( a ) {
2001 < 0 ) { this.depth -= a || 1;
2002 < 0 ) { },
2003 < 0 ) { setParser: function( name, parser ) {
2004 < 0 ) { this.parsers[ name ] = parser;
2005 < 0 ) { },
2006  
2007 < 0 ) { // The next 3 are exposed so you can use them
2008 < 0 ) { quote: quote,
2009 < 0 ) { literal: literal,
2010 < 0 ) { join: join,
2011 < 0 ) { depth: 1,
2012 < 0 ) { maxDepth: QUnit.config.maxDepth,
2013  
2014 < 0 ) { // This is the list of parsers, to modify them, use dump.setParser
2015 < 0 ) { parsers: {
2016 < 0 ) { window: "[Window]",
2017 < 0 ) { document: "[Document]",
2018 < 0 ) { error: function( error ) {
2019 < 0 ) { return "Error(\"" + error.message + "\")";
2020 < 0 ) { },
2021 < 0 ) { unknown: "[Unknown]",
2022 < 0 ) { "null": "null",
2023 < 0 ) { "undefined": "undefined",
2024 < 0 ) { "function": function( fn ) {
2025 < 0 ) { var ret = "function",
2026  
2027 < 0 ) { // Functions never have name in IE
2028 < 0 ) { name = "name" in fn ? fn.name : ( reName.exec( fn ) || [] )[ 1 ];
2029  
2030 < 0 ) { if ( name ) {
2031 < 0 ) { ret += " " + name;
2032 < 0 ) { }
2033 < 0 ) { ret += "(";
2034  
2035 < 0 ) { ret = [ ret, dump.parse( fn, "functionArgs" ), "){" ].join( "" );
2036 < 0 ) { return join( ret, dump.parse( fn, "functionCode" ), "}" );
2037 < 0 ) { },
2038 < 0 ) { array: array,
2039 < 0 ) { nodelist: array,
2040 < 0 ) { "arguments": array,
2041 < 0 ) { object: function( map, stack ) {
2042 < 0 ) { var keys, key, val, i, nonEnumerableProperties,
2043 < 0 ) { ret = [];
2044  
2045 < 0 ) { if ( dump.maxDepth && dump.depth > dump.maxDepth ) {
2046 < 0 ) { return "[object Object]";
2047 < 0 ) { }
2048  
2049 < 0 ) { dump.up();
2050 < 0 ) { keys = [];
2051 < 0 ) { for ( key in map ) {
2052 < 0 ) { keys.push( key );
2053 < 0 ) { }
2054  
2055 < 0 ) { // Some properties are not always enumerable on Error objects.
2056 < 0 ) { nonEnumerableProperties = [ "message", "name" ];
2057 < 0 ) { for ( i in nonEnumerableProperties ) {
2058 < 0 ) { key = nonEnumerableProperties[ i ];
2059 < 0 ) { if ( key in map && inArray( key, keys ) < 0 ) {
2060 < 0 ) { keys.push( key );
2061 < 0 ) { }
2062 < 0 ) { }
2063 < 0 ) { keys.sort();
2064 < 0 ) { for ( i = 0; i < keys.length; i++ ) {
2065 < 0 ) { key = keys[ i ];
2066 < 0 ) { val = map[ key ];
2067 < 0 ) { ret.push( dump.parse( key, "key" ) + ": " +
2068 < 0 ) { dump.parse( val, undefined, stack ) );
2069 < 0 ) { }
2070 < 0 ) { dump.down();
2071 < 0 ) { return join( "{", ret, "}" );
2072 < 0 ) { },
2073 < 0 ) { node: function( node ) {
2074 < 0 ) { var len, i, val,
2075 < 0 ) { open = dump.HTML ? "&lt;" : "<",
2076 < 0 ) { close = dump.HTML ? "&gt;" : ">",
2077 < 0 ) { tag = node.nodeName.toLowerCase(),
2078 < 0 ) { ret = open + tag,
2079 < 0 ) { attrs = node.attributes;
2080  
2081 < 0 ) { if ( attrs ) {
2082 < 0 ) { for ( i = 0, len = attrs.length; i < len; i++ ) {
2083 < 0 ) { val = attrs[ i ].nodeValue;
2084  
2085 < 0 ) { // IE6 includes all attributes in .attributes, even ones not explicitly
2086 < 0 ) { // set. Those have values like undefined, null, 0, false, "" or
2087 < 0 ) { // "inherit".
2088 < 0 ) { if ( val && val !== "inherit" ) {
2089 < 0 ) { ret += " " + attrs[ i ].nodeName + "=" +
2090 < 0 ) { dump.parse( val, "attribute" );
2091 < 0 ) { }
2092 < 0 ) { }
2093 < 0 ) { }
2094 < 0 ) { ret += close;
2095  
2096 < 0 ) { // Show content of TextNode or CDATASection
2097 < 0 ) { if ( node.nodeType === 3 || node.nodeType === 4 ) {
2098 < 0 ) { ret += node.nodeValue;
2099 < 0 ) { }
2100  
2101 < 0 ) { return ret + open + "/" + tag + close;
2102 < 0 ) { },
2103  
2104 < 0 ) { // Function calls it internally, it's the arguments part of the function
2105 < 0 ) { functionArgs: function( fn ) {
2106 < 0 ) { var args,
2107 < 0 ) { l = fn.length;
2108  
2109 < 0 ) { if ( !l ) {
2110 < 0 ) { return "";
2111 < 0 ) { }
2112  
2113 < 0 ) { args = new Array( l );
2114 < 0 ) { while ( l-- ) {
2115  
2116 < 0 ) { // 97 is 'a'
2117 < 0 ) { args[ l ] = String.fromCharCode( 97 + l );
2118 < 0 ) { }
2119 < 0 ) { return " " + args.join( ", " ) + " ";
2120 < 0 ) { },
2121  
2122 < 0 ) { // Object calls it internally, the key part of an item in a map
2123 < 0 ) { key: quote,
2124  
2125 < 0 ) { // Function calls it internally, it's the content of the function
2126 < 0 ) { functionCode: "[code]",
2127  
2128 < 0 ) { // Node calls it internally, it's a html attribute value
2129 < 0 ) { attribute: quote,
2130 < 0 ) { string: quote,
2131 < 0 ) { date: quote,
2132 < 0 ) { regexp: literal,
2133 < 0 ) { number: literal,
2134 < 0 ) { "boolean": literal,
2135 < 0 ) { symbol: function( sym ) {
2136 < 0 ) { return sym.toString();
2137 < 0 ) { }
2138 < 0 ) { },
2139  
2140 < 0 ) { // If true, entities are escaped ( <, >, \t, space and \n )
2141 < 0 ) { HTML: false,
2142  
2143 < 0 ) { // Indentation unit
2144 < 0 ) { indentChar: " ",
2145  
2146 < 0 ) { // If true, items in a collection, are separated by a \n, else just a space.
2147 < 0 ) { multiline: true
2148 < 0 ) { };
2149  
2150 < 0 ) { return dump;
2151 < 0 ) {}() );
2152  
2153 < 0 ) {// Back compat
2154 < 0 ) {QUnit.jsDump = QUnit.dump;
2155  
2156 < 0 ) {function applyDeprecated( name ) {
2157 < 0 ) { return function() {
2158 < 0 ) { throw new Error(
2159 < 0 ) { name + " is removed in QUnit 2.0.\n" +
2160 < 0 ) { "Details in our upgrade guide at https://qunitjs.com/upgrade-guide-2.x/"
2161 < 0 ) { );
2162 < 0 ) { };
2163 < 0 ) {}
2164  
2165 < 0 ) {Object.keys( Assert.prototype ).forEach( function( key ) {
2166 < 0 ) { QUnit[ key ] = applyDeprecated( "`QUnit." + key + "`" );
2167 < 0 ) {} );
2168  
2169 < 0 ) {QUnit.asyncTest = function() {
2170 < 0 ) { throw new Error(
2171 < 0 ) { "asyncTest is removed in QUnit 2.0, use QUnit.test() with assert.async() instead.\n" +
2172 < 0 ) { "Details in our upgrade guide at https://qunitjs.com/upgrade-guide-2.x/"
2173 < 0 ) { );
2174 < 0 ) {};
2175  
2176 < 0 ) {QUnit.stop = function() {
2177 < 0 ) { throw new Error(
2178 < 0 ) { "QUnit.stop is removed in QUnit 2.0, use QUnit.test() with assert.async() instead.\n" +
2179 < 0 ) { "Details in our upgrade guide at https://qunitjs.com/upgrade-guide-2.x/"
2180 < 0 ) { );
2181 < 0 ) {};
2182  
2183 < 0 ) {function resetThrower() {
2184 < 0 ) { throw new Error(
2185 < 0 ) { "QUnit.reset is removed in QUnit 2.0 without replacement.\n" +
2186 < 0 ) { "Details in our upgrade guide at https://qunitjs.com/upgrade-guide-2.x/"
2187 < 0 ) { );
2188 < 0 ) {}
2189  
2190 < 0 ) {Object.defineProperty( QUnit, "reset", {
2191 < 0 ) { get: function() {
2192 < 0 ) { return resetThrower;
2193 < 0 ) { },
2194 < 0 ) { set: resetThrower
2195 < 0 ) {} );
2196  
2197 < 0 ) {if ( defined.document ) {
2198 < 0 ) { if ( window.QUnit ) {
2199 < 0 ) { throw new Error( "QUnit has already been defined." );
2200 < 0 ) { }
2201  
2202 < 0 ) { [
2203 < 0 ) { "test",
2204 < 0 ) { "module",
2205 < 0 ) { "expect",
2206 < 0 ) { "start",
2207 < 0 ) { "ok",
2208 < 0 ) { "notOk",
2209 < 0 ) { "equal",
2210 < 0 ) { "notEqual",
2211 < 0 ) { "propEqual",
2212 < 0 ) { "notPropEqual",
2213 < 0 ) { "deepEqual",
2214 < 0 ) { "notDeepEqual",
2215 < 0 ) { "strictEqual",
2216 < 0 ) { "notStrictEqual",
2217 < 0 ) { "throws",
2218 < 0 ) { "raises"
2219 < 0 ) { ].forEach( function( key ) {
2220 < 0 ) { window[ key ] = applyDeprecated( "The global `" + key + "`" );
2221 < 0 ) { } );
2222  
2223 < 0 ) { window.QUnit = QUnit;
2224 < 0 ) {}
2225  
2226 < 0 ) {// For nodejs
2227 < 0 ) {if ( typeof module !== "undefined" && module && module.exports ) {
2228 < 0 ) { module.exports = QUnit;
2229  
2230 < 0 ) { // For consistency with CommonJS environments' exports
2231 < 0 ) { module.exports.QUnit = QUnit;
2232 < 0 ) {}
2233  
2234 < 0 ) {// For CommonJS with exports, but without module.exports, like Rhino
2235 < 0 ) {if ( typeof exports !== "undefined" && exports ) {
2236 < 0 ) { exports.QUnit = QUnit;
2237 < 0 ) {}
2238  
2239 < 0 ) {if ( typeof define === "function" && define.amd ) {
2240 < 0 ) { define( function() {
2241 < 0 ) { return QUnit;
2242 < 0 ) { } );
2243 < 0 ) { QUnit.config.autostart = false;
2244 < 0 ) {}
2245  
2246 < 0 ) {// Get a reference to the global object, like window in browsers
2247 < 0 ) {}( ( function() {
2248 < 0 ) { return this;
2249 < 0 ) {}() ) ) );
2250  
2251 < 0 ) {( function() {
2252  
2253 < 0 ) {if ( typeof window === "undefined" || !window.document ) {
2254 < 0 ) { return;
2255 < 0 ) {}
2256  
2257 < 0 ) {var config = QUnit.config,
2258 < 0 ) { hasOwn = Object.prototype.hasOwnProperty;
2259  
2260 < 0 ) {// Stores fixture HTML for resetting later
2261 < 0 ) {function storeFixture() {
2262  
2263 < 0 ) { // Avoid overwriting user-defined values
2264 < 0 ) { if ( hasOwn.call( config, "fixture" ) ) {
2265 < 0 ) { return;
2266 < 0 ) { }
2267  
2268 < 0 ) { var fixture = document.getElementById( "qunit-fixture" );
2269 < 0 ) { if ( fixture ) {
2270 < 0 ) { config.fixture = fixture.innerHTML;
2271 < 0 ) { }
2272 < 0 ) {}
2273  
2274 < 0 ) {QUnit.begin( storeFixture );
2275  
2276 < 0 ) {// Resets the fixture DOM element if available.
2277 < 0 ) {function resetFixture() {
2278 < 0 ) { if ( config.fixture == null ) {
2279 < 0 ) { return;
2280 < 0 ) { }
2281  
2282 < 0 ) { var fixture = document.getElementById( "qunit-fixture" );
2283 < 0 ) { if ( fixture ) {
2284 < 0 ) { fixture.innerHTML = config.fixture;
2285 < 0 ) { }
2286 < 0 ) {}
2287  
2288 < 0 ) {QUnit.testStart( resetFixture );
2289  
2290 < 0 ) {}() );
2291  
2292 < 0 ) {( function() {
2293  
2294 < 0 ) {// Only interact with URLs via window.location
2295 < 0 ) {var location = typeof window !== "undefined" && window.location;
2296 < 0 ) {if ( !location ) {
2297 < 0 ) { return;
2298 < 0 ) {}
2299  
2300 < 0 ) {var urlParams = getUrlParams();
2301  
2302 < 0 ) {QUnit.urlParams = urlParams;
2303  
2304 < 0 ) {// Match module/test by inclusion in an array
2305 < 0 ) {QUnit.config.moduleId = [].concat( urlParams.moduleId || [] );
2306 < 0 ) {QUnit.config.testId = [].concat( urlParams.testId || [] );
2307  
2308 < 0 ) {// Exact case-insensitive match of the module name
2309 < 0 ) {QUnit.config.module = urlParams.module;
2310  
2311 < 0 ) {// Regular expression or case-insenstive substring match against "moduleName: testName"
2312 < 0 ) {QUnit.config.filter = urlParams.filter;
2313  
2314 < 0 ) {// Test order randomization
2315 < 0 ) {if ( urlParams.seed === true ) {
2316  
2317 < 0 ) { // Generate a random seed if the option is specified without a value
2318 < 0 ) { QUnit.config.seed = Math.random().toString( 36 ).slice( 2 );
2319 < 0 ) {} else if ( urlParams.seed ) {
2320 < 0 ) { QUnit.config.seed = urlParams.seed;
2321 < 0 ) {}
2322  
2323 < 0 ) {// Add URL-parameter-mapped config values with UI form rendering data
2324 < 0 ) {QUnit.config.urlConfig.push(
2325 < 0 ) { {
2326 < 0 ) { id: "hidepassed",
2327 < 0 ) { label: "Hide passed tests",
2328 < 0 ) { tooltip: "Only show tests and assertions that fail. Stored as query-strings."
2329 < 0 ) { },
2330 < 0 ) { {
2331 < 0 ) { id: "noglobals",
2332 < 0 ) { label: "Check for Globals",
2333 < 0 ) { tooltip: "Enabling this will test if any test introduces new properties on the " +
2334 < 0 ) { "global object (`window` in Browsers). Stored as query-strings."
2335 < 0 ) { },
2336 < 0 ) { {
2337 < 0 ) { id: "notrycatch",
2338 < 0 ) { label: "No try-catch",
2339 < 0 ) { tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging " +
2340 < 0 ) { "exceptions in IE reasonable. Stored as query-strings."
2341 < 0 ) { }
2342 < 0 ) {);
2343  
2344 < 0 ) {QUnit.begin( function() {
2345 < 0 ) { var i, option,
2346 < 0 ) { urlConfig = QUnit.config.urlConfig;
2347  
2348 < 0 ) { for ( i = 0; i < urlConfig.length; i++ ) {
2349  
2350 < 0 ) { // Options can be either strings or objects with nonempty "id" properties
2351 < 0 ) { option = QUnit.config.urlConfig[ i ];
2352 < 0 ) { if ( typeof option !== "string" ) {
2353 < 0 ) { option = option.id;
2354 < 0 ) { }
2355  
2356 < 0 ) { if ( QUnit.config[ option ] === undefined ) {
2357 < 0 ) { QUnit.config[ option ] = urlParams[ option ];
2358 < 0 ) { }
2359 < 0 ) { }
2360 < 0 ) {} );
2361  
2362 < 0 ) {function getUrlParams() {
2363 < 0 ) { var i, param, name, value;
2364 < 0 ) { var urlParams = {};
2365 < 0 ) { var params = location.search.slice( 1 ).split( "&" );
2366 < 0 ) { var length = params.length;
2367  
2368 < 0 ) { for ( i = 0; i < length; i++ ) {
2369 < 0 ) { if ( params[ i ] ) {
2370 < 0 ) { param = params[ i ].split( "=" );
2371 < 0 ) { name = decodeQueryParam( param[ 0 ] );
2372  
2373 < 0 ) { // Allow just a key to turn on a flag, e.g., test.html?noglobals
2374 < 0 ) { value = param.length === 1 ||
2375 < 0 ) { decodeQueryParam( param.slice( 1 ).join( "=" ) ) ;
2376 < 0 ) { if ( urlParams[ name ] ) {
2377 < 0 ) { urlParams[ name ] = [].concat( urlParams[ name ], value );
2378 < 0 ) { } else {
2379 < 0 ) { urlParams[ name ] = value;
2380 < 0 ) { }
2381 < 0 ) { }
2382 < 0 ) { }
2383  
2384 < 0 ) { return urlParams;
2385 < 0 ) {}
2386  
2387 < 0 ) {function decodeQueryParam( param ) {
2388 < 0 ) { return decodeURIComponent( param.replace( /\+/g, "%20" ) );
2389 < 0 ) {}
2390  
2391 < 0 ) {// Don't load the HTML Reporter on non-browser environments
2392 < 0 ) {if ( typeof window === "undefined" || !window.document ) {
2393 < 0 ) { return;
2394 < 0 ) {}
2395  
2396 < 0 ) {QUnit.init = function() {
2397 < 0 ) { throw new Error(
2398 < 0 ) { "QUnit.init is removed in QUnit 2.0, use QUnit.test() with assert.async() instead.\n" +
2399 < 0 ) { "Details in our upgrade guide at https://qunitjs.com/upgrade-guide-2.x/"
2400 < 0 ) { );
2401 < 0 ) {};
2402  
2403 < 0 ) {var config = QUnit.config,
2404 < 0 ) { document = window.document,
2405 < 0 ) { collapseNext = false,
2406 < 0 ) { hasOwn = Object.prototype.hasOwnProperty,
2407 < 0 ) { unfilteredUrl = setUrl( { filter: undefined, module: undefined,
2408 < 0 ) { moduleId: undefined, testId: undefined } ),
2409 < 0 ) { defined = {
2410 < 0 ) { sessionStorage: ( function() {
2411 < 0 ) { var x = "qunit-test-string";
2412 < 0 ) { try {
2413 < 0 ) { sessionStorage.setItem( x, x );
2414 < 0 ) { sessionStorage.removeItem( x );
2415 < 0 ) { return true;
2416 < 0 ) { } catch ( e ) {
2417 < 0 ) { return false;
2418 < 0 ) { }
2419 < 0 ) { }() )
2420 < 0 ) { },
2421 < 0 ) { modulesList = [];
2422  
2423 < 0 ) {// Escape text for attribute or text content.
2424 < 0 ) {function escapeText( s ) {
2425 < 0 ) { if ( !s ) {
2426 < 0 ) { return "";
2427 < 0 ) { }
2428 < 0 ) { s = s + "";
2429  
2430 < 0 ) { // Both single quotes and double quotes (for attributes)
2431 < 0 ) { return s.replace( /['"<>&]/g, function( s ) {
2432 < 0 ) {<> switch ( s ) {
2433 < 0 ) {<> case "'":
2434 < 0 ) {<> return "&#039;";
2435 < 0 ) {<> case "\"":
2436 < 0 ) {<> return "&quot;";
2437 < 0 ) {<> case "<":
2438 < 0 ) {<> return "&lt;";
2439 < 0 ) {<> case ">":
2440 < 0 ) {<> return "&gt;";
2441 < 0 ) {<> case "&":
2442 < 0 ) {<> return "&amp;";
2443 < 0 ) {<> }
2444 < 0 ) {<> } );
2445 < 0 ) {<>}
2446  
2447 < 0 ) {<>function addEvent( elem, type, fn ) {
2448 < 0 ) {<> elem.addEventListener( type, fn, false );
2449 < 0 ) {<>}
2450  
2451 < 0 ) {<>function removeEvent( elem, type, fn ) {
2452 < 0 ) {<> elem.removeEventListener( type, fn, false );
2453 < 0 ) {<>}
2454  
2455 < 0 ) {<>function addEvents( elems, type, fn ) {
2456 < 0 ) {<> var i = elems.length;
2457 < 0 ) {<> while ( i-- ) {
2458 < 0 ) {<> addEvent( elems[ i ], type, fn );
2459 < 0 ) {<> }
2460 < 0 ) {<>}
2461  
2462 < 0 ) {<>function hasClass( elem, name ) {
2463 < 0 ) {<> return ( " " + elem.className + " " ).indexOf( " " + name + " " ) >= 0;
2464 < 0 ) {<>}
2465  
2466 < 0 ) {<>function addClass( elem, name ) {
2467 < 0 ) {<> if ( !hasClass( elem, name ) ) {
2468 < 0 ) {<> elem.className += ( elem.className ? " " : "" ) + name;
2469 < 0 ) {<> }
2470 < 0 ) {<>}
2471  
2472 < 0 ) {<>function toggleClass( elem, name, force ) {
2473 < 0 ) {<> if ( force || typeof force === "undefined" && !hasClass( elem, name ) ) {
2474 < 0 ) {<> addClass( elem, name );
2475 < 0 ) {<> } else {
2476 < 0 ) {<> removeClass( elem, name );
2477 < 0 ) {<> }
2478 < 0 ) {<>}
2479  
2480 < 0 ) {<>function removeClass( elem, name ) {
2481 < 0 ) {<> var set = " " + elem.className + " ";
2482  
2483 < 0 ) {<> // Class name may appear multiple times
2484 < 0 ) {<> while ( set.indexOf( " " + name + " " ) >= 0 ) {
2485 < 0 ) {<> set = set.replace( " " + name + " ", " " );
2486 < 0 ) {<> }
2487  
2488 < 0 ) {<> // Trim for prettiness
2489 < 0 ) {<> elem.className = typeof set.trim === "function" ? set.trim() : set.replace( /^\s+|\s+$/g, "" );
2490 < 0 ) {<>}
2491  
2492 < 0 ) {<>function id( name ) {
2493 < 0 ) {<> return document.getElementById && document.getElementById( name );
2494 < 0 ) {<>}
2495  
2496 < 0 ) {<>function interceptNavigation( ev ) {
2497 < 0 ) {<> applyUrlParams();
2498  
2499 < 0 ) {<> if ( ev && ev.preventDefault ) {
2500 < 0 ) {<> ev.preventDefault();
2501 < 0 ) {<> }
2502  
2503 < 0 ) {<> return false;
2504 < 0 ) {<>}
2505  
2506 < 0 ) {<>function getUrlConfigHtml() {
2507 < 0 ) {<> var i, j, val,
2508 < 0 ) {<> escaped, escapedTooltip,
2509 < 0 ) {<> selection = false,
2510 < 0 ) {<> urlConfig = config.urlConfig,
2511 < 0 ) {<> urlConfigHtml = "";
2512  
2513 < 0 ) {<> for ( i = 0; i < urlConfig.length; i++ ) {
2514  
2515 < 0 ) {<> // Options can be either strings or objects with nonempty "id" properties
2516 < 0 ) {<> val = config.urlConfig[ i ];
2517 < 0 ) {<> if ( typeof val === "string" ) {
2518 < 0 ) {<> val = {
2519 < 0 ) {<> id: val,
2520 < 0 ) {<> label: val
2521 < 0 ) {<> };
2522 < 0 ) {<> }
2523  
2524 < 0 ) {<> escaped = escapeText( val.id );
2525 < 0 ) {<> escapedTooltip = escapeText( val.tooltip );
2526  
2527 < 0 ) {<> if ( !val.value || typeof val.value === "string" ) {
2528 < 0 ) {<> urlConfigHtml += "<label for='qunit-urlconfig-" + escaped +
2529 < 0 ) {<> "' title='" + escapedTooltip + "'><input id='qunit-urlconfig-" + escaped +
2530 < 0 ) {<> "' name='" + escaped + "' type='checkbox'" +
2531 < 0 ) {<> ( val.value ? " value='" + escapeText( val.value ) + "'" : "" ) +
2532 < 0 ) {<> ( config[ val.id ] ? " checked='checked'" : "" ) +
2533 < 0 ) {<> " title='" + escapedTooltip + "' />" + escapeText( val.label ) + "</label>";
2534 < 0 ) {<> } else {
2535 < 0 ) {<> urlConfigHtml += "<label for='qunit-urlconfig-" + escaped +
2536 < 0 ) {<> "' title='" + escapedTooltip + "'>" + val.label +
2537 < 0 ) {<> ": </label><select id='qunit-urlconfig-" + escaped +
2538 < 0 ) {<> "' name='" + escaped + "' title='" + escapedTooltip + "'><option></option>";
2539  
2540 < 0 ) {<> if ( QUnit.is( "array", val.value ) ) {
2541 < 0 ) {<> for ( j = 0; j < val.value.length; j++ ) {
2542 < 0 ) {<> escaped = escapeText( val.value[ j ] );
2543 < 0 ) {<> urlConfigHtml += "<option value='" + escaped + "'" +
2544 < 0 ) {<> ( config[ val.id ] === val.value[ j ] ?
2545 < 0 ) {<> ( selection = true ) && " selected='selected'" : "" ) +
2546 < 0 ) {<> ">" + escaped + "</option>";
2547 < 0 ) {<> }
2548 < 0 ) {<> } else {
2549 < 0 ) {<> for ( j in val.value ) {
2550 < 0 ) {<> if ( hasOwn.call( val.value, j ) ) {
2551 < 0 ) {<> urlConfigHtml += "<option value='" + escapeText( j ) + "'" +
2552 < 0 ) {<> ( config[ val.id ] === j ?
2553 < 0 ) {<> ( selection = true ) && " selected='selected'" : "" ) +
2554 < 0 ) {<> ">" + escapeText( val.value[ j ] ) + "</option>";
2555 < 0 ) {<> }
2556 < 0 ) {<> }
2557 < 0 ) {<> }
2558 < 0 ) {<> if ( config[ val.id ] && !selection ) {
2559 < 0 ) {<> escaped = escapeText( config[ val.id ] );
2560 < 0 ) {<> urlConfigHtml += "<option value='" + escaped +
2561 < 0 ) {<> "' selected='selected' disabled='disabled'>" + escaped + "</option>";
2562 < 0 ) {<> }
2563 < 0 ) {<> urlConfigHtml += "</select>";
2564 < 0 ) {<> }
2565 < 0 ) {<> }
2566  
2567 < 0 ) {<> return urlConfigHtml;
2568 < 0 ) {<>}
2569  
2570 < 0 ) {<>// Handle "click" events on toolbar checkboxes and "change" for select menus.
2571 < 0 ) {<>// Updates the URL with the new state of `config.urlConfig` values.
2572 < 0 ) {<>function toolbarChanged() {
2573 < 0 ) {<> var updatedUrl, value, tests,
2574 < 0 ) {<> field = this,
2575 < 0 ) {<> params = {};
2576  
2577 < 0 ) {<> // Detect if field is a select menu or a checkbox
2578 < 0 ) {<> if ( "selectedIndex" in field ) {
2579 < 0 ) {<> value = field.options[ field.selectedIndex ].value || undefined;
2580 < 0 ) {<> } else {
2581 < 0 ) {<> value = field.checked ? ( field.defaultValue || true ) : undefined;
2582 < 0 ) {<> }
2583  
2584 < 0 ) {<> params[ field.name ] = value;
2585 < 0 ) {<> updatedUrl = setUrl( params );
2586  
2587 < 0 ) {<> // Check if we can apply the change without a page refresh
2588 < 0 ) {<> if ( "hidepassed" === field.name && "replaceState" in window.history ) {
2589 < 0 ) {<> QUnit.urlParams[ field.name ] = value;
2590 < 0 ) {<> config[ field.name ] = value || false;
2591 < 0 ) {<> tests = id( "qunit-tests" );
2592 < 0 ) {<> if ( tests ) {
2593 < 0 ) {<> toggleClass( tests, "hidepass", value || false );
2594 < 0 ) {<> }
2595 < 0 ) {<> window.history.replaceState( null, "", updatedUrl );
2596 < 0 ) {<> } else {
2597 < 0 ) {<> window.location = updatedUrl;
2598 < 0 ) {<> }
2599 < 0 ) {<>}
2600  
2601 < 0 ) {<>function setUrl( params ) {
2602 < 0 ) {<> var key, arrValue, i,
2603 < 0 ) {<> querystring = "?",
2604 < 0 ) {<> location = window.location;
2605  
2606 < 0 ) {<> params = QUnit.extend( QUnit.extend( {}, QUnit.urlParams ), params );
2607  
2608 < 0 ) {<> for ( key in params ) {
2609  
2610 < 0 ) {<> // Skip inherited or undefined properties
2611 < 0 ) {<> if ( hasOwn.call( params, key ) && params[ key ] !== undefined ) {
2612  
2613 < 0 ) {<> // Output a parameter for each value of this key (but usually just one)
2614 < 0 ) {<> arrValue = [].concat( params[ key ] );
2615 < 0 ) {<> for ( i = 0; i < arrValue.length; i++ ) {
2616 < 0 ) {<> querystring += encodeURIComponent( key );
2617 < 0 ) {<> if ( arrValue[ i ] !== true ) {
2618 < 0 ) {<> querystring += "=" + encodeURIComponent( arrValue[ i ] );
2619 < 0 ) {<> }
2620 < 0 ) {<> querystring += "&";
2621 < 0 ) {<> }
2622 < 0 ) {<> }
2623 < 0 ) {<> }
2624 < 0 ) {<> return location.protocol + "//" + location.host +
2625 < 0 ) {<> location.pathname + querystring.slice( 0, -1 );
2626 < 0 ) {<>}
2627  
2628 < 0 ) {<>function applyUrlParams() {
2629 < 0 ) {<> var i,
2630 < 0 ) {<> selectedModules = [],
2631 < 0 ) {<> modulesList = id( "qunit-modulefilter-dropdown-list" ).getElementsByTagName( "input" ),
2632 < 0 ) {<> filter = id( "qunit-filter-input" ).value;
2633  
2634 < 0 ) {<> for ( i = 0; i < modulesList.length; i++ ) {
2635 < 0 ) {<> if ( modulesList[ i ].checked ) {
2636 < 0 ) {<> selectedModules.push( modulesList[ i ].value );
2637 < 0 ) {<> }
2638 < 0 ) {<> }
2639  
2640 < 0 ) {<> window.location = setUrl( {
2641 < 0 ) {<> filter: ( filter === "" ) ? undefined : filter,
2642 < 0 ) {<> moduleId: ( selectedModules.length === 0 ) ? undefined : selectedModules,
2643  
2644 < 0 ) {<> // Remove module and testId filter
2645 < 0 ) {<> module: undefined,
2646 < 0 ) {<> testId: undefined
2647 < 0 ) {<> } );
2648 < 0 ) {<>}
2649  
2650 < 0 ) {<>function toolbarUrlConfigContainer() {
2651 < 0 ) {<> var urlConfigContainer = document.createElement( "span" );
2652  
2653 < 0 ) {<> urlConfigContainer.innerHTML = getUrlConfigHtml();
2654 < 0 ) {<> addClass( urlConfigContainer, "qunit-url-config" );
2655  
2656 < 0 ) {<> addEvents( urlConfigContainer.getElementsByTagName( "input" ), "change", toolbarChanged );
2657 < 0 ) {<> addEvents( urlConfigContainer.getElementsByTagName( "select" ), "change", toolbarChanged );
2658  
2659 < 0 ) {<> return urlConfigContainer;
2660 < 0 ) {<>}
2661  
2662 < 0 ) {<>function toolbarLooseFilter() {
2663 < 0 ) {<> var filter = document.createElement( "form" ),
2664 < 0 ) {<> label = document.createElement( "label" ),
2665 < 0 ) {<> input = document.createElement( "input" ),
2666 < 0 ) {<> button = document.createElement( "button" );
2667  
2668 < 0 ) {<> addClass( filter, "qunit-filter" );
2669  
2670 < 0 ) {<> label.innerHTML = "Filter: ";
2671  
2672 < 0 ) {<> input.type = "text";
2673 < 0 ) {<> input.value = config.filter || "";
2674 < 0 ) {<> input.name = "filter";
2675 < 0 ) {<> input.id = "qunit-filter-input";
2676  
2677 < 0 ) {<> button.innerHTML = "Go";
2678  
2679 < 0 ) {<> label.appendChild( input );
2680  
2681 < 0 ) {<> filter.appendChild( label );
2682 < 0 ) {<> filter.appendChild( document.createTextNode( " " ) );
2683 < 0 ) {<> filter.appendChild( button );
2684 < 0 ) {<> addEvent( filter, "submit", interceptNavigation );
2685  
2686 < 0 ) {<> return filter;
2687 < 0 ) {<>}
2688  
2689 < 0 ) {<>function moduleListHtml () {
2690 < 0 ) {<> var i, checked,
2691 < 0 ) {<> html = "";
2692  
2693 < 0 ) {<> for ( i = 0; i < config.modules.length; i++ ) {
2694 < 0 ) {<> if ( config.modules[ i ].name !== "" ) {
2695 < 0 ) {<> checked = config.moduleId.indexOf( config.modules[ i ].moduleId ) > -1;
2696 < 0 ) {<> html += "<li><label class='clickable" + ( checked ? " checked" : "" ) +
2697 < 0 ) {<> "'><input type='checkbox' " + "value='" + config.modules[ i ].moduleId + "'" +
2698 < 0 ) {<> ( checked ? " checked='checked'" : "" ) + " />" +
2699 < 0 ) {<> escapeText( config.modules[ i ].name ) + "</label></li>";
2700 < 0 ) {<> }
2701 < 0 ) {<> }
2702  
2703 < 0 ) {<> return html;
2704 < 0 ) {<>}
2705  
2706 < 0 ) {<>function toolbarModuleFilter () {
2707 < 0 ) {<> var allCheckbox, commit, reset,
2708 < 0 ) {<> moduleFilter = document.createElement( "form" ),
2709 < 0 ) {<> label = document.createElement( "label" ),
2710 < 0 ) {<> moduleSearch = document.createElement( "input" ),
2711 < 0 ) {<> dropDown = document.createElement( "div" ),
2712 < 0 ) {<> actions = document.createElement( "span" ),
2713 < 0 ) {<> dropDownList = document.createElement( "ul" ),
2714 < 0 ) {<> dirty = false;
2715  
2716 < 0 ) {<> moduleSearch.id = "qunit-modulefilter-search";
2717 < 0 ) {<> addEvent( moduleSearch, "input", searchInput );
2718 < 0 ) {<> addEvent( moduleSearch, "input", searchFocus );
2719 < 0 ) {<> addEvent( moduleSearch, "focus", searchFocus );
2720 < 0 ) {<> addEvent( moduleSearch, "click", searchFocus );
2721  
2722 < 0 ) {<> label.id = "qunit-modulefilter-search-container";
2723 < 0 ) {<> label.innerHTML = "Module: ";
2724 < 0 ) {<> label.appendChild( moduleSearch );
2725  
2726 < 0 ) {<> actions.id = "qunit-modulefilter-actions";
2727 < 0 ) {<> actions.innerHTML =
2728 < 0 ) {<> "<button style='display:none'>Apply</button>" +
2729 < 0 ) {<> "<button type='reset' style='display:none'>Reset</button>" +
2730 < 0 ) {<> "<label class='clickable" +
2731 < 0 ) {<> ( config.moduleId.length ? "" : " checked" ) +
2732 < 0 ) {<> "'><input type='checkbox'" + ( config.moduleId.length ? "" : " checked='checked'" ) +
2733 < 0 ) {<> ">All modules</label>";
2734 < 0 ) {<> allCheckbox = actions.lastChild.firstChild;
2735 < 0 ) {<> commit = actions.firstChild;
2736 < 0 ) {<> reset = commit.nextSibling;
2737 < 0 ) {<> addEvent( commit, "click", applyUrlParams );
2738  
2739 < 0 ) {<> dropDownList.id = "qunit-modulefilter-dropdown-list";
2740 < 0 ) {<> dropDownList.innerHTML = moduleListHtml();
2741  
2742 < 0 ) {<> dropDown.id = "qunit-modulefilter-dropdown";
2743 < 0 ) {<> dropDown.style.display = "none";
2744 < 0 ) {<> dropDown.appendChild( actions );
2745 < 0 ) {<> dropDown.appendChild( dropDownList );
2746 < 0 ) {<> addEvent( dropDown, "change", selectionChange );
2747 < 0 ) {<> selectionChange();
2748  
2749 < 0 ) {<> moduleFilter.id = "qunit-modulefilter";
2750 < 0 ) {<> moduleFilter.appendChild( label );
2751 < 0 ) {<> moduleFilter.appendChild( dropDown ) ;
2752 < 0 ) {<> addEvent( moduleFilter, "submit", interceptNavigation );
2753 < 0 ) {<> addEvent( moduleFilter, "reset", function() {
2754  
2755 < 0 ) {<> // Let the reset happen, then update styles
2756 < 0 ) {<> window.setTimeout( selectionChange );
2757 < 0 ) {<> } );
2758  
2759 < 0 ) {<> // Enables show/hide for the dropdown
2760 < 0 ) {<> function searchFocus() {
2761 < 0 ) {<> if ( dropDown.style.display !== "none" ) {
2762 < 0 ) {<> return;
2763 < 0 ) {<> }
2764  
2765 < 0 ) {<> dropDown.style.display = "block";
2766 < 0 ) {<> addEvent( document, "click", hideHandler );
2767 < 0 ) {<> addEvent( document, "keydown", hideHandler );
2768  
2769 < 0 ) {<> // Hide on Escape keydown or outside-container click
2770 < 0 ) {<> function hideHandler( e ) {
2771 < 0 ) {<> var inContainer = moduleFilter.contains( e.target );
2772  
2773 < 0 ) {<> if ( e.keyCode === 27 || !inContainer ) {
2774 < 0 ) {<> if ( e.keyCode === 27 && inContainer ) {
2775 < 0 ) {<> moduleSearch.focus();
2776 < 0 ) {<> }
2777 < 0 ) {<> dropDown.style.display = "none";
2778 < 0 ) {<> removeEvent( document, "click", hideHandler );
2779 < 0 ) {<> removeEvent( document, "keydown", hideHandler );
2780 < 0 ) {<> moduleSearch.value = "";
2781 < 0 ) {<> searchInput();
2782 < 0 ) {<> }
2783 < 0 ) {<> }
2784 < 0 ) {<> }
2785  
2786 < 0 ) {<> // Processes module search box input
2787 < 0 ) {<> function searchInput() {
2788 < 0 ) {<> var i, item,
2789 < 0 ) {<> searchText = moduleSearch.value.toLowerCase(),
2790 < 0 ) {<> listItems = dropDownList.children;
2791  
2792 < 0 ) {<> for ( i = 0; i < listItems.length; i++ ) {
2793 < 0 ) {<> item = listItems[ i ];
2794 < 0 ) {<> if ( !searchText || item.textContent.toLowerCase().indexOf( searchText ) > -1 ) {
2795 < 0 ) {<> item.style.display = "";
2796 < 0 ) {<> } else {
2797 < 0 ) {<> item.style.display = "none";
2798 < 0 ) {<> }
2799 < 0 ) {<> }
2800 < 0 ) {<> }
2801  
2802 < 0 ) {<> // Processes selection changes
2803 < 0 ) {<> function selectionChange( evt ) {
2804 < 0 ) {<> var i, item,
2805 < 0 ) {<> checkbox = evt && evt.target || allCheckbox,
2806 < 0 ) {<> modulesList = dropDownList.getElementsByTagName( "input" ),
2807 < 0 ) {<> selectedNames = [];
2808  
2809 < 0 ) {<> toggleClass( checkbox.parentNode, "checked", checkbox.checked );
2810  
2811 < 0 ) {<> dirty = false;
2812 < 0 ) {<> if ( checkbox.checked && checkbox !== allCheckbox ) {
2813 < 0 ) {<> allCheckbox.checked = false;
2814 < 0 ) {<> removeClass( allCheckbox.parentNode, "checked" );
2815 < 0 ) {<> }
2816 < 0 ) {<> for ( i = 0; i < modulesList.length; i++ ) {
2817 < 0 ) {<> item = modulesList[ i ];
2818 < 0 ) {<> if ( !evt ) {
2819 < 0 ) {<> toggleClass( item.parentNode, "checked", item.checked );
2820 < 0 ) {<> } else if ( checkbox === allCheckbox && checkbox.checked ) {
2821 < 0 ) {<> item.checked = false;
2822 < 0 ) {<> removeClass( item.parentNode, "checked" );
2823 < 0 ) {<> }
2824 < 0 ) {<> dirty = dirty || ( item.checked !== item.defaultChecked );
2825 < 0 ) {<> if ( item.checked ) {
2826 < 0 ) {<> selectedNames.push( item.parentNode.textContent );
2827 < 0 ) {<> }
2828 < 0 ) {<> }
2829  
2830 < 0 ) {<> commit.style.display = reset.style.display = dirty ? "" : "none";
2831 < 0 ) {<> moduleSearch.placeholder = selectedNames.join( ", " ) || allCheckbox.parentNode.textContent;
2832 < 0 ) {<> moduleSearch.title = "Type to filter list. Current selection:\n" +
2833 < 0 ) {<> ( selectedNames.join( "\n" ) || allCheckbox.parentNode.textContent );
2834 < 0 ) {<> }
2835  
2836 < 0 ) {<> return moduleFilter;
2837 < 0 ) {<>}
2838  
2839 < 0 ) {<>function appendToolbar() {
2840 < 0 ) {<> var toolbar = id( "qunit-testrunner-toolbar" );
2841  
2842 < 0 ) {<> if ( toolbar ) {
2843 < 0 ) {<> toolbar.appendChild( toolbarUrlConfigContainer() );
2844 < 0 ) {<> toolbar.appendChild( toolbarModuleFilter() );
2845 < 0 ) {<> toolbar.appendChild( toolbarLooseFilter() );
2846 < 0 ) {<> toolbar.appendChild( document.createElement( "div" ) ).className = "clearfix";
2847 < 0 ) {<> }
2848 < 0 ) {<>}
2849  
2850 < 0 ) {<>function appendHeader() {
2851 < 0 ) {<> var header = id( "qunit-header" );
2852  
2853 < 0 ) {<> if ( header ) {
2854 < 0 ) {<> header.innerHTML = "<a href='" + escapeText( unfilteredUrl ) + "'>" + header.innerHTML +
2855 < 0 ) {<> "</a> ";
2856 < 0 ) {<> }
2857 < 0 ) {<>}
2858  
2859 < 0 ) {<>function appendBanner() {
2860 < 0 ) {<> var banner = id( "qunit-banner" );
2861  
2862 < 0 ) {<> if ( banner ) {
2863 < 0 ) {<> banner.className = "";
2864 < 0 ) {<> }
2865 < 0 ) {<>}
2866  
2867 < 0 ) {<>function appendTestResults() {
2868 < 0 ) {<> var tests = id( "qunit-tests" ),
2869 < 0 ) {<> result = id( "qunit-testresult" );
2870  
2871 < 0 ) {<> if ( result ) {
2872 < 0 ) {<> result.parentNode.removeChild( result );
2873 < 0 ) {<> }
2874  
2875 < 0 ) {<> if ( tests ) {
2876 < 0 ) {<> tests.innerHTML = "";
2877 < 0 ) {<> result = document.createElement( "p" );
2878 < 0 ) {<> result.id = "qunit-testresult";
2879 < 0 ) {<> result.className = "result";
2880 < 0 ) {<> tests.parentNode.insertBefore( result, tests );
2881 < 0 ) {<> result.innerHTML = "Running...<br />&#160;";
2882 < 0 ) {<> }
2883 < 0 ) {<>}
2884  
2885 < 0 ) {<>function appendFilteredTest() {
2886 < 0 ) {<> var testId = QUnit.config.testId;
2887 < 0 ) {<> if ( !testId || testId.length <= 0 ) {
2888 < 0 ) {<> return "";
2889 < 0 ) {<> }
2890 < 0 ) {<> return "<div id='qunit-filteredTest'>Rerunning selected tests: " +
2891 < 0 ) {<> escapeText( testId.join( ", " ) ) +
2892 < 0 ) {<> " <a id='qunit-clearFilter' href='" +
2893 < 0 ) {<> escapeText( unfilteredUrl ) +
2894 < 0 ) {<> "'>Run all tests</a></div>";
2895 < 0 ) {<>}
2896  
2897 < 0 ) {<>function appendUserAgent() {
2898 < 0 ) {<> var userAgent = id( "qunit-userAgent" );
2899  
2900 < 0 ) {<> if ( userAgent ) {
2901 < 0 ) {<> userAgent.innerHTML = "";
2902 < 0 ) {<> userAgent.appendChild(
2903 < 0 ) {<> document.createTextNode(
2904 < 0 ) {<> "QUnit " + QUnit.version + "; " + navigator.userAgent
2905 < 0 ) {<> )
2906 < 0 ) {<> );
2907 < 0 ) {<> }
2908 < 0 ) {<>}
2909  
2910 < 0 ) {<>function appendInterface() {
2911 < 0 ) {<> var qunit = id( "qunit" );
2912  
2913 < 0 ) {<> if ( qunit ) {
2914 < 0 ) {<> qunit.innerHTML =
2915 < 0 ) {<> "<h1 id='qunit-header'>" + escapeText( document.title ) + "</h1>" +
2916 < 0 ) {<> "<h2 id='qunit-banner'></h2>" +
2917 < 0 ) {<> "<div id='qunit-testrunner-toolbar'></div>" +
2918 < 0 ) {<> appendFilteredTest() +
2919 < 0 ) {<> "<h2 id='qunit-userAgent'></h2>" +
2920 < 0 ) {<> "<ol id='qunit-tests'></ol>";
2921 < 0 ) {<> }
2922  
2923 < 0 ) {<> appendHeader();
2924 < 0 ) {<> appendBanner();
2925 < 0 ) {<> appendTestResults();
2926 < 0 ) {<> appendUserAgent();
2927 < 0 ) {<> appendToolbar();
2928 < 0 ) {<>}
2929  
2930 < 0 ) {<>function appendTestsList( modules ) {
2931 < 0 ) {<> var i, l, x, z, test, moduleObj;
2932  
2933 < 0 ) {<> for ( i = 0, l = modules.length; i < l; i++ ) {
2934 < 0 ) {<> moduleObj = modules[ i ];
2935  
2936 < 0 ) {<> for ( x = 0, z = moduleObj.tests.length; x < z; x++ ) {
2937 < 0 ) {<> test = moduleObj.tests[ x ];
2938  
2939 < 0 ) {<> appendTest( test.name, test.testId, moduleObj.name );
2940 < 0 ) {<> }
2941 < 0 ) {<> }
2942 < 0 ) {<>}
2943  
2944 < 0 ) {<>function appendTest( name, testId, moduleName ) {
2945 < 0 ) {<> var title, rerunTrigger, testBlock, assertList,
2946 < 0 ) {<> tests = id( "qunit-tests" );
2947  
2948 < 0 ) {<> if ( !tests ) {
2949 < 0 ) {<> return;
2950 < 0 ) {<> }
2951  
2952 < 0 ) {<> title = document.createElement( "strong" );
2953 < 0 ) {<> title.innerHTML = getNameHtml( name, moduleName );
2954  
2955 < 0 ) {<> rerunTrigger = document.createElement( "a" );
2956 < 0 ) {<> rerunTrigger.innerHTML = "Rerun";
2957 < 0 ) {<> rerunTrigger.href = setUrl( { testId: testId } );
2958  
2959 < 0 ) {<> testBlock = document.createElement( "li" );
2960 < 0 ) {<> testBlock.appendChild( title );
2961 < 0 ) {<> testBlock.appendChild( rerunTrigger );
2962 < 0 ) {<> testBlock.id = "qunit-test-output-" + testId;
2963  
2964 < 0 ) {<> assertList = document.createElement( "ol" );
2965 < 0 ) {<> assertList.className = "qunit-assert-list";
2966  
2967 < 0 ) {<> testBlock.appendChild( assertList );
2968  
2969 < 0 ) {<> tests.appendChild( testBlock );
2970 < 0 ) {<>}
2971  
2972 < 0 ) {<>// HTML Reporter initialization and load
2973 < 0 ) {<>QUnit.begin( function( details ) {
2974 < 0 ) {<> var i, moduleObj, tests;
2975  
2976 < 0 ) {<> // Sort modules by name for the picker
2977 < 0 ) {<> for ( i = 0; i < details.modules.length; i++ ) {
2978 < 0 ) {<> moduleObj = details.modules[ i ];
2979 < 0 ) {<> if ( moduleObj.name ) {
2980 < 0 ) {<> modulesList.push( moduleObj.name );
2981 < 0 ) {<> }
2982 < 0 ) {<> }
2983 < 0 ) {<> modulesList.sort( function( a, b ) {
2984 < 0 ) {<> return a.localeCompare( b );
2985 < 0 ) {<> } );
2986  
2987 < 0 ) {<> // Initialize QUnit elements
2988 < 0 ) {<> appendInterface();
2989 < 0 ) {<> appendTestsList( details.modules );
2990 < 0 ) {<> tests = id( "qunit-tests" );
2991 < 0 ) {<> if ( tests && config.hidepassed ) {
2992 < 0 ) {<> addClass( tests, "hidepass" );
2993 < 0 ) {<> }
2994 < 0 ) {<>} );
2995  
2996 < 0 ) {<>QUnit.done( function( details ) {
2997 < 0 ) {<> var i, key,
2998 < 0 ) {<> banner = id( "qunit-banner" ),
2999 < 0 ) {<> tests = id( "qunit-tests" ),
3000 < 0 ) {<> html = [
3001 < 0 ) {<> "Tests completed in ",
3002 < 0 ) {<> details.runtime,
3003 < 0 ) {<> " milliseconds.<br />",
3004 < 0 ) {<> "<span class='passed'>",
3005 < 0 ) {<> details.passed,
3006 < 0 ) {<> "</span> assertions of <span class='total'>",
3007 < 0 ) {<> details.total,
3008 < 0 ) {<> "</span> passed, <span class='failed'>",
3009 < 0 ) {<> details.failed,
3010 < 0 ) {<> "</span> failed."
3011 < 0 ) {<> ].join( "" );
3012  
3013 < 0 ) {<> if ( banner ) {
3014 < 0 ) {<> banner.className = details.failed ? "qunit-fail" : "qunit-pass";
3015 < 0 ) {<> }
3016  
3017 < 0 ) {<> if ( tests ) {
3018 < 0 ) {<> id( "qunit-testresult" ).innerHTML = html;
3019 < 0 ) {<> }
3020  
3021 < 0 ) {<> if ( config.altertitle && document.title ) {
3022  
3023 < 0 ) {<> // Show ✖ for good, ✔ for bad suite result in title
3024 < 0 ) {<> // use escape sequences in case file gets loaded with non-utf-8-charset
3025 < 0 ) {<> document.title = [
3026 < 0 ) {<> ( details.failed ? "\u2716" : "\u2714" ),
3027 < 0 ) {<> document.title.replace( /^[\u2714\u2716] /i, "" )
3028 < 0 ) {<> ].join( " " );
3029 < 0 ) {<> }
3030  
3031 < 0 ) {<> // Clear own sessionStorage items if all tests passed
3032 < 0 ) {<> if ( config.reorder && defined.sessionStorage && details.failed === 0 ) {
3033 < 0 ) {<> for ( i = 0; i < sessionStorage.length; i++ ) {
3034 < 0 ) {<> key = sessionStorage.key( i++ );
3035 < 0 ) {<> if ( key.indexOf( "qunit-test-" ) === 0 ) {
3036 < 0 ) {<> sessionStorage.removeItem( key );
3037 < 0 ) {<> }
3038 < 0 ) {<> }
3039 < 0 ) {<> }
3040  
3041 < 0 ) {<> // Scroll back to top to show results
3042 < 0 ) {<> if ( config.scrolltop && window.scrollTo ) {
3043 < 0 ) {<> window.scrollTo( 0, 0 );
3044 < 0 ) {<> }
3045 < 0 ) {<>} );
3046  
3047 < 0 ) {<>function getNameHtml( name, module ) {
3048 < 0 ) {<> var nameHtml = "";
3049  
3050 < 0 ) {<> if ( module ) {
3051 < 0 ) {<> nameHtml = "<span class='module-name'>" + escapeText( module ) + "</span>: ";
3052 < 0 ) {<> }
3053  
3054 < 0 ) {<> nameHtml += "<span class='test-name'>" + escapeText( name ) + "</span>";
3055  
3056 < 0 ) {<> return nameHtml;
3057 < 0 ) {<>}
3058  
3059 < 0 ) {<>QUnit.testStart( function( details ) {
3060 < 0 ) {<> var running, testBlock, bad;
3061  
3062 < 0 ) {<> testBlock = id( "qunit-test-output-" + details.testId );
3063 < 0 ) {<> if ( testBlock ) {
3064 < 0 ) {<> testBlock.className = "running";
3065 < 0 ) {<> } else {
3066  
3067 < 0 ) {<> // Report later registered tests
3068 < 0 ) {<> appendTest( details.name, details.testId, details.module );
3069 < 0 ) {<> }
3070  
3071 < 0 ) {<> running = id( "qunit-testresult" );
3072 < 0 ) {<> if ( running ) {
3073 < 0 ) {<> bad = QUnit.config.reorder && defined.sessionStorage &&
3074 < 0 ) {<> +sessionStorage.getItem( "qunit-test-" + details.module + "-" + details.name );
3075  
3076 < 0 ) {<> running.innerHTML = ( bad ?
3077 < 0 ) {<> "Rerunning previously failed test: <br />" :
3078 < 0 ) {<> "Running: <br />" ) +
3079 < 0 ) {<> getNameHtml( details.name, details.module );
3080 < 0 ) {<> }
3081  
3082 < 0 ) {<>} );
3083  
3084 < 0 ) {<>function stripHtml( string ) {
3085  
3086 < 0 ) {<> // Strip tags, html entity and whitespaces
3087 < 0 ) {<> return string.replace( /<\/?[^>]+(>|$)/g, "" ).replace( /\"/g, "" ).replace( /\s+/g, "" );
3088 < 0 ) {<><\/?[^>}
3089  
3090 < 0 ) {<><\/?[^>QUnit.log( function( details ) {
3091 < 0 ) {<><\/?[^> var assertList, assertLi,
3092 < 0 ) {<><\/?[^> message, expected, actual, diff,
3093 < 0 ) {<><\/?[^> showDiff = false,
3094 < 0 ) {<><\/?[^> testItem = id( "qunit-test-output-" + details.testId );
3095  
3096 < 0 ) {<><\/?[^> if ( !testItem ) {
3097 < 0 ) {<><\/?[^> return;
3098 < 0 ) {<><\/?[^> }
3099  
3100 < 0 ) {<><\/?[^> message = escapeText( details.message ) || ( details.result ? "okay" : "failed" );
3101 < 0 ) {<><\/?[^> message = "<span class='test-message'>" + message + "</span>";
3102 < 0 ) {<><\/?[^> message += "<span class='runtime'>@ " + details.runtime + " ms</span>";
3103  
3104 < 0 ) {<><\/?[^> // The pushFailure doesn't provide details.expected
3105 < 0 ) {<><\/?[^> // when it calls, it's implicit to also not show expected and diff stuff
3106 < 0 ) {<><\/?[^> // Also, we need to check details.expected existence, as it can exist and be undefined
3107 < 0 ) {<><\/?[^> if ( !details.result && hasOwn.call( details, "expected" ) ) {
3108 < 0 ) {<><\/?[^> if ( details.negative ) {
3109 < 0 ) {<><\/?[^> expected = "NOT " + QUnit.dump.parse( details.expected );
3110 < 0 ) {<><\/?[^> } else {
3111 < 0 ) {<><\/?[^> expected = QUnit.dump.parse( details.expected );
3112 < 0 ) {<><\/?[^> }
3113  
3114 < 0 ) {<><\/?[^> actual = QUnit.dump.parse( details.actual );
3115 < 0 ) {<><\/?[^> message += "<table><tr class='test-expected'><th>Expected: </th><td><pre>" +
3116 < 0 ) {<><\/?[^> escapeText( expected ) +
3117 < 0 ) {<><\/?[^> "</pre></td></tr>";
3118  
3119 < 0 ) {<><\/?[^> if ( actual !== expected ) {
3120  
3121 < 0 ) {<><\/?[^> message += "<tr class='test-actual'><th>Result: </th><td><pre>" +
3122 < 0 ) {<><\/?[^> escapeText( actual ) + "</pre></td></tr>";
3123  
3124 < 0 ) {<><\/?[^> // Don't show diff if actual or expected are booleans
3125 < 0 ) {<><\/?[^> if ( !( /^(true|false)$/.test( actual ) ) &&
3126 < 0 ) {<><\/?[^> !( /^(true|false)$/.test( expected ) ) ) {
3127 < 0 ) {<><\/?[^> diff = QUnit.diff( expected, actual );
3128 < 0 ) {<><\/?[^> showDiff = stripHtml( diff ).length !==
3129 < 0 ) {<><\/?[^> stripHtml( expected ).length +
3130 < 0 ) {<><\/?[^> stripHtml( actual ).length;
3131 < 0 ) {<><\/?[^> }
3132  
3133 < 0 ) {<><\/?[^> // Don't show diff if expected and actual are totally different
3134 < 0 ) {<><\/?[^> if ( showDiff ) {
3135 < 0 ) {<><\/?[^> message += "<tr class='test-diff'><th>Diff: </th><td><pre>" +
3136 < 0 ) {<><\/?[^> diff + "</pre></td></tr>";
3137 < 0 ) {<><\/?[^> }
3138 < 0 ) {<><\/?[^> } else if ( expected.indexOf( "[object Array]" ) !== -1 ||
3139 < 0 ) {<><\/?[^> expected.indexOf( "[object Object]" ) !== -1 ) {
3140 < 0 ) {<><\/?[^> message += "<tr class='test-message'><th>Message: </th><td>" +
3141 < 0 ) {<><\/?[^> "Diff suppressed as the depth of object is more than current max depth (" +
3142 < 0 ) {<><\/?[^> QUnit.config.maxDepth + ").<p>Hint: Use <code>QUnit.dump.maxDepth</code> to " +
3143 < 0 ) {<><\/?[^> " run with a higher max depth or <a href='" +
3144 < 0 ) {<><\/?[^> escapeText( setUrl( { maxDepth: -1 } ) ) + "'>" +
3145 < 0 ) {<><\/?[^> "Rerun</a> without max depth.</p></td></tr>";
3146 < 0 ) {<><\/?[^> } else {
3147 < 0 ) {<><\/?[^> message += "<tr class='test-message'><th>Message: </th><td>" +
3148 < 0 ) {<><\/?[^> "Diff suppressed as the expected and actual results have an equivalent" +
3149 < 0 ) {<><\/?[^> " serialization</td></tr>";
3150 < 0 ) {<><\/?[^> }
3151  
3152 < 0 ) {<><\/?[^> if ( details.source ) {
3153 < 0 ) {<><\/?[^> message += "<tr class='test-source'><th>Source: </th><td><pre>" +
3154 < 0 ) {<><\/?[^> escapeText( details.source ) + "</pre></td></tr>";
3155 < 0 ) {<><\/?[^> }
3156  
3157 < 0 ) {<><\/?[^> message += "</table>";
3158  
3159 < 0 ) {<><\/?[^> // This occurs when pushFailure is set and we have an extracted stack trace
3160 < 0 ) {<><\/?[^> } else if ( !details.result && details.source ) {
3161 < 0 ) {<><\/?[^> message += "<table>" +
3162 < 0 ) {<><\/?[^> "<tr class='test-source'><th>Source: </th><td><pre>" +
3163 < 0 ) {<><\/?[^> escapeText( details.source ) + "</pre></td></tr>" +
3164 < 0 ) {<><\/?[^> "</table>";
3165 < 0 ) {<><\/?[^> }
3166  
3167 < 0 ) {<><\/?[^> assertList = testItem.getElementsByTagName( "ol" )[ 0 ];
3168  
3169 < 0 ) {<><\/?[^> assertLi = document.createElement( "li" );
3170 < 0 ) {<><\/?[^> assertLi.className = details.result ? "pass" : "fail";
3171 < 0 ) {<><\/?[^> assertLi.innerHTML = message;
3172 < 0 ) {<><\/?[^> assertList.appendChild( assertLi );
3173 < 0 ) {<><\/?[^>} );
3174  
3175 < 0 ) {<><\/?[^>QUnit.testDone( function( details ) {
3176 < 0 ) {<><\/?[^> var testTitle, time, testItem, assertList,
3177 < 0 ) {<><\/?[^> good, bad, testCounts, skipped, sourceName,
3178 < 0 ) {<><\/?[^> tests = id( "qunit-tests" );
3179  
3180 < 0 ) {<><\/?[^> if ( !tests ) {
3181 < 0 ) {<><\/?[^> return;
3182 < 0 ) {<><\/?[^> }
3183  
3184 < 0 ) {<><\/?[^> testItem = id( "qunit-test-output-" + details.testId );
3185  
3186 < 0 ) {<><\/?[^> assertList = testItem.getElementsByTagName( "ol" )[ 0 ];
3187  
3188 < 0 ) {<><\/?[^> good = details.passed;
3189 < 0 ) {<><\/?[^> bad = details.failed;
3190  
3191 < 0 ) {<><\/?[^> // Store result when possible
3192 < 0 ) {<><\/?[^> if ( config.reorder && defined.sessionStorage ) {
3193 < 0 ) {<><\/?[^> if ( bad ) {
3194 < 0 ) {<><\/?[^> sessionStorage.setItem( "qunit-test-" + details.module + "-" + details.name, bad );
3195 < 0 ) {<><\/?[^> } else {
3196 < 0 ) {<><\/?[^> sessionStorage.removeItem( "qunit-test-" + details.module + "-" + details.name );
3197 < 0 ) {<><\/?[^> }
3198 < 0 ) {<><\/?[^> }
3199  
3200 < 0 ) {<><\/?[^> if ( bad === 0 ) {
3201  
3202 < 0 ) {<><\/?[^> // Collapse the passing tests
3203 < 0 ) {<><\/?[^> addClass( assertList, "qunit-collapsed" );
3204 < 0 ) {<><\/?[^> } else if ( bad && config.collapse && !collapseNext ) {
3205  
3206 < 0 ) {<><\/?[^> // Skip collapsing the first failing test
3207 < 0 ) {<><\/?[^> collapseNext = true;
3208 < 0 ) {<><\/?[^> } else {
3209  
3210 < 0 ) {<><\/?[^> // Collapse remaining tests
3211 < 0 ) {<><\/?[^> addClass( assertList, "qunit-collapsed" );
3212 < 0 ) {<><\/?[^> }
3213  
3214 < 0 ) {<><\/?[^> // The testItem.firstChild is the test name
3215 < 0 ) {<><\/?[^> testTitle = testItem.firstChild;
3216  
3217 < 0 ) {<><\/?[^> testCounts = bad ?
3218 < 0 ) {<><\/?[^> "<b class='failed'>" + bad + "</b>, " + "<b class='passed'>" + good + "</b>, " :
3219 < 0 ) {<><\/?[^> "";
3220  
3221 < 0 ) {<><\/?[^> testTitle.innerHTML += " <b class='counts'>(" + testCounts +
3222 < 0 ) {<><\/?[^> details.assertions.length + ")</b>";
3223  
3224 < 0 ) {<><\/?[^> if ( details.skipped ) {
3225 < 0 ) {<><\/?[^> testItem.className = "skipped";
3226 < 0 ) {<><\/?[^> skipped = document.createElement( "em" );
3227 < 0 ) {<><\/?[^> skipped.className = "qunit-skipped-label";
3228 < 0 ) {<><\/?[^> skipped.innerHTML = "skipped";
3229 < 0 ) {<><\/?[^> testItem.insertBefore( skipped, testTitle );
3230 < 0 ) {<><\/?[^> } else {
3231 < 0 ) {<><\/?[^> addEvent( testTitle, "click", function() {
3232 < 0 ) {<><\/?[^> toggleClass( assertList, "qunit-collapsed" );
3233 < 0 ) {<><\/?[^> } );
3234  
3235 < 0 ) {<><\/?[^> testItem.className = bad ? "fail" : "pass";
3236  
3237 < 0 ) {<><\/?[^> time = document.createElement( "span" );
3238 < 0 ) {<><\/?[^> time.className = "runtime";
3239 < 0 ) {<><\/?[^> time.innerHTML = details.runtime + " ms";
3240 < 0 ) {<><\/?[^> testItem.insertBefore( time, assertList );
3241 < 0 ) {<><\/?[^> }
3242  
3243 < 0 ) {<><\/?[^> // Show the source of the test when showing assertions
3244 < 0 ) {<><\/?[^> if ( details.source ) {
3245 < 0 ) {<><\/?[^> sourceName = document.createElement( "p" );
3246 < 0 ) {<><\/?[^> sourceName.innerHTML = "<strong>Source: </strong>" + details.source;
3247 < 0 ) {<><\/?[^> addClass( sourceName, "qunit-source" );
3248 < 0 ) {<><\/?[^> if ( bad === 0 ) {
3249 < 0 ) {<><\/?[^> addClass( sourceName, "qunit-collapsed" );
3250 < 0 ) {<><\/?[^> }
3251 < 0 ) {<><\/?[^> addEvent( testTitle, "click", function() {
3252 < 0 ) {<><\/?[^> toggleClass( sourceName, "qunit-collapsed" );
3253 < 0 ) {<><\/?[^> } );
3254 < 0 ) {<><\/?[^> testItem.appendChild( sourceName );
3255 < 0 ) {<><\/?[^> }
3256 < 0 ) {<><\/?[^>} );
3257  
3258 < 0 ) {<><\/?[^>// Avoid readyState issue with phantomjs
3259 < 0 ) {<><\/?[^>// Ref: #818
3260 < 0 ) {<><\/?[^>var notPhantom = ( function( p ) {
3261 < 0 ) {<><\/?[^> return !( p && p.version && p.version.major > 0 );
3262 < 0 ) {<><\/?[^>} )( window.phantom );
3263  
3264 < 0 ) {<><\/?[^>if ( notPhantom && document.readyState === "complete" ) {
3265 < 0 ) {<><\/?[^> QUnit.load();
3266 < 0 ) {<><\/?[^>} else {
3267 < 0 ) {<><\/?[^> addEvent( window, "load", QUnit.load );
3268 < 0 ) {<><\/?[^>}
3269  
3270 < 0 ) {<><\/?[^>/*
3271 < 0 ) {<><\/?[^> * This file is a modified version of google-diff-match-patch's JavaScript implementation
3272 < 0 ) {<><\/?[^> * (https://code.google.com/p/google-diff-match-patch/source/browse/trunk/javascript/diff_match_patch_uncompressed.js),
3273 < 0 ) {<><\/?[^> * modifications are licensed as more fully set forth in LICENSE.txt.
3274 < 0 ) {<><\/?[^> *
3275 < 0 ) {<><\/?[^> * The original source of google-diff-match-patch is attributable and licensed as follows:
3276 < 0 ) {<><\/?[^> *
3277 < 0 ) {<><\/?[^> * Copyright 2006 Google Inc.
3278 < 0 ) {<><\/?[^> * https://code.google.com/p/google-diff-match-patch/
3279 < 0 ) {<><\/?[^> *
3280 < 0 ) {<><\/?[^> * Licensed under the Apache License, Version 2.0 (the "License");
3281 < 0 ) {<><\/?[^> * you may not use this file except in compliance with the License.
3282 < 0 ) {<><\/?[^> * You may obtain a copy of the License at
3283 < 0 ) {<><\/?[^> *
3284 < 0 ) {<><\/?[^> * https://www.apache.org/licenses/LICENSE-2.0
3285 < 0 ) {<><\/?[^> *
3286 < 0 ) {<><\/?[^> * Unless required by applicable law or agreed to in writing, software
3287 < 0 ) {<><\/?[^> * distributed under the License is distributed on an "AS IS" BASIS,
3288 < 0 ) {<><\/?[^> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
3289 < 0 ) {<><\/?[^> * See the License for the specific language governing permissions and
3290 < 0 ) {<><\/?[^> * limitations under the License.
3291 < 0 ) {<><\/?[^> *
3292 < 0 ) {<><\/?[^> * More Info:
3293 < 0 ) {<><\/?[^> * https://code.google.com/p/google-diff-match-patch/
3294 < 0 ) {<><\/?[^> *
3295 < 0 ) {<><\/?[^> * Usage: QUnit.diff(expected, actual)
3296 < 0 ) {<><\/?[^> *
3297 < 0 ) {<><\/?[^> */
3298 < 0 ) {<><\/?[^>QUnit.diff = ( function() {
3299 < 0 ) {<><\/?[^> function DiffMatchPatch() {
3300 < 0 ) {<><\/?[^> }
3301  
3302 < 0 ) {<><\/?[^> // DIFF FUNCTIONS
3303  
3304 < 0 ) {<><\/?[^> /**
3305 < 0 ) {<><\/?[^> * The data structure representing a diff is an array of tuples:
3306 < 0 ) {<><\/?[^> * [[DIFF_DELETE, 'Hello'], [DIFF_INSERT, 'Goodbye'], [DIFF_EQUAL, ' world.']]
3307 < 0 ) {<><\/?[^> * which means: delete 'Hello', add 'Goodbye' and keep ' world.'
3308 < 0 ) {<><\/?[^> */
3309 < 0 ) {<><\/?[^> var DIFF_DELETE = -1,
3310 < 0 ) {<><\/?[^> DIFF_INSERT = 1,
3311 < 0 ) {<><\/?[^> DIFF_EQUAL = 0;
3312  
3313 < 0 ) {<><\/?[^> /**
3314 < 0 ) {<><\/?[^> * Find the differences between two texts. Simplifies the problem by stripping
3315 < 0 ) {<><\/?[^> * any common prefix or suffix off the texts before diffing.
3316 < 0 ) {<><\/?[^> * @param {string} text1 Old string to be diffed.
3317 < 0 ) {<><\/?[^> * @param {string} text2 New string to be diffed.
3318 < 0 ) {<><\/?[^> * @param {boolean=} optChecklines Optional speedup flag. If present and false,
3319 < 0 ) {<><\/?[^> * then don't run a line-level diff first to identify the changed areas.
3320 < 0 ) {<><\/?[^> * Defaults to true, which does a faster, slightly less optimal diff.
3321 < 0 ) {<><\/?[^> * @return {!Array.<!DiffMatchPatch.Diff>} Array of diff tuples.
3322 < 0 ) {<><\/?[^> */
3323 < 0 ) {<><\/?[^> DiffMatchPatch.prototype.DiffMain = function( text1, text2, optChecklines ) {
3324 < 0 ) {<><\/?[^> var deadline, checklines, commonlength,
3325 < 0 ) {<><\/?[^> commonprefix, commonsuffix, diffs;
3326  
3327 < 0 ) {<><\/?[^> // The diff must be complete in up to 1 second.
3328 < 0 ) {<><\/?[^> deadline = ( new Date() ).getTime() + 1000;
3329  
3330 < 0 ) {<><\/?[^> // Check for null inputs.
3331 < 0 ) {<><\/?[^> if ( text1 === null || text2 === null ) {
3332 < 0 ) {<><\/?[^> throw new Error( "Null input. (DiffMain)" );
3333 < 0 ) {<><\/?[^> }
3334  
3335 < 0 ) {<><\/?[^> // Check for equality (speedup).
3336 < 0 ) {<><\/?[^> if ( text1 === text2 ) {
3337 < 0 ) {<><\/?[^> if ( text1 ) {
3338 < 0 ) {<><\/?[^> return [
3339 < 0 ) {<><\/?[^> [ DIFF_EQUAL, text1 ]
3340 < 0 ) {<><\/?[^> ];
3341 < 0 ) {<><\/?[^> }
3342 < 0 ) {<><\/?[^> return [];
3343 < 0 ) {<><\/?[^> }
3344  
3345 < 0 ) {<><\/?[^> if ( typeof optChecklines === "undefined" ) {
3346 < 0 ) {<><\/?[^> optChecklines = true;
3347 < 0 ) {<><\/?[^> }
3348  
3349 < 0 ) {<><\/?[^> checklines = optChecklines;
3350  
3351 < 0 ) {<><\/?[^> // Trim off common prefix (speedup).
3352 < 0 ) {<><\/?[^> commonlength = this.diffCommonPrefix( text1, text2 );
3353 < 0 ) {<><\/?[^> commonprefix = text1.substring( 0, commonlength );
3354 < 0 ) {<><\/?[^> text1 = text1.substring( commonlength );
3355 < 0 ) {<><\/?[^> text2 = text2.substring( commonlength );
3356  
3357 < 0 ) {<><\/?[^> // Trim off common suffix (speedup).
3358 < 0 ) {<><\/?[^> commonlength = this.diffCommonSuffix( text1, text2 );
3359 < 0 ) {<><\/?[^> commonsuffix = text1.substring( text1.length - commonlength );
3360 < 0 ) {<><\/?[^> text1 = text1.substring( 0, text1.length - commonlength );
3361 < 0 ) {<><\/?[^> text2 = text2.substring( 0, text2.length - commonlength );
3362  
3363 < 0 ) {<><\/?[^> // Compute the diff on the middle block.
3364 < 0 ) {<><\/?[^> diffs = this.diffCompute( text1, text2, checklines, deadline );
3365  
3366 < 0 ) {<><\/?[^> // Restore the prefix and suffix.
3367 < 0 ) {<><\/?[^> if ( commonprefix ) {
3368 < 0 ) {<><\/?[^> diffs.unshift( [ DIFF_EQUAL, commonprefix ] );
3369 < 0 ) {<><\/?[^> }
3370 < 0 ) {<><\/?[^> if ( commonsuffix ) {
3371 < 0 ) {<><\/?[^> diffs.push( [ DIFF_EQUAL, commonsuffix ] );
3372 < 0 ) {<><\/?[^> }
3373 < 0 ) {<><\/?[^> this.diffCleanupMerge( diffs );
3374 < 0 ) {<><\/?[^> return diffs;
3375 < 0 ) {<><\/?[^> };
3376  
3377 < 0 ) {<><\/?[^> /**
3378 < 0 ) {<><\/?[^> * Reduce the number of edits by eliminating operationally trivial equalities.
3379 < 0 ) {<><\/?[^> * @param {!Array.<!DiffMatchPatch.Diff>} diffs Array of diff tuples.
3380 < 0 ) {<><\/?[^> */
3381 < 0 ) {<><\/?[^> DiffMatchPatch.prototype.diffCleanupEfficiency = function( diffs ) {
3382 < 0 ) {<><\/?[^> var changes, equalities, equalitiesLength, lastequality,
3383 < 0 ) {<><\/?[^> pointer, preIns, preDel, postIns, postDel;
3384 < 0 ) {<><\/?[^> changes = false;
3385 < 0 ) {<><\/?[^> equalities = []; // Stack of indices where equalities are found.
3386 < 0 ) {<><\/?[^> equalitiesLength = 0; // Keeping our own length var is faster in JS.
3387 < 0 ) {<><\/?[^> /** @type {?string} */
3388 < 0 ) {<><\/?[^> lastequality = null;
3389  
3390 < 0 ) {<><\/?[^> // Always equal to diffs[equalities[equalitiesLength - 1]][1]
3391 < 0 ) {<><\/?[^> pointer = 0; // Index of current position.
3392  
3393 < 0 ) {<><\/?[^> // Is there an insertion operation before the last equality.
3394 < 0 ) {<><\/?[^> preIns = false;
3395  
3396 < 0 ) {<><\/?[^> // Is there a deletion operation before the last equality.
3397 < 0 ) {<><\/?[^> preDel = false;
3398  
3399 < 0 ) {<><\/?[^> // Is there an insertion operation after the last equality.
3400 < 0 ) {<><\/?[^> postIns = false;
3401  
3402 < 0 ) {<><\/?[^> // Is there a deletion operation after the last equality.
3403 < 0 ) {<><\/?[^> postDel = false;
3404 < 0 ) {<><\/?[^> while ( pointer < diffs.length ) {
3405  
3406 < 0 ) {<><\/?[^> // Equality found.
3407 < 0 ) {<><\/?[^> if ( diffs[ pointer ][ 0 ] === DIFF_EQUAL ) {
3408 < 0 ) {<><\/?[^> if ( diffs[ pointer ][ 1 ].length < 4 && ( postIns || postDel ) ) {
3409  
3410 < 0 ) {<><\/?[^> // Candidate found.
3411 < 0 ) {<><\/?[^> equalities[ equalitiesLength++ ] = pointer;
3412 < 0 ) {<><\/?[^> preIns = postIns;
3413 < 0 ) {<><\/?[^> preDel = postDel;
3414 < 0 ) {<><\/?[^> lastequality = diffs[ pointer ][ 1 ];
3415 < 0 ) {<><\/?[^> } else {
3416  
3417 < 0 ) {<><\/?[^> // Not a candidate, and can never become one.
3418 < 0 ) {<><\/?[^> equalitiesLength = 0;
3419 < 0 ) {<><\/?[^> lastequality = null;
3420 < 0 ) {<><\/?[^> }
3421 < 0 ) {<><\/?[^> postIns = postDel = false;
3422  
3423 < 0 ) {<><\/?[^> // An insertion or deletion.
3424 < 0 ) {<><\/?[^> } else {
3425  
3426 < 0 ) {<><\/?[^> if ( diffs[ pointer ][ 0 ] === DIFF_DELETE ) {
3427 < 0 ) {<><\/?[^> postDel = true;
3428 < 0 ) {<><\/?[^> } else {
3429 < 0 ) {<><\/?[^> postIns = true;
3430 < 0 ) {<><\/?[^> }
3431  
3432 < 0 ) {<><\/?[^> /*
3433 < 0 ) {<><\/?[^> * Five types to be split:
3434 < 0 ) {<><\/?[^> * <ins>A</ins><del>B</del>XY<ins>C</ins><del>D</del>
3435 < 0 ) {<><\/?[^> * <ins>A</ins>X<ins>C</ins><del>D</del>
3436 < 0 ) {<><\/?[^> * <ins>A</ins><del>B</del>X<ins>C</ins>
3437 < 0 ) {<><\/?[^> * <ins>A</del>X<ins>C</ins><del>D</del>
3438 < 0 ) {<><\/?[^> * <ins>A</ins><del>B</del>X<del>C</del>
3439 < 0 ) {<><\/?[^> */
3440 < 0 ) {<><\/?[^> if ( lastequality && ( ( preIns && preDel && postIns && postDel ) ||
3441 < 0 ) {<><\/?[^> ( ( lastequality.length < 2 ) &&
3442 < 0 ) {<><\/?[^> ( preIns + preDel + postIns + postDel ) === 3 ) ) ) {
3443  
3444 < 0 ) {<><\/?[^> // Duplicate record.
3445 < 0 ) {<><\/?[^> diffs.splice(
3446 < 0 ) {<><\/?[^> equalities[ equalitiesLength - 1 ],
3447 < 0 ) {<><\/?[^> 0,
3448 < 0 ) {<><\/?[^> [ DIFF_DELETE, lastequality ]
3449 < 0 ) {<><\/?[^> );
3450  
3451 < 0 ) {<><\/?[^> // Change second copy to insert.
3452 < 0 ) {<><\/?[^> diffs[ equalities[ equalitiesLength - 1 ] + 1 ][ 0 ] = DIFF_INSERT;
3453 < 0 ) {<><\/?[^> equalitiesLength--; // Throw away the equality we just deleted;
3454 < 0 ) {<><\/?[^> lastequality = null;
3455 < 0 ) {<><\/?[^> if ( preIns && preDel ) {
3456  
3457 < 0 ) {<><\/?[^> // No changes made which could affect previous entry, keep going.
3458 < 0 ) {<><\/?[^> postIns = postDel = true;
3459 < 0 ) {<><\/?[^> equalitiesLength = 0;
3460 < 0 ) {<><\/?[^> } else {
3461 < 0 ) {<><\/?[^> equalitiesLength--; // Throw away the previous equality.
3462 < 0 ) {<><\/?[^> pointer = equalitiesLength > 0 ? equalities[ equalitiesLength - 1 ] : -1;
3463 < 0 ) {<><\/?[^> postIns = postDel = false;
3464 < 0 ) {<><\/?[^> }
3465 < 0 ) {<><\/?[^> changes = true;
3466 < 0 ) {<><\/?[^> }
3467 < 0 ) {<><\/?[^> }
3468 < 0 ) {<><\/?[^> pointer++;
3469 < 0 ) {<><\/?[^> }
3470  
3471 < 0 ) {<><\/?[^> if ( changes ) {
3472 < 0 ) {<><\/?[^> this.diffCleanupMerge( diffs );
3473 < 0 ) {<><\/?[^> }
3474 < 0 ) {<><\/?[^> };
3475  
3476 < 0 ) {<><\/?[^> /**
3477 < 0 ) {<><\/?[^> * Convert a diff array into a pretty HTML report.
3478 < 0 ) {<><\/?[^> * @param {!Array.<!DiffMatchPatch.Diff>} diffs Array of diff tuples.
3479 < 0 ) {<><\/?[^> * @param {integer} string to be beautified.
3480 < 0 ) {<><\/?[^> * @return {string} HTML representation.
3481 < 0 ) {<><\/?[^> */
3482 < 0 ) {<><\/?[^> DiffMatchPatch.prototype.diffPrettyHtml = function( diffs ) {
3483 < 0 ) {<><\/?[^> var op, data, x,
3484 < 0 ) {<><\/?[^> html = [];
3485 < 0 ) {<><\/?[^> for ( x = 0; x < diffs.length; x++ ) {
3486 < 0 ) {<><\/?[^> op = diffs[ x ][ 0 ]; // Operation (insert, delete, equal)
3487 < 0 ) {<><\/?[^> data = diffs[ x ][ 1 ]; // Text of change.
3488 < 0 ) {<><\/?[^> switch ( op ) {
3489 < 0 ) {<><\/?[^> case DIFF_INSERT:
3490 < 0 ) {<><\/?[^> html[ x ] = "<ins>" + escapeText( data ) + "</ins>";
3491 < 0 ) {<><\/?[^> break;
3492 < 0 ) {<><\/?[^> case DIFF_DELETE:
3493 < 0 ) {<><\/?[^> html[ x ] = "<del>" + escapeText( data ) + "</del>";
3494 < 0 ) {<><\/?[^> break;
3495 < 0 ) {<><\/?[^> case DIFF_EQUAL:
3496 < 0 ) {<><\/?[^> html[ x ] = "<span>" + escapeText( data ) + "</span>";
3497 < 0 ) {<><\/?[^> break;
3498 < 0 ) {<><\/?[^> }
3499 < 0 ) {<><\/?[^> }
3500 < 0 ) {<><\/?[^> return html.join( "" );
3501 < 0 ) {<><\/?[^> };
3502  
3503 < 0 ) {<><\/?[^> /**
3504 < 0 ) {<><\/?[^> * Determine the common prefix of two strings.
3505 < 0 ) {<><\/?[^> * @param {string} text1 First string.
3506 < 0 ) {<><\/?[^> * @param {string} text2 Second string.
3507 < 0 ) {<><\/?[^> * @return {number} The number of characters common to the start of each
3508 < 0 ) {<><\/?[^> * string.
3509 < 0 ) {<><\/?[^> */
3510 < 0 ) {<><\/?[^> DiffMatchPatch.prototype.diffCommonPrefix = function( text1, text2 ) {
3511 < 0 ) {<><\/?[^> var pointermid, pointermax, pointermin, pointerstart;
3512  
3513 < 0 ) {<><\/?[^> // Quick check for common null cases.
3514 < 0 ) {<><\/?[^> if ( !text1 || !text2 || text1.charAt( 0 ) !== text2.charAt( 0 ) ) {
3515 < 0 ) {<><\/?[^> return 0;
3516 < 0 ) {<><\/?[^> }
3517  
3518 < 0 ) {<><\/?[^> // Binary search.
3519 < 0 ) {<><\/?[^> // Performance analysis: https://neil.fraser.name/news/2007/10/09/
3520 < 0 ) {<><\/?[^> pointermin = 0;
3521 < 0 ) {<><\/?[^> pointermax = Math.min( text1.length, text2.length );
3522 < 0 ) {<><\/?[^> pointermid = pointermax;
3523 < 0 ) {<><\/?[^> pointerstart = 0;
3524 < 0 ) {<><\/?[^> while ( pointermin < pointermid ) {
3525 < 0 ) {<><\/?[^> if ( text1.substring( pointerstart, pointermid ) ===
3526 < 0 ) {<><\/?[^> text2.substring( pointerstart, pointermid ) ) {
3527 < 0 ) {<><\/?[^> pointermin = pointermid;
3528 < 0 ) {<><\/?[^> pointerstart = pointermin;
3529 < 0 ) {<><\/?[^> } else {
3530 < 0 ) {<><\/?[^> pointermax = pointermid;
3531 < 0 ) {<><\/?[^> }
3532 < 0 ) {<><\/?[^> pointermid = Math.floor( ( pointermax - pointermin ) / 2 + pointermin );
3533 < 0 ) {<><\/?[^> }
3534 < 0 ) {<><\/?[^> return pointermid;
3535 < 0 ) {<><\/?[^> };
3536  
3537 < 0 ) {<><\/?[^> /**
3538 < 0 ) {<><\/?[^> * Determine the common suffix of two strings.
3539 < 0 ) {<><\/?[^> * @param {string} text1 First string.
3540 < 0 ) {<><\/?[^> * @param {string} text2 Second string.
3541 < 0 ) {<><\/?[^> * @return {number} The number of characters common to the end of each string.
3542 < 0 ) {<><\/?[^> */
3543 < 0 ) {<><\/?[^> DiffMatchPatch.prototype.diffCommonSuffix = function( text1, text2 ) {
3544 < 0 ) {<><\/?[^> var pointermid, pointermax, pointermin, pointerend;
3545  
3546 < 0 ) {<><\/?[^> // Quick check for common null cases.
3547 < 0 ) {<><\/?[^> if ( !text1 ||
3548 < 0 ) {<><\/?[^> !text2 ||
3549 < 0 ) {<><\/?[^> text1.charAt( text1.length - 1 ) !== text2.charAt( text2.length - 1 ) ) {
3550 < 0 ) {<><\/?[^> return 0;
3551 < 0 ) {<><\/?[^> }
3552  
3553 < 0 ) {<><\/?[^> // Binary search.
3554 < 0 ) {<><\/?[^> // Performance analysis: https://neil.fraser.name/news/2007/10/09/
3555 < 0 ) {<><\/?[^> pointermin = 0;
3556 < 0 ) {<><\/?[^> pointermax = Math.min( text1.length, text2.length );
3557 < 0 ) {<><\/?[^> pointermid = pointermax;
3558 < 0 ) {<><\/?[^> pointerend = 0;
3559 < 0 ) {<><\/?[^> while ( pointermin < pointermid ) {
3560 < 0 ) {<><\/?[^> if ( text1.substring( text1.length - pointermid, text1.length - pointerend ) ===
3561 < 0 ) {<><\/?[^> text2.substring( text2.length - pointermid, text2.length - pointerend ) ) {
3562 < 0 ) {<><\/?[^> pointermin = pointermid;
3563 < 0 ) {<><\/?[^> pointerend = pointermin;
3564 < 0 ) {<><\/?[^> } else {
3565 < 0 ) {<><\/?[^> pointermax = pointermid;
3566 < 0 ) {<><\/?[^> }
3567 < 0 ) {<><\/?[^> pointermid = Math.floor( ( pointermax - pointermin ) / 2 + pointermin );
3568 < 0 ) {<><\/?[^> }
3569 < 0 ) {<><\/?[^> return pointermid;
3570 < 0 ) {<><\/?[^> };
3571  
3572 < 0 ) {<><\/?[^> /**
3573 < 0 ) {<><\/?[^> * Find the differences between two texts. Assumes that the texts do not
3574 < 0 ) {<><\/?[^> * have any common prefix or suffix.
3575 < 0 ) {<><\/?[^> * @param {string} text1 Old string to be diffed.
3576 < 0 ) {<><\/?[^> * @param {string} text2 New string to be diffed.
3577 < 0 ) {<><\/?[^> * @param {boolean} checklines Speedup flag. If false, then don't run a
3578 < 0 ) {<><\/?[^> * line-level diff first to identify the changed areas.
3579 < 0 ) {<><\/?[^> * If true, then run a faster, slightly less optimal diff.
3580 < 0 ) {<><\/?[^> * @param {number} deadline Time when the diff should be complete by.
3581 < 0 ) {<><\/?[^> * @return {!Array.<!DiffMatchPatch.Diff>} Array of diff tuples.
3582 < 0 ) {<><\/?[^> * @private
3583 < 0 ) {<><\/?[^> */
3584 < 0 ) {<><\/?[^> DiffMatchPatch.prototype.diffCompute = function( text1, text2, checklines, deadline ) {
3585 < 0 ) {<><\/?[^> var diffs, longtext, shorttext, i, hm,
3586 < 0 ) {<><\/?[^> text1A, text2A, text1B, text2B,
3587 < 0 ) {<><\/?[^> midCommon, diffsA, diffsB;
3588  
3589 < 0 ) {<><\/?[^> if ( !text1 ) {
3590  
3591 < 0 ) {<><\/?[^> // Just add some text (speedup).
3592 < 0 ) {<><\/?[^> return [
3593 < 0 ) {<><\/?[^> [ DIFF_INSERT, text2 ]
3594 < 0 ) {<><\/?[^> ];
3595 < 0 ) {<><\/?[^> }
3596  
3597 < 0 ) {<><\/?[^> if ( !text2 ) {
3598  
3599 < 0 ) {<><\/?[^> // Just delete some text (speedup).
3600 < 0 ) {<><\/?[^> return [
3601 < 0 ) {<><\/?[^> [ DIFF_DELETE, text1 ]
3602 < 0 ) {<><\/?[^> ];
3603 < 0 ) {<><\/?[^> }
3604  
3605 < 0 ) {<><\/?[^> longtext = text1.length > text2.length ? text1 : text2;
3606 < 0 ) {<><\/?[^> shorttext = text1.length > text2.length ? text2 : text1;
3607 < 0 ) {<><\/?[^> i = longtext.indexOf( shorttext );
3608 < 0 ) {<><\/?[^> if ( i !== -1 ) {
3609  
3610 < 0 ) {<><\/?[^> // Shorter text is inside the longer text (speedup).
3611 < 0 ) {<><\/?[^> diffs = [
3612 < 0 ) {<><\/?[^> [ DIFF_INSERT, longtext.substring( 0, i ) ],
3613 < 0 ) {<><\/?[^> [ DIFF_EQUAL, shorttext ],
3614 < 0 ) {<><\/?[^> [ DIFF_INSERT, longtext.substring( i + shorttext.length ) ]
3615 < 0 ) {<><\/?[^> ];
3616  
3617 < 0 ) {<><\/?[^> // Swap insertions for deletions if diff is reversed.
3618 < 0 ) {<><\/?[^> if ( text1.length > text2.length ) {
3619 < 0 ) {<><\/?[^> diffs[ 0 ][ 0 ] = diffs[ 2 ][ 0 ] = DIFF_DELETE;
3620 < 0 ) {<><\/?[^> }
3621 < 0 ) {<><\/?[^> return diffs;
3622 < 0 ) {<><\/?[^> }
3623  
3624 < 0 ) {<><\/?[^> if ( shorttext.length === 1 ) {
3625  
3626 < 0 ) {<><\/?[^> // Single character string.
3627 < 0 ) {<><\/?[^> // After the previous speedup, the character can't be an equality.
3628 < 0 ) {<><\/?[^> return [
3629 < 0 ) {<><\/?[^> [ DIFF_DELETE, text1 ],
3630 < 0 ) {<><\/?[^> [ DIFF_INSERT, text2 ]
3631 < 0 ) {<><\/?[^> ];
3632 < 0 ) {<><\/?[^> }
3633  
3634 < 0 ) {<><\/?[^> // Check to see if the problem can be split in two.
3635 < 0 ) {<><\/?[^> hm = this.diffHalfMatch( text1, text2 );
3636 < 0 ) {<><\/?[^> if ( hm ) {
3637  
3638 < 0 ) {<><\/?[^> // A half-match was found, sort out the return data.
3639 < 0 ) {<><\/?[^> text1A = hm[ 0 ];
3640 < 0 ) {<><\/?[^> text1B = hm[ 1 ];
3641 < 0 ) {<><\/?[^> text2A = hm[ 2 ];
3642 < 0 ) {<><\/?[^> text2B = hm[ 3 ];
3643 < 0 ) {<><\/?[^> midCommon = hm[ 4 ];
3644  
3645 < 0 ) {<><\/?[^> // Send both pairs off for separate processing.
3646 < 0 ) {<><\/?[^> diffsA = this.DiffMain( text1A, text2A, checklines, deadline );
3647 < 0 ) {<><\/?[^> diffsB = this.DiffMain( text1B, text2B, checklines, deadline );
3648  
3649 < 0 ) {<><\/?[^> // Merge the results.
3650 < 0 ) {<><\/?[^> return diffsA.concat( [
3651 < 0 ) {<><\/?[^> [ DIFF_EQUAL, midCommon ]
3652 < 0 ) {<><\/?[^> ], diffsB );
3653 < 0 ) {<><\/?[^> }
3654  
3655 < 0 ) {<><\/?[^> if ( checklines && text1.length > 100 && text2.length > 100 ) {
3656 < 0 ) {<><\/?[^> return this.diffLineMode( text1, text2, deadline );
3657 < 0 ) {<><\/?[^> }
3658  
3659 < 0 ) {<><\/?[^> return this.diffBisect( text1, text2, deadline );
3660 < 0 ) {<><\/?[^> };
3661  
3662 < 0 ) {<><\/?[^> /**
3663 < 0 ) {<><\/?[^> * Do the two texts share a substring which is at least half the length of the
3664 < 0 ) {<><\/?[^> * longer text?
3665 < 0 ) {<><\/?[^> * This speedup can produce non-minimal diffs.
3666 < 0 ) {<><\/?[^> * @param {string} text1 First string.
3667 < 0 ) {<><\/?[^> * @param {string} text2 Second string.
3668 < 0 ) {<><\/?[^> * @return {Array.<string>} Five element Array, containing the prefix of
3669 < 0 ) {<><\/?[^> * text1, the suffix of text1, the prefix of text2, the suffix of
3670 < 0 ) {<><\/?[^> * text2 and the common middle. Or null if there was no match.
3671 < 0 ) {<><\/?[^> * @private
3672 < 0 ) {<><\/?[^> */
3673 < 0 ) {<><\/?[^> DiffMatchPatch.prototype.diffHalfMatch = function( text1, text2 ) {
3674 < 0 ) {<><\/?[^> var longtext, shorttext, dmp,
3675 < 0 ) {<><\/?[^> text1A, text2B, text2A, text1B, midCommon,
3676 < 0 ) {<><\/?[^> hm1, hm2, hm;
3677  
3678 < 0 ) {<><\/?[^> longtext = text1.length > text2.length ? text1 : text2;
3679 < 0 ) {<><\/?[^> shorttext = text1.length > text2.length ? text2 : text1;
3680 < 0 ) {<><\/?[^> if ( longtext.length < 4 || shorttext.length * 2 < longtext.length ) {
3681 < 0 ) {<><\/?[^> return null; // Pointless.
3682 < 0 ) {<><\/?[^> }
3683 < 0 ) {<><\/?[^> dmp = this; // 'this' becomes 'window' in a closure.
3684  
3685 < 0 ) {<><\/?[^> /**
3686 < 0 ) {<><\/?[^> * Does a substring of shorttext exist within longtext such that the substring
3687 < 0 ) {<><\/?[^> * is at least half the length of longtext?
3688 < 0 ) {<><\/?[^> * Closure, but does not reference any external variables.
3689 < 0 ) {<><\/?[^> * @param {string} longtext Longer string.
3690 < 0 ) {<><\/?[^> * @param {string} shorttext Shorter string.
3691 < 0 ) {<><\/?[^> * @param {number} i Start index of quarter length substring within longtext.
3692 < 0 ) {<><\/?[^> * @return {Array.<string>} Five element Array, containing the prefix of
3693 < 0 ) {<><\/?[^> * longtext, the suffix of longtext, the prefix of shorttext, the suffix
3694 < 0 ) {<><\/?[^> * of shorttext and the common middle. Or null if there was no match.
3695 < 0 ) {<><\/?[^> * @private
3696 < 0 ) {<><\/?[^> */
3697 < 0 ) {<><\/?[^> function diffHalfMatchI( longtext, shorttext, i ) {
3698 < 0 ) {<><\/?[^> var seed, j, bestCommon, prefixLength, suffixLength,
3699 < 0 ) {<><\/?[^> bestLongtextA, bestLongtextB, bestShorttextA, bestShorttextB;
3700  
3701 < 0 ) {<><\/?[^> // Start with a 1/4 length substring at position i as a seed.
3702 < 0 ) {<><\/?[^> seed = longtext.substring( i, i + Math.floor( longtext.length / 4 ) );
3703 < 0 ) {<><\/?[^> j = -1;
3704 < 0 ) {<><\/?[^> bestCommon = "";
3705 < 0 ) {<><\/?[^> while ( ( j = shorttext.indexOf( seed, j + 1 ) ) !== -1 ) {
3706 < 0 ) {<><\/?[^> prefixLength = dmp.diffCommonPrefix( longtext.substring( i ),
3707 < 0 ) {<><\/?[^> shorttext.substring( j ) );
3708 < 0 ) {<><\/?[^> suffixLength = dmp.diffCommonSuffix( longtext.substring( 0, i ),
3709 < 0 ) {<><\/?[^> shorttext.substring( 0, j ) );
3710 < 0 ) {<><\/?[^> if ( bestCommon.length < suffixLength + prefixLength ) {
3711 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { bestCommon = shorttext.substring( j - suffixLength, j ) +
3712 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { shorttext.substring( j, j + prefixLength );
3713 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { bestLongtextA = longtext.substring( 0, i - suffixLength );
3714 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { bestLongtextB = longtext.substring( i + prefixLength );
3715 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { bestShorttextA = shorttext.substring( 0, j - suffixLength );
3716 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { bestShorttextB = shorttext.substring( j + prefixLength );
3717 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { }
3718 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { }
3719 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { if ( bestCommon.length * 2 >= longtext.length ) {
3720 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { return [ bestLongtextA, bestLongtextB,
3721 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { bestShorttextA, bestShorttextB, bestCommon
3722 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { ];
3723 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { } else {
3724 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { return null;
3725 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { }
3726 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { }
3727  
3728 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { // First check if the second quarter is the seed for a half-match.
3729 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { hm1 = diffHalfMatchI( longtext, shorttext,
3730 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { Math.ceil( longtext.length / 4 ) );
3731  
3732 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { // Check again based on the third quarter.
3733 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { hm2 = diffHalfMatchI( longtext, shorttext,
3734 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { Math.ceil( longtext.length / 2 ) );
3735 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { if ( !hm1 && !hm2 ) {
3736 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { return null;
3737 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { } else if ( !hm2 ) {
3738 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { hm = hm1;
3739 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { } else if ( !hm1 ) {
3740 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { hm = hm2;
3741 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { } else {
3742  
3743 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { // Both matched. Select the longest.
3744 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { hm = hm1[ 4 ].length > hm2[ 4 ].length ? hm1 : hm2;
3745 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { }
3746  
3747 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { // A half-match was found, sort out the return data.
3748 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { text1A, text1B, text2A, text2B;
3749 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { if ( text1.length > text2.length ) {
3750 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { text1A = hm[ 0 ];
3751 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { text1B = hm[ 1 ];
3752 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { text2A = hm[ 2 ];
3753 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { text2B = hm[ 3 ];
3754 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { } else {
3755 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { text2A = hm[ 0 ];
3756 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { text2B = hm[ 1 ];
3757 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { text1A = hm[ 2 ];
3758 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { text1B = hm[ 3 ];
3759 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { }
3760 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { midCommon = hm[ 4 ];
3761 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { return [ text1A, text1B, text2A, text2B, midCommon ];
3762 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { };
3763  
3764 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { /**
3765 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { * Do a quick line-level diff on both strings, then rediff the parts for
3766 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { * greater accuracy.
3767 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { * This speedup can produce non-minimal diffs.
3768 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { * @param {string} text1 Old string to be diffed.
3769 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { * @param {string} text2 New string to be diffed.
3770 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { * @param {number} deadline Time when the diff should be complete by.
3771 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { * @return {!Array.<!DiffMatchPatch.Diff>} Array of diff tuples.
3772 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { * @private
3773 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { */
3774 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { DiffMatchPatch.prototype.diffLineMode = function( text1, text2, deadline ) {
3775 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { var a, diffs, linearray, pointer, countInsert,
3776 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { countDelete, textInsert, textDelete, j;
3777  
3778 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { // Scan the text on a line-by-line basis first.
3779 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { a = this.diffLinesToChars( text1, text2 );
3780 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { text1 = a.chars1;
3781 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { text2 = a.chars2;
3782 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { linearray = a.lineArray;
3783  
3784 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { diffs = this.DiffMain( text1, text2, false, deadline );
3785  
3786 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { // Convert the diff back to original text.
3787 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { this.diffCharsToLines( diffs, linearray );
3788  
3789 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { // Eliminate freak matches (e.g. blank lines)
3790 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { this.diffCleanupSemantic( diffs );
3791  
3792 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { // Rediff any replacement blocks, this time character-by-character.
3793 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { // Add a dummy entry at the end.
3794 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { diffs.push( [ DIFF_EQUAL, "" ] );
3795 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { pointer = 0;
3796 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { countDelete = 0;
3797 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { countInsert = 0;
3798 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { textDelete = "";
3799 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { textInsert = "";
3800 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) { while ( pointer < diffs.length ) {
3801 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { switch ( diffs[ pointer ][ 0 ] ) {
3802 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { case DIFF_INSERT:
3803 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { countInsert++;
3804 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { textInsert += diffs[ pointer ][ 1 ];
3805 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { break;
3806 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { case DIFF_DELETE:
3807 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { countDelete++;
3808 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { textDelete += diffs[ pointer ][ 1 ];
3809 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { break;
3810 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { case DIFF_EQUAL:
3811  
3812 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Upon reaching an equality, check for prior redundancies.
3813 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { if ( countDelete >= 1 && countInsert >= 1 ) {
3814  
3815 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Delete the offending records and add the merged ones.
3816 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { diffs.splice( pointer - countDelete - countInsert,
3817 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { countDelete + countInsert );
3818 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { pointer = pointer - countDelete - countInsert;
3819 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { a = this.DiffMain( textDelete, textInsert, false, deadline );
3820 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { for ( j = a.length - 1; j >= 0; j-- ) {
3821 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { diffs.splice( pointer, 0, a[ j ] );
3822 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
3823 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { pointer = pointer + a.length;
3824 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
3825 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { countInsert = 0;
3826 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { countDelete = 0;
3827 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { textDelete = "";
3828 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { textInsert = "";
3829 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { break;
3830 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
3831 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { pointer++;
3832 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
3833 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { diffs.pop(); // Remove the dummy entry at the end.
3834  
3835 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { return diffs;
3836 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { };
3837  
3838 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { /**
3839 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * Find the 'middle snake' of a diff, split the problem in two
3840 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * and return the recursively constructed diff.
3841 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * See Myers 1986 paper: An O(ND) Difference Algorithm and Its Variations.
3842 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * @param {string} text1 Old string to be diffed.
3843 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * @param {string} text2 New string to be diffed.
3844 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * @param {number} deadline Time at which to bail if not yet complete.
3845 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * @return {!Array.<!DiffMatchPatch.Diff>} Array of diff tuples.
3846 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * @private
3847 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { */
3848 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { DiffMatchPatch.prototype.diffBisect = function( text1, text2, deadline ) {
3849 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { var text1Length, text2Length, maxD, vOffset, vLength,
3850 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { v1, v2, x, delta, front, k1start, k1end, k2start,
3851 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { k2end, k2Offset, k1Offset, x1, x2, y1, y2, d, k1, k2;
3852  
3853 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Cache the text lengths to prevent multiple calls.
3854 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { text1Length = text1.length;
3855 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { text2Length = text2.length;
3856 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { maxD = Math.ceil( ( text1Length + text2Length ) / 2 );
3857 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { vOffset = maxD;
3858 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { vLength = 2 * maxD;
3859 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { v1 = new Array( vLength );
3860 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { v2 = new Array( vLength );
3861  
3862 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Setting all elements to -1 is faster in Chrome & Firefox than mixing
3863 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // integers and undefined.
3864 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { for ( x = 0; x < vLength; x++ ) {
3865 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { v1[ x ] = -1;
3866 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { v2[ x ] = -1;
3867 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
3868 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { v1[ vOffset + 1 ] = 0;
3869 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { v2[ vOffset + 1 ] = 0;
3870 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { delta = text1Length - text2Length;
3871  
3872 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // If the total number of characters is odd, then the front path will collide
3873 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // with the reverse path.
3874 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { front = ( delta % 2 !== 0 );
3875  
3876 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Offsets for start and end of k loop.
3877 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Prevents mapping of space beyond the grid.
3878 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { k1start = 0;
3879 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { k1end = 0;
3880 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { k2start = 0;
3881 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { k2end = 0;
3882 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { for ( d = 0; d < maxD; d++ ) {
3883  
3884 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Bail out if deadline is reached.
3885 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { if ( ( new Date() ).getTime() > deadline ) {
3886 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { break;
3887 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
3888  
3889 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Walk the front path one step.
3890 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { for ( k1 = -d + k1start; k1 <= d - k1end; k1 += 2 ) {
3891 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { k1Offset = vOffset + k1;
3892 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { if ( k1 === -d || ( k1 !== d && v1[ k1Offset - 1 ] < v1[ k1Offset + 1 ] ) ) {
3893 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { x1 = v1[ k1Offset + 1 ];
3894 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { } else {
3895 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { x1 = v1[ k1Offset - 1 ] + 1;
3896 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
3897 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { y1 = x1 - k1;
3898 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { while ( x1 < text1Length && y1 < text2Length &&
3899 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { text1.charAt( x1 ) === text2.charAt( y1 ) ) {
3900 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { x1++;
3901 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { y1++;
3902 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
3903 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { v1[ k1Offset ] = x1;
3904 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { if ( x1 > text1Length ) {
3905  
3906 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Ran off the right of the graph.
3907 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { k1end += 2;
3908 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { } else if ( y1 > text2Length ) {
3909  
3910 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Ran off the bottom of the graph.
3911 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { k1start += 2;
3912 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { } else if ( front ) {
3913 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { k2Offset = vOffset + delta - k1;
3914 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { if ( k2Offset >= 0 && k2Offset < vLength && v2[ k2Offset ] !== -1 ) {
3915  
3916 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Mirror x2 onto top-left coordinate system.
3917 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { x2 = text1Length - v2[ k2Offset ];
3918 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { if ( x1 >= x2 ) {
3919  
3920 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Overlap detected.
3921 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { return this.diffBisectSplit( text1, text2, x1, y1, deadline );
3922 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
3923 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
3924 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
3925 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
3926  
3927 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Walk the reverse path one step.
3928 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { for ( k2 = -d + k2start; k2 <= d - k2end; k2 += 2 ) {
3929 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { k2Offset = vOffset + k2;
3930 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { if ( k2 === -d || ( k2 !== d && v2[ k2Offset - 1 ] < v2[ k2Offset + 1 ] ) ) {
3931 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { x2 = v2[ k2Offset + 1 ];
3932 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { } else {
3933 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { x2 = v2[ k2Offset - 1 ] + 1;
3934 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
3935 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { y2 = x2 - k2;
3936 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { while ( x2 < text1Length && y2 < text2Length &&
3937 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { text1.charAt( text1Length - x2 - 1 ) ===
3938 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { text2.charAt( text2Length - y2 - 1 ) ) {
3939 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { x2++;
3940 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { y2++;
3941 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
3942 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { v2[ k2Offset ] = x2;
3943 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { if ( x2 > text1Length ) {
3944  
3945 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Ran off the left of the graph.
3946 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { k2end += 2;
3947 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { } else if ( y2 > text2Length ) {
3948  
3949 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Ran off the top of the graph.
3950 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { k2start += 2;
3951 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { } else if ( !front ) {
3952 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { k1Offset = vOffset + delta - k2;
3953 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { if ( k1Offset >= 0 && k1Offset < vLength && v1[ k1Offset ] !== -1 ) {
3954 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { x1 = v1[ k1Offset ];
3955 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { y1 = vOffset + x1 - k1Offset;
3956  
3957 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Mirror x2 onto top-left coordinate system.
3958 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { x2 = text1Length - x2;
3959 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { if ( x1 >= x2 ) {
3960  
3961 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Overlap detected.
3962 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { return this.diffBisectSplit( text1, text2, x1, y1, deadline );
3963 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
3964 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
3965 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
3966 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
3967 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
3968  
3969 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Diff took too long and hit the deadline or
3970 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // number of diffs equals number of characters, no commonality at all.
3971 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { return [
3972 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { [ DIFF_DELETE, text1 ],
3973 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { [ DIFF_INSERT, text2 ]
3974 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { ];
3975 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { };
3976  
3977 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { /**
3978 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * Given the location of the 'middle snake', split the diff in two parts
3979 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * and recurse.
3980 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * @param {string} text1 Old string to be diffed.
3981 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * @param {string} text2 New string to be diffed.
3982 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * @param {number} x Index of split point in text1.
3983 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * @param {number} y Index of split point in text2.
3984 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * @param {number} deadline Time at which to bail if not yet complete.
3985 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * @return {!Array.<!DiffMatchPatch.Diff>} Array of diff tuples.
3986 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * @private
3987 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { */
3988 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { DiffMatchPatch.prototype.diffBisectSplit = function( text1, text2, x, y, deadline ) {
3989 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { var text1a, text1b, text2a, text2b, diffs, diffsb;
3990 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { text1a = text1.substring( 0, x );
3991 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { text2a = text2.substring( 0, y );
3992 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { text1b = text1.substring( x );
3993 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { text2b = text2.substring( y );
3994  
3995 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Compute both diffs serially.
3996 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { diffs = this.DiffMain( text1a, text2a, false, deadline );
3997 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { diffsb = this.DiffMain( text1b, text2b, false, deadline );
3998  
3999 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { return diffs.concat( diffsb );
4000 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { };
4001  
4002 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { /**
4003 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * Reduce the number of edits by eliminating semantically trivial equalities.
4004 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * @param {!Array.<!DiffMatchPatch.Diff>} diffs Array of diff tuples.
4005 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { */
4006 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { DiffMatchPatch.prototype.diffCleanupSemantic = function( diffs ) {
4007 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { var changes, equalities, equalitiesLength, lastequality,
4008 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { pointer, lengthInsertions2, lengthDeletions2, lengthInsertions1,
4009 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { lengthDeletions1, deletion, insertion, overlapLength1, overlapLength2;
4010 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { changes = false;
4011 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { equalities = []; // Stack of indices where equalities are found.
4012 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { equalitiesLength = 0; // Keeping our own length var is faster in JS.
4013 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { /** @type {?string} */
4014 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { lastequality = null;
4015  
4016 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Always equal to diffs[equalities[equalitiesLength - 1]][1]
4017 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { pointer = 0; // Index of current position.
4018  
4019 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Number of characters that changed prior to the equality.
4020 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { lengthInsertions1 = 0;
4021 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { lengthDeletions1 = 0;
4022  
4023 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Number of characters that changed after the equality.
4024 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { lengthInsertions2 = 0;
4025 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { lengthDeletions2 = 0;
4026 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { while ( pointer < diffs.length ) {
4027 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { if ( diffs[ pointer ][ 0 ] === DIFF_EQUAL ) { // Equality found.
4028 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { equalities[ equalitiesLength++ ] = pointer;
4029 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { lengthInsertions1 = lengthInsertions2;
4030 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { lengthDeletions1 = lengthDeletions2;
4031 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { lengthInsertions2 = 0;
4032 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { lengthDeletions2 = 0;
4033 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { lastequality = diffs[ pointer ][ 1 ];
4034 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { } else { // An insertion or deletion.
4035 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { if ( diffs[ pointer ][ 0 ] === DIFF_INSERT ) {
4036 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { lengthInsertions2 += diffs[ pointer ][ 1 ].length;
4037 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { } else {
4038 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { lengthDeletions2 += diffs[ pointer ][ 1 ].length;
4039 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
4040  
4041 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Eliminate an equality that is smaller or equal to the edits on both
4042 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // sides of it.
4043 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { if ( lastequality && ( lastequality.length <=
4044 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { Math.max( lengthInsertions1, lengthDeletions1 ) ) &&
4045 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { ( lastequality.length <= Math.max( lengthInsertions2,
4046 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { lengthDeletions2 ) ) ) {
4047  
4048 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Duplicate record.
4049 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { diffs.splice(
4050 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { equalities[ equalitiesLength - 1 ],
4051 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { 0,
4052 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { [ DIFF_DELETE, lastequality ]
4053 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { );
4054  
4055 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Change second copy to insert.
4056 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { diffs[ equalities[ equalitiesLength - 1 ] + 1 ][ 0 ] = DIFF_INSERT;
4057  
4058 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Throw away the equality we just deleted.
4059 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { equalitiesLength--;
4060  
4061 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Throw away the previous equality (it needs to be reevaluated).
4062 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { equalitiesLength--;
4063 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { pointer = equalitiesLength > 0 ? equalities[ equalitiesLength - 1 ] : -1;
4064  
4065 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Reset the counters.
4066 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { lengthInsertions1 = 0;
4067 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { lengthDeletions1 = 0;
4068 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { lengthInsertions2 = 0;
4069 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { lengthDeletions2 = 0;
4070 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { lastequality = null;
4071 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { changes = true;
4072 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
4073 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
4074 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { pointer++;
4075 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
4076  
4077 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Normalize the diff.
4078 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { if ( changes ) {
4079 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { this.diffCleanupMerge( diffs );
4080 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
4081  
4082 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Find any overlaps between deletions and insertions.
4083 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // e.g: <del>abcxxx</del><ins>xxxdef</ins>
4084 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // -> <del>abc</del>xxx<ins>def</ins>
4085 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // e.g: <del>xxxabc</del><ins>defxxx</ins>
4086 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // -> <ins>def</ins>xxx<del>abc</del>
4087 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Only extract an overlap if it is as big as the edit ahead or behind it.
4088 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { pointer = 1;
4089 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { while ( pointer < diffs.length ) {
4090 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { if ( diffs[ pointer - 1 ][ 0 ] === DIFF_DELETE &&
4091 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { diffs[ pointer ][ 0 ] === DIFF_INSERT ) {
4092 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { deletion = diffs[ pointer - 1 ][ 1 ];
4093 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { insertion = diffs[ pointer ][ 1 ];
4094 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { overlapLength1 = this.diffCommonOverlap( deletion, insertion );
4095 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { overlapLength2 = this.diffCommonOverlap( insertion, deletion );
4096 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { if ( overlapLength1 >= overlapLength2 ) {
4097 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { if ( overlapLength1 >= deletion.length / 2 ||
4098 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { overlapLength1 >= insertion.length / 2 ) {
4099  
4100 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Overlap found. Insert an equality and trim the surrounding edits.
4101 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { diffs.splice(
4102 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { pointer,
4103 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { 0,
4104 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { [ DIFF_EQUAL, insertion.substring( 0, overlapLength1 ) ]
4105 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { );
4106 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { diffs[ pointer - 1 ][ 1 ] =
4107 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { deletion.substring( 0, deletion.length - overlapLength1 );
4108 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { diffs[ pointer + 1 ][ 1 ] = insertion.substring( overlapLength1 );
4109 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { pointer++;
4110 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
4111 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { } else {
4112 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { if ( overlapLength2 >= deletion.length / 2 ||
4113 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { overlapLength2 >= insertion.length / 2 ) {
4114  
4115 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Reverse overlap found.
4116 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Insert an equality and swap and trim the surrounding edits.
4117 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { diffs.splice(
4118 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { pointer,
4119 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { 0,
4120 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { [ DIFF_EQUAL, deletion.substring( 0, overlapLength2 ) ]
4121 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { );
4122  
4123 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { diffs[ pointer - 1 ][ 0 ] = DIFF_INSERT;
4124 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { diffs[ pointer - 1 ][ 1 ] =
4125 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { insertion.substring( 0, insertion.length - overlapLength2 );
4126 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { diffs[ pointer + 1 ][ 0 ] = DIFF_DELETE;
4127 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { diffs[ pointer + 1 ][ 1 ] =
4128 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { deletion.substring( overlapLength2 );
4129 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { pointer++;
4130 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
4131 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
4132 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { pointer++;
4133 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
4134 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { pointer++;
4135 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
4136 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { };
4137  
4138 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { /**
4139 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * Determine if the suffix of one string is the prefix of another.
4140 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * @param {string} text1 First string.
4141 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * @param {string} text2 Second string.
4142 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * @return {number} The number of characters common to the end of the first
4143 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * string and the start of the second string.
4144 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * @private
4145 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { */
4146 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { DiffMatchPatch.prototype.diffCommonOverlap = function( text1, text2 ) {
4147 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { var text1Length, text2Length, textLength,
4148 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { best, length, pattern, found;
4149  
4150 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Cache the text lengths to prevent multiple calls.
4151 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { text1Length = text1.length;
4152 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { text2Length = text2.length;
4153  
4154 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Eliminate the null case.
4155 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { if ( text1Length === 0 || text2Length === 0 ) {
4156 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { return 0;
4157 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
4158  
4159 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Truncate the longer string.
4160 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { if ( text1Length > text2Length ) {
4161 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { text1 = text1.substring( text1Length - text2Length );
4162 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { } else if ( text1Length < text2Length ) {
4163 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { text2 = text2.substring( 0, text1Length );
4164 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
4165 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { textLength = Math.min( text1Length, text2Length );
4166  
4167 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Quick check for the worst case.
4168 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { if ( text1 === text2 ) {
4169 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { return textLength;
4170 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
4171  
4172 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Start by looking for a single character match
4173 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // and increase length until no match is found.
4174 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Performance analysis: https://neil.fraser.name/news/2010/11/04/
4175 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { best = 0;
4176 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { length = 1;
4177 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { while ( true ) {
4178 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { pattern = text1.substring( textLength - length );
4179 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { found = text2.indexOf( pattern );
4180 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { if ( found === -1 ) {
4181 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { return best;
4182 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
4183 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { length += found;
4184 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { if ( found === 0 || text1.substring( textLength - length ) ===
4185 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { text2.substring( 0, length ) ) {
4186 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { best = length;
4187 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { length++;
4188 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
4189 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
4190 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { };
4191  
4192 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { /**
4193 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * Split two texts into an array of strings. Reduce the texts to a string of
4194 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * hashes where each Unicode character represents one line.
4195 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * @param {string} text1 First string.
4196 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * @param {string} text2 Second string.
4197 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * @return {{chars1: string, chars2: string, lineArray: !Array.<string>}}
4198 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * An object containing the encoded text1, the encoded text2 and
4199 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * the array of unique strings.
4200 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * The zeroth element of the array of unique strings is intentionally blank.
4201 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * @private
4202 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { */
4203 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { DiffMatchPatch.prototype.diffLinesToChars = function( text1, text2 ) {
4204 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { var lineArray, lineHash, chars1, chars2;
4205 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { lineArray = []; // E.g. lineArray[4] === 'Hello\n'
4206 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { lineHash = {}; // E.g. lineHash['Hello\n'] === 4
4207  
4208 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // '\x00' is a valid character, but various debuggers don't like it.
4209 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // So we'll insert a junk entry to avoid generating a null character.
4210 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { lineArray[ 0 ] = "";
4211  
4212 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { /**
4213 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * Split a text into an array of strings. Reduce the texts to a string of
4214 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * hashes where each Unicode character represents one line.
4215 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * Modifies linearray and linehash through being a closure.
4216 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * @param {string} text String to encode.
4217 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * @return {string} Encoded string.
4218 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * @private
4219 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { */
4220 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { function diffLinesToCharsMunge( text ) {
4221 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { var chars, lineStart, lineEnd, lineArrayLength, line;
4222 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { chars = "";
4223  
4224 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Walk the text, pulling out a substring for each line.
4225 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // text.split('\n') would would temporarily double our memory footprint.
4226 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Modifying text would create many large strings to garbage collect.
4227 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { lineStart = 0;
4228 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { lineEnd = -1;
4229  
4230 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Keeping our own length variable is faster than looking it up.
4231 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { lineArrayLength = lineArray.length;
4232 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { while ( lineEnd < text.length - 1 ) {
4233 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { lineEnd = text.indexOf( "\n", lineStart );
4234 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { if ( lineEnd === -1 ) {
4235 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { lineEnd = text.length - 1;
4236 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
4237 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { line = text.substring( lineStart, lineEnd + 1 );
4238 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { lineStart = lineEnd + 1;
4239  
4240 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { if ( lineHash.hasOwnProperty ? lineHash.hasOwnProperty( line ) :
4241 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { ( lineHash[ line ] !== undefined ) ) {
4242 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { chars += String.fromCharCode( lineHash[ line ] );
4243 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { } else {
4244 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { chars += String.fromCharCode( lineArrayLength );
4245 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { lineHash[ line ] = lineArrayLength;
4246 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { lineArray[ lineArrayLength++ ] = line;
4247 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
4248 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
4249 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { return chars;
4250 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
4251  
4252 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { chars1 = diffLinesToCharsMunge( text1 );
4253 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { chars2 = diffLinesToCharsMunge( text2 );
4254 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { return {
4255 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { chars1: chars1,
4256 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { chars2: chars2,
4257 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { lineArray: lineArray
4258 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { };
4259 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { };
4260  
4261 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { /**
4262 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * Rehydrate the text in a diff from a string of line hashes to real lines of
4263 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * text.
4264 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * @param {!Array.<!DiffMatchPatch.Diff>} diffs Array of diff tuples.
4265 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * @param {!Array.<string>} lineArray Array of unique strings.
4266 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * @private
4267 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { */
4268 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { DiffMatchPatch.prototype.diffCharsToLines = function( diffs, lineArray ) {
4269 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { var x, chars, text, y;
4270 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { for ( x = 0; x < diffs.length; x++ ) {
4271 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { chars = diffs[ x ][ 1 ];
4272 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { text = [];
4273 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { for ( y = 0; y < chars.length; y++ ) {
4274 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { text[ y ] = lineArray[ chars.charCodeAt( y ) ];
4275 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
4276 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { diffs[ x ][ 1 ] = text.join( "" );
4277 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
4278 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { };
4279  
4280 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { /**
4281 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * Reorder and merge like edit sections. Merge equalities.
4282 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * Any edit section can move as long as it doesn't cross an equality.
4283 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { * @param {!Array.<!DiffMatchPatch.Diff>} diffs Array of diff tuples.
4284 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { */
4285 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { DiffMatchPatch.prototype.diffCleanupMerge = function( diffs ) {
4286 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { var pointer, countDelete, countInsert, textInsert, textDelete,
4287 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { commonlength, changes, diffPointer, position;
4288 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { diffs.push( [ DIFF_EQUAL, "" ] ); // Add a dummy entry at the end.
4289 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { pointer = 0;
4290 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { countDelete = 0;
4291 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { countInsert = 0;
4292 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { textDelete = "";
4293 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { textInsert = "";
4294 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { commonlength;
4295 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { while ( pointer < diffs.length ) {
4296 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { switch ( diffs[ pointer ][ 0 ] ) {
4297 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { case DIFF_INSERT:
4298 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { countInsert++;
4299 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { textInsert += diffs[ pointer ][ 1 ];
4300 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { pointer++;
4301 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { break;
4302 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { case DIFF_DELETE:
4303 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { countDelete++;
4304 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { textDelete += diffs[ pointer ][ 1 ];
4305 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { pointer++;
4306 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { break;
4307 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { case DIFF_EQUAL:
4308  
4309 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Upon reaching an equality, check for prior redundancies.
4310 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { if ( countDelete + countInsert > 1 ) {
4311 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { if ( countDelete !== 0 && countInsert !== 0 ) {
4312  
4313 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Factor out any common prefixes.
4314 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { commonlength = this.diffCommonPrefix( textInsert, textDelete );
4315 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { if ( commonlength !== 0 ) {
4316 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { if ( ( pointer - countDelete - countInsert ) > 0 &&
4317 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { diffs[ pointer - countDelete - countInsert - 1 ][ 0 ] ===
4318 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { DIFF_EQUAL ) {
4319 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { diffs[ pointer - countDelete - countInsert - 1 ][ 1 ] +=
4320 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { textInsert.substring( 0, commonlength );
4321 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { } else {
4322 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { diffs.splice( 0, 0, [ DIFF_EQUAL,
4323 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { textInsert.substring( 0, commonlength )
4324 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { ] );
4325 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { pointer++;
4326 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
4327 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { textInsert = textInsert.substring( commonlength );
4328 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { textDelete = textDelete.substring( commonlength );
4329 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
4330  
4331 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Factor out any common suffixies.
4332 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { commonlength = this.diffCommonSuffix( textInsert, textDelete );
4333 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { if ( commonlength !== 0 ) {
4334 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { diffs[ pointer ][ 1 ] = textInsert.substring( textInsert.length -
4335 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { commonlength ) + diffs[ pointer ][ 1 ];
4336 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { textInsert = textInsert.substring( 0, textInsert.length -
4337 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { commonlength );
4338 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { textDelete = textDelete.substring( 0, textDelete.length -
4339 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { commonlength );
4340 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
4341 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
4342  
4343 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Delete the offending records and add the merged ones.
4344 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { if ( countDelete === 0 ) {
4345 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { diffs.splice( pointer - countInsert,
4346 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { countDelete + countInsert, [ DIFF_INSERT, textInsert ] );
4347 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { } else if ( countInsert === 0 ) {
4348 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { diffs.splice( pointer - countDelete,
4349 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { countDelete + countInsert, [ DIFF_DELETE, textDelete ] );
4350 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { } else {
4351 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { diffs.splice(
4352 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { pointer - countDelete - countInsert,
4353 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { countDelete + countInsert,
4354 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { [ DIFF_DELETE, textDelete ], [ DIFF_INSERT, textInsert ]
4355 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { );
4356 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
4357 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { pointer = pointer - countDelete - countInsert +
4358 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { ( countDelete ? 1 : 0 ) + ( countInsert ? 1 : 0 ) + 1;
4359 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { } else if ( pointer !== 0 && diffs[ pointer - 1 ][ 0 ] === DIFF_EQUAL ) {
4360  
4361 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Merge this equality with the previous one.
4362 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { diffs[ pointer - 1 ][ 1 ] += diffs[ pointer ][ 1 ];
4363 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { diffs.splice( pointer, 1 );
4364 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { } else {
4365 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { pointer++;
4366 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
4367 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { countInsert = 0;
4368 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { countDelete = 0;
4369 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { textDelete = "";
4370 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { textInsert = "";
4371 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { break;
4372 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
4373 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
4374 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { if ( diffs[ diffs.length - 1 ][ 1 ] === "" ) {
4375 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { diffs.pop(); // Remove the dummy entry at the end.
4376 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
4377  
4378 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Second pass: look for single edits surrounded on both sides by equalities
4379 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // which can be shifted sideways to eliminate an equality.
4380 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // e.g: A<ins>BA</ins>C -> <ins>AB</ins>AC
4381 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { changes = false;
4382 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { pointer = 1;
4383  
4384 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Intentionally ignore the first and last element (don't need checking).
4385 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { while ( pointer < diffs.length - 1 ) {
4386 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { if ( diffs[ pointer - 1 ][ 0 ] === DIFF_EQUAL &&
4387 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { diffs[ pointer + 1 ][ 0 ] === DIFF_EQUAL ) {
4388  
4389 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { diffPointer = diffs[ pointer ][ 1 ];
4390 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { position = diffPointer.substring(
4391 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { diffPointer.length - diffs[ pointer - 1 ][ 1 ].length
4392 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { );
4393  
4394 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // This is a single edit surrounded by equalities.
4395 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { if ( position === diffs[ pointer - 1 ][ 1 ] ) {
4396  
4397 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Shift the edit over the previous equality.
4398 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { diffs[ pointer ][ 1 ] = diffs[ pointer - 1 ][ 1 ] +
4399 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { diffs[ pointer ][ 1 ].substring( 0, diffs[ pointer ][ 1 ].length -
4400 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { diffs[ pointer - 1 ][ 1 ].length );
4401 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { diffs[ pointer + 1 ][ 1 ] =
4402 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { diffs[ pointer - 1 ][ 1 ] + diffs[ pointer + 1 ][ 1 ];
4403 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { diffs.splice( pointer - 1, 1 );
4404 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { changes = true;
4405 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { } else if ( diffPointer.substring( 0, diffs[ pointer + 1 ][ 1 ].length ) ===
4406 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { diffs[ pointer + 1 ][ 1 ] ) {
4407  
4408 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // Shift the edit over the next equality.
4409 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { diffs[ pointer - 1 ][ 1 ] += diffs[ pointer + 1 ][ 1 ];
4410 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { diffs[ pointer ][ 1 ] =
4411 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { diffs[ pointer ][ 1 ].substring( diffs[ pointer + 1 ][ 1 ].length ) +
4412 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { diffs[ pointer + 1 ][ 1 ];
4413 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { diffs.splice( pointer + 1, 1 );
4414 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { changes = true;
4415 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
4416 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
4417 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { pointer++;
4418 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
4419  
4420 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { // If shifts were made, the diff needs reordering and another shift sweep.
4421 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { if ( changes ) {
4422 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { this.diffCleanupMerge( diffs );
4423 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { }
4424 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { };
4425  
4426 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { return function( o, n ) {
4427 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { var diff, output, text;
4428 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { diff = new DiffMatchPatch();
4429 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { output = diff.DiffMain( o, n );
4430 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { diff.diffCleanupEfficiency( output );
4431 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { text = diff.diffPrettyHtml( output );
4432  
4433 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { return text;
4434 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) { };
4435 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) {}() );
4436  
4437 < 0 ) {<><\/?[^>< suffixLength + prefixLength ) {< diffs.length ) {}() );