Added images and made the visualizator work
[VSoRC/.git] / js / joint.all.js
1 /*! JointJS v0.9.0 - JavaScript diagramming library  2014-05-13 
2
3
4 This Source Code Form is subject to the terms of the Mozilla Public
5 License, v. 2.0. If a copy of the MPL was not distributed with this
6 file, You can obtain one at http://mozilla.org/MPL/2.0/.
7  */
8 /*!
9  * jQuery JavaScript Library v2.0.3
10  * http://jquery.com/
11  *
12  * Includes Sizzle.js
13  * http://sizzlejs.com/
14  *
15  * Copyright 2005, 2013 jQuery Foundation, Inc. and other contributors
16  * Released under the MIT license
17  * http://jquery.org/license
18  *
19  * Date: 2013-07-03T13:30Z
20  */
21 (function( window, undefined ) {
22
23 // Can't do this because several apps including ASP.NET trace
24 // the stack via arguments.caller.callee and Firefox dies if
25 // you try to trace through "use strict" call chains. (#13335)
26 // Support: Firefox 18+
27 //"use strict";
28 var
29         // A central reference to the root jQuery(document)
30         rootjQuery,
31
32         // The deferred used on DOM ready
33         readyList,
34
35         // Support: IE9
36         // For `typeof xmlNode.method` instead of `xmlNode.method !== undefined`
37         core_strundefined = typeof undefined,
38
39         // Use the correct document accordingly with window argument (sandbox)
40         location = window.location,
41         document = window.document,
42         docElem = document.documentElement,
43
44         // Map over jQuery in case of overwrite
45         _jQuery = window.jQuery,
46
47         // Map over the $ in case of overwrite
48         _$ = window.$,
49
50         // [[Class]] -> type pairs
51         class2type = {},
52
53         // List of deleted data cache ids, so we can reuse them
54         core_deletedIds = [],
55
56         core_version = "2.0.3",
57
58         // Save a reference to some core methods
59         core_concat = core_deletedIds.concat,
60         core_push = core_deletedIds.push,
61         core_slice = core_deletedIds.slice,
62         core_indexOf = core_deletedIds.indexOf,
63         core_toString = class2type.toString,
64         core_hasOwn = class2type.hasOwnProperty,
65         core_trim = core_version.trim,
66
67         // Define a local copy of jQuery
68         jQuery = function( selector, context ) {
69                 // The jQuery object is actually just the init constructor 'enhanced'
70                 return new jQuery.fn.init( selector, context, rootjQuery );
71         },
72
73         // Used for matching numbers
74         core_pnum = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,
75
76         // Used for splitting on whitespace
77         core_rnotwhite = /\S+/g,
78
79         // A simple way to check for HTML strings
80         // Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
81         // Strict HTML recognition (#11290: must start with <)
82         rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,
83
84         // Match a standalone tag
85         rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/,
86
87         // Matches dashed string for camelizing
88         rmsPrefix = /^-ms-/,
89         rdashAlpha = /-([\da-z])/gi,
90
91         // Used by jQuery.camelCase as callback to replace()
92         fcamelCase = function( all, letter ) {
93                 return letter.toUpperCase();
94         },
95
96         // The ready event handler and self cleanup method
97         completed = function() {
98                 document.removeEventListener( "DOMContentLoaded", completed, false );
99                 window.removeEventListener( "load", completed, false );
100                 jQuery.ready();
101         };
102
103 jQuery.fn = jQuery.prototype = {
104         // The current version of jQuery being used
105         jquery: core_version,
106
107         constructor: jQuery,
108         init: function( selector, context, rootjQuery ) {
109                 var match, elem;
110
111                 // HANDLE: $(""), $(null), $(undefined), $(false)
112                 if ( !selector ) {
113                         return this;
114                 }
115
116                 // Handle HTML strings
117                 if ( typeof selector === "string" ) {
118                         if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
119                                 // Assume that strings that start and end with <> are HTML and skip the regex check
120                                 match = [ null, selector, null ];
121
122                         } else {
123                                 match = rquickExpr.exec( selector );
124                         }
125
126                         // Match html or make sure no context is specified for #id
127                         if ( match && (match[1] || !context) ) {
128
129                                 // HANDLE: $(html) -> $(array)
130                                 if ( match[1] ) {
131                                         context = context instanceof jQuery ? context[0] : context;
132
133                                         // scripts is true for back-compat
134                                         jQuery.merge( this, jQuery.parseHTML(
135                                                 match[1],
136                                                 context && context.nodeType ? context.ownerDocument || context : document,
137                                                 true
138                                         ) );
139
140                                         // HANDLE: $(html, props)
141                                         if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
142                                                 for ( match in context ) {
143                                                         // Properties of context are called as methods if possible
144                                                         if ( jQuery.isFunction( this[ match ] ) ) {
145                                                                 this[ match ]( context[ match ] );
146
147                                                         // ...and otherwise set as attributes
148                                                         } else {
149                                                                 this.attr( match, context[ match ] );
150                                                         }
151                                                 }
152                                         }
153
154                                         return this;
155
156                                 // HANDLE: $(#id)
157                                 } else {
158                                         elem = document.getElementById( match[2] );
159
160                                         // Check parentNode to catch when Blackberry 4.6 returns
161                                         // nodes that are no longer in the document #6963
162                                         if ( elem && elem.parentNode ) {
163                                                 // Inject the element directly into the jQuery object
164                                                 this.length = 1;
165                                                 this[0] = elem;
166                                         }
167
168                                         this.context = document;
169                                         this.selector = selector;
170                                         return this;
171                                 }
172
173                         // HANDLE: $(expr, $(...))
174                         } else if ( !context || context.jquery ) {
175                                 return ( context || rootjQuery ).find( selector );
176
177                         // HANDLE: $(expr, context)
178                         // (which is just equivalent to: $(context).find(expr)
179                         } else {
180                                 return this.constructor( context ).find( selector );
181                         }
182
183                 // HANDLE: $(DOMElement)
184                 } else if ( selector.nodeType ) {
185                         this.context = this[0] = selector;
186                         this.length = 1;
187                         return this;
188
189                 // HANDLE: $(function)
190                 // Shortcut for document ready
191                 } else if ( jQuery.isFunction( selector ) ) {
192                         return rootjQuery.ready( selector );
193                 }
194
195                 if ( selector.selector !== undefined ) {
196                         this.selector = selector.selector;
197                         this.context = selector.context;
198                 }
199
200                 return jQuery.makeArray( selector, this );
201         },
202
203         // Start with an empty selector
204         selector: "",
205
206         // The default length of a jQuery object is 0
207         length: 0,
208
209         toArray: function() {
210                 return core_slice.call( this );
211         },
212
213         // Get the Nth element in the matched element set OR
214         // Get the whole matched element set as a clean array
215         get: function( num ) {
216                 return num == null ?
217
218                         // Return a 'clean' array
219                         this.toArray() :
220
221                         // Return just the object
222                         ( num < 0 ? this[ this.length + num ] : this[ num ] );
223         },
224
225         // Take an array of elements and push it onto the stack
226         // (returning the new matched element set)
227         pushStack: function( elems ) {
228
229                 // Build a new jQuery matched element set
230                 var ret = jQuery.merge( this.constructor(), elems );
231
232                 // Add the old object onto the stack (as a reference)
233                 ret.prevObject = this;
234                 ret.context = this.context;
235
236                 // Return the newly-formed element set
237                 return ret;
238         },
239
240         // Execute a callback for every element in the matched set.
241         // (You can seed the arguments with an array of args, but this is
242         // only used internally.)
243         each: function( callback, args ) {
244                 return jQuery.each( this, callback, args );
245         },
246
247         ready: function( fn ) {
248                 // Add the callback
249                 jQuery.ready.promise().done( fn );
250
251                 return this;
252         },
253
254         slice: function() {
255                 return this.pushStack( core_slice.apply( this, arguments ) );
256         },
257
258         first: function() {
259                 return this.eq( 0 );
260         },
261
262         last: function() {
263                 return this.eq( -1 );
264         },
265
266         eq: function( i ) {
267                 var len = this.length,
268                         j = +i + ( i < 0 ? len : 0 );
269                 return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );
270         },
271
272         map: function( callback ) {
273                 return this.pushStack( jQuery.map(this, function( elem, i ) {
274                         return callback.call( elem, i, elem );
275                 }));
276         },
277
278         end: function() {
279                 return this.prevObject || this.constructor(null);
280         },
281
282         // For internal use only.
283         // Behaves like an Array's method, not like a jQuery method.
284         push: core_push,
285         sort: [].sort,
286         splice: [].splice
287 };
288
289 // Give the init function the jQuery prototype for later instantiation
290 jQuery.fn.init.prototype = jQuery.fn;
291
292 jQuery.extend = jQuery.fn.extend = function() {
293         var options, name, src, copy, copyIsArray, clone,
294                 target = arguments[0] || {},
295                 i = 1,
296                 length = arguments.length,
297                 deep = false;
298
299         // Handle a deep copy situation
300         if ( typeof target === "boolean" ) {
301                 deep = target;
302                 target = arguments[1] || {};
303                 // skip the boolean and the target
304                 i = 2;
305         }
306
307         // Handle case when target is a string or something (possible in deep copy)
308         if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
309                 target = {};
310         }
311
312         // extend jQuery itself if only one argument is passed
313         if ( length === i ) {
314                 target = this;
315                 --i;
316         }
317
318         for ( ; i < length; i++ ) {
319                 // Only deal with non-null/undefined values
320                 if ( (options = arguments[ i ]) != null ) {
321                         // Extend the base object
322                         for ( name in options ) {
323                                 src = target[ name ];
324                                 copy = options[ name ];
325
326                                 // Prevent never-ending loop
327                                 if ( target === copy ) {
328                                         continue;
329                                 }
330
331                                 // Recurse if we're merging plain objects or arrays
332                                 if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
333                                         if ( copyIsArray ) {
334                                                 copyIsArray = false;
335                                                 clone = src && jQuery.isArray(src) ? src : [];
336
337                                         } else {
338                                                 clone = src && jQuery.isPlainObject(src) ? src : {};
339                                         }
340
341                                         // Never move original objects, clone them
342                                         target[ name ] = jQuery.extend( deep, clone, copy );
343
344                                 // Don't bring in undefined values
345                                 } else if ( copy !== undefined ) {
346                                         target[ name ] = copy;
347                                 }
348                         }
349                 }
350         }
351
352         // Return the modified object
353         return target;
354 };
355
356 jQuery.extend({
357         // Unique for each copy of jQuery on the page
358         expando: "jQuery" + ( core_version + Math.random() ).replace( /\D/g, "" ),
359
360         noConflict: function( deep ) {
361                 if ( window.$ === jQuery ) {
362                         window.$ = _$;
363                 }
364
365                 if ( deep && window.jQuery === jQuery ) {
366                         window.jQuery = _jQuery;
367                 }
368
369                 return jQuery;
370         },
371
372         // Is the DOM ready to be used? Set to true once it occurs.
373         isReady: false,
374
375         // A counter to track how many items to wait for before
376         // the ready event fires. See #6781
377         readyWait: 1,
378
379         // Hold (or release) the ready event
380         holdReady: function( hold ) {
381                 if ( hold ) {
382                         jQuery.readyWait++;
383                 } else {
384                         jQuery.ready( true );
385                 }
386         },
387
388         // Handle when the DOM is ready
389         ready: function( wait ) {
390
391                 // Abort if there are pending holds or we're already ready
392                 if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
393                         return;
394                 }
395
396                 // Remember that the DOM is ready
397                 jQuery.isReady = true;
398
399                 // If a normal DOM Ready event fired, decrement, and wait if need be
400                 if ( wait !== true && --jQuery.readyWait > 0 ) {
401                         return;
402                 }
403
404                 // If there are functions bound, to execute
405                 readyList.resolveWith( document, [ jQuery ] );
406
407                 // Trigger any bound ready events
408                 if ( jQuery.fn.trigger ) {
409                         jQuery( document ).trigger("ready").off("ready");
410                 }
411         },
412
413         // See test/unit/core.js for details concerning isFunction.
414         // Since version 1.3, DOM methods and functions like alert
415         // aren't supported. They return false on IE (#2968).
416         isFunction: function( obj ) {
417                 return jQuery.type(obj) === "function";
418         },
419
420         isArray: Array.isArray,
421
422         isWindow: function( obj ) {
423                 return obj != null && obj === obj.window;
424         },
425
426         isNumeric: function( obj ) {
427                 return !isNaN( parseFloat(obj) ) && isFinite( obj );
428         },
429
430         type: function( obj ) {
431                 if ( obj == null ) {
432                         return String( obj );
433                 }
434                 // Support: Safari <= 5.1 (functionish RegExp)
435                 return typeof obj === "object" || typeof obj === "function" ?
436                         class2type[ core_toString.call(obj) ] || "object" :
437                         typeof obj;
438         },
439
440         isPlainObject: function( obj ) {
441                 // Not plain objects:
442                 // - Any object or value whose internal [[Class]] property is not "[object Object]"
443                 // - DOM nodes
444                 // - window
445                 if ( jQuery.type( obj ) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
446                         return false;
447                 }
448
449                 // Support: Firefox <20
450                 // The try/catch suppresses exceptions thrown when attempting to access
451                 // the "constructor" property of certain host objects, ie. |window.location|
452                 // https://bugzilla.mozilla.org/show_bug.cgi?id=814622
453                 try {
454                         if ( obj.constructor &&
455                                         !core_hasOwn.call( obj.constructor.prototype, "isPrototypeOf" ) ) {
456                                 return false;
457                         }
458                 } catch ( e ) {
459                         return false;
460                 }
461
462                 // If the function hasn't returned already, we're confident that
463                 // |obj| is a plain object, created by {} or constructed with new Object
464                 return true;
465         },
466
467         isEmptyObject: function( obj ) {
468                 var name;
469                 for ( name in obj ) {
470                         return false;
471                 }
472                 return true;
473         },
474
475         error: function( msg ) {
476                 throw new Error( msg );
477         },
478
479         // data: string of html
480         // context (optional): If specified, the fragment will be created in this context, defaults to document
481         // keepScripts (optional): If true, will include scripts passed in the html string
482         parseHTML: function( data, context, keepScripts ) {
483                 if ( !data || typeof data !== "string" ) {
484                         return null;
485                 }
486                 if ( typeof context === "boolean" ) {
487                         keepScripts = context;
488                         context = false;
489                 }
490                 context = context || document;
491
492                 var parsed = rsingleTag.exec( data ),
493                         scripts = !keepScripts && [];
494
495                 // Single tag
496                 if ( parsed ) {
497                         return [ context.createElement( parsed[1] ) ];
498                 }
499
500                 parsed = jQuery.buildFragment( [ data ], context, scripts );
501
502                 if ( scripts ) {
503                         jQuery( scripts ).remove();
504                 }
505
506                 return jQuery.merge( [], parsed.childNodes );
507         },
508
509         parseJSON: JSON.parse,
510
511         // Cross-browser xml parsing
512         parseXML: function( data ) {
513                 var xml, tmp;
514                 if ( !data || typeof data !== "string" ) {
515                         return null;
516                 }
517
518                 // Support: IE9
519                 try {
520                         tmp = new DOMParser();
521                         xml = tmp.parseFromString( data , "text/xml" );
522                 } catch ( e ) {
523                         xml = undefined;
524                 }
525
526                 if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) {
527                         jQuery.error( "Invalid XML: " + data );
528                 }
529                 return xml;
530         },
531
532         noop: function() {},
533
534         // Evaluates a script in a global context
535         globalEval: function( code ) {
536                 var script,
537                                 indirect = eval;
538
539                 code = jQuery.trim( code );
540
541                 if ( code ) {
542                         // If the code includes a valid, prologue position
543                         // strict mode pragma, execute code by injecting a
544                         // script tag into the document.
545                         if ( code.indexOf("use strict") === 1 ) {
546                                 script = document.createElement("script");
547                                 script.text = code;
548                                 document.head.appendChild( script ).parentNode.removeChild( script );
549                         } else {
550                         // Otherwise, avoid the DOM node creation, insertion
551                         // and removal by using an indirect global eval
552                                 indirect( code );
553                         }
554                 }
555         },
556
557         // Convert dashed to camelCase; used by the css and data modules
558         // Microsoft forgot to hump their vendor prefix (#9572)
559         camelCase: function( string ) {
560                 return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
561         },
562
563         nodeName: function( elem, name ) {
564                 return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
565         },
566
567         // args is for internal usage only
568         each: function( obj, callback, args ) {
569                 var value,
570                         i = 0,
571                         length = obj.length,
572                         isArray = isArraylike( obj );
573
574                 if ( args ) {
575                         if ( isArray ) {
576                                 for ( ; i < length; i++ ) {
577                                         value = callback.apply( obj[ i ], args );
578
579                                         if ( value === false ) {
580                                                 break;
581                                         }
582                                 }
583                         } else {
584                                 for ( i in obj ) {
585                                         value = callback.apply( obj[ i ], args );
586
587                                         if ( value === false ) {
588                                                 break;
589                                         }
590                                 }
591                         }
592
593                 // A special, fast, case for the most common use of each
594                 } else {
595                         if ( isArray ) {
596                                 for ( ; i < length; i++ ) {
597                                         value = callback.call( obj[ i ], i, obj[ i ] );
598
599                                         if ( value === false ) {
600                                                 break;
601                                         }
602                                 }
603                         } else {
604                                 for ( i in obj ) {
605                                         value = callback.call( obj[ i ], i, obj[ i ] );
606
607                                         if ( value === false ) {
608                                                 break;
609                                         }
610                                 }
611                         }
612                 }
613
614                 return obj;
615         },
616
617         trim: function( text ) {
618                 return text == null ? "" : core_trim.call( text );
619         },
620
621         // results is for internal usage only
622         makeArray: function( arr, results ) {
623                 var ret = results || [];
624
625                 if ( arr != null ) {
626                         if ( isArraylike( Object(arr) ) ) {
627                                 jQuery.merge( ret,
628                                         typeof arr === "string" ?
629                                         [ arr ] : arr
630                                 );
631                         } else {
632                                 core_push.call( ret, arr );
633                         }
634                 }
635
636                 return ret;
637         },
638
639         inArray: function( elem, arr, i ) {
640                 return arr == null ? -1 : core_indexOf.call( arr, elem, i );
641         },
642
643         merge: function( first, second ) {
644                 var l = second.length,
645                         i = first.length,
646                         j = 0;
647
648                 if ( typeof l === "number" ) {
649                         for ( ; j < l; j++ ) {
650                                 first[ i++ ] = second[ j ];
651                         }
652                 } else {
653                         while ( second[j] !== undefined ) {
654                                 first[ i++ ] = second[ j++ ];
655                         }
656                 }
657
658                 first.length = i;
659
660                 return first;
661         },
662
663         grep: function( elems, callback, inv ) {
664                 var retVal,
665                         ret = [],
666                         i = 0,
667                         length = elems.length;
668                 inv = !!inv;
669
670                 // Go through the array, only saving the items
671                 // that pass the validator function
672                 for ( ; i < length; i++ ) {
673                         retVal = !!callback( elems[ i ], i );
674                         if ( inv !== retVal ) {
675                                 ret.push( elems[ i ] );
676                         }
677                 }
678
679                 return ret;
680         },
681
682         // arg is for internal usage only
683         map: function( elems, callback, arg ) {
684                 var value,
685                         i = 0,
686                         length = elems.length,
687                         isArray = isArraylike( elems ),
688                         ret = [];
689
690                 // Go through the array, translating each of the items to their
691                 if ( isArray ) {
692                         for ( ; i < length; i++ ) {
693                                 value = callback( elems[ i ], i, arg );
694
695                                 if ( value != null ) {
696                                         ret[ ret.length ] = value;
697                                 }
698                         }
699
700                 // Go through every key on the object,
701                 } else {
702                         for ( i in elems ) {
703                                 value = callback( elems[ i ], i, arg );
704
705                                 if ( value != null ) {
706                                         ret[ ret.length ] = value;
707                                 }
708                         }
709                 }
710
711                 // Flatten any nested arrays
712                 return core_concat.apply( [], ret );
713         },
714
715         // A global GUID counter for objects
716         guid: 1,
717
718         // Bind a function to a context, optionally partially applying any
719         // arguments.
720         proxy: function( fn, context ) {
721                 var tmp, args, proxy;
722
723                 if ( typeof context === "string" ) {
724                         tmp = fn[ context ];
725                         context = fn;
726                         fn = tmp;
727                 }
728
729                 // Quick check to determine if target is callable, in the spec
730                 // this throws a TypeError, but we will just return undefined.
731                 if ( !jQuery.isFunction( fn ) ) {
732                         return undefined;
733                 }
734
735                 // Simulated bind
736                 args = core_slice.call( arguments, 2 );
737                 proxy = function() {
738                         return fn.apply( context || this, args.concat( core_slice.call( arguments ) ) );
739                 };
740
741                 // Set the guid of unique handler to the same of original handler, so it can be removed
742                 proxy.guid = fn.guid = fn.guid || jQuery.guid++;
743
744                 return proxy;
745         },
746
747         // Multifunctional method to get and set values of a collection
748         // The value/s can optionally be executed if it's a function
749         access: function( elems, fn, key, value, chainable, emptyGet, raw ) {
750                 var i = 0,
751                         length = elems.length,
752                         bulk = key == null;
753
754                 // Sets many values
755                 if ( jQuery.type( key ) === "object" ) {
756                         chainable = true;
757                         for ( i in key ) {
758                                 jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
759                         }
760
761                 // Sets one value
762                 } else if ( value !== undefined ) {
763                         chainable = true;
764
765                         if ( !jQuery.isFunction( value ) ) {
766                                 raw = true;
767                         }
768
769                         if ( bulk ) {
770                                 // Bulk operations run against the entire set
771                                 if ( raw ) {
772                                         fn.call( elems, value );
773                                         fn = null;
774
775                                 // ...except when executing function values
776                                 } else {
777                                         bulk = fn;
778                                         fn = function( elem, key, value ) {
779                                                 return bulk.call( jQuery( elem ), value );
780                                         };
781                                 }
782                         }
783
784                         if ( fn ) {
785                                 for ( ; i < length; i++ ) {
786                                         fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
787                                 }
788                         }
789                 }
790
791                 return chainable ?
792                         elems :
793
794                         // Gets
795                         bulk ?
796                                 fn.call( elems ) :
797                                 length ? fn( elems[0], key ) : emptyGet;
798         },
799
800         now: Date.now,
801
802         // A method for quickly swapping in/out CSS properties to get correct calculations.
803         // Note: this method belongs to the css module but it's needed here for the support module.
804         // If support gets modularized, this method should be moved back to the css module.
805         swap: function( elem, options, callback, args ) {
806                 var ret, name,
807                         old = {};
808
809                 // Remember the old values, and insert the new ones
810                 for ( name in options ) {
811                         old[ name ] = elem.style[ name ];
812                         elem.style[ name ] = options[ name ];
813                 }
814
815                 ret = callback.apply( elem, args || [] );
816
817                 // Revert the old values
818                 for ( name in options ) {
819                         elem.style[ name ] = old[ name ];
820                 }
821
822                 return ret;
823         }
824 });
825
826 jQuery.ready.promise = function( obj ) {
827         if ( !readyList ) {
828
829                 readyList = jQuery.Deferred();
830
831                 // Catch cases where $(document).ready() is called after the browser event has already occurred.
832                 // we once tried to use readyState "interactive" here, but it caused issues like the one
833                 // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
834                 if ( document.readyState === "complete" ) {
835                         // Handle it asynchronously to allow scripts the opportunity to delay ready
836                         setTimeout( jQuery.ready );
837
838                 } else {
839
840                         // Use the handy event callback
841                         document.addEventListener( "DOMContentLoaded", completed, false );
842
843                         // A fallback to window.onload, that will always work
844                         window.addEventListener( "load", completed, false );
845                 }
846         }
847         return readyList.promise( obj );
848 };
849
850 // Populate the class2type map
851 jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
852         class2type[ "[object " + name + "]" ] = name.toLowerCase();
853 });
854
855 function isArraylike( obj ) {
856         var length = obj.length,
857                 type = jQuery.type( obj );
858
859         if ( jQuery.isWindow( obj ) ) {
860                 return false;
861         }
862
863         if ( obj.nodeType === 1 && length ) {
864                 return true;
865         }
866
867         return type === "array" || type !== "function" &&
868                 ( length === 0 ||
869                 typeof length === "number" && length > 0 && ( length - 1 ) in obj );
870 }
871
872 // All jQuery objects should point back to these
873 rootjQuery = jQuery(document);
874 /*!
875  * Sizzle CSS Selector Engine v1.9.4-pre
876  * http://sizzlejs.com/
877  *
878  * Copyright 2013 jQuery Foundation, Inc. and other contributors
879  * Released under the MIT license
880  * http://jquery.org/license
881  *
882  * Date: 2013-06-03
883  */
884 (function( window, undefined ) {
885
886 var i,
887         support,
888         cachedruns,
889         Expr,
890         getText,
891         isXML,
892         compile,
893         outermostContext,
894         sortInput,
895
896         // Local document vars
897         setDocument,
898         document,
899         docElem,
900         documentIsHTML,
901         rbuggyQSA,
902         rbuggyMatches,
903         matches,
904         contains,
905
906         // Instance-specific data
907         expando = "sizzle" + -(new Date()),
908         preferredDoc = window.document,
909         dirruns = 0,
910         done = 0,
911         classCache = createCache(),
912         tokenCache = createCache(),
913         compilerCache = createCache(),
914         hasDuplicate = false,
915         sortOrder = function( a, b ) {
916                 if ( a === b ) {
917                         hasDuplicate = true;
918                         return 0;
919                 }
920                 return 0;
921         },
922
923         // General-purpose constants
924         strundefined = typeof undefined,
925         MAX_NEGATIVE = 1 << 31,
926
927         // Instance methods
928         hasOwn = ({}).hasOwnProperty,
929         arr = [],
930         pop = arr.pop,
931         push_native = arr.push,
932         push = arr.push,
933         slice = arr.slice,
934         // Use a stripped-down indexOf if we can't use a native one
935         indexOf = arr.indexOf || function( elem ) {
936                 var i = 0,
937                         len = this.length;
938                 for ( ; i < len; i++ ) {
939                         if ( this[i] === elem ) {
940                                 return i;
941                         }
942                 }
943                 return -1;
944         },
945
946         booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
947
948         // Regular expressions
949
950         // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace
951         whitespace = "[\\x20\\t\\r\\n\\f]",
952         // http://www.w3.org/TR/css3-syntax/#characters
953         characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
954
955         // Loosely modeled on CSS identifier characters
956         // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors
957         // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
958         identifier = characterEncoding.replace( "w", "w#" ),
959
960         // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors
961         attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace +
962                 "*(?:([*^$|!~]?=)" + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]",
963
964         // Prefer arguments quoted,
965         //   then not containing pseudos/brackets,
966         //   then attribute selectors/non-parenthetical expressions,
967         //   then anything else
968         // These preferences are here to reduce the number of selectors
969         //   needing tokenize in the PSEUDO preFilter
970         pseudos = ":(" + characterEncoding + ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + attributes.replace( 3, 8 ) + ")*)|.*)\\)|)",
971
972         // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
973         rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
974
975         rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
976         rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
977
978         rsibling = new RegExp( whitespace + "*[+~]" ),
979         rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*)" + whitespace + "*\\]", "g" ),
980
981         rpseudo = new RegExp( pseudos ),
982         ridentifier = new RegExp( "^" + identifier + "$" ),
983
984         matchExpr = {
985                 "ID": new RegExp( "^#(" + characterEncoding + ")" ),
986                 "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
987                 "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ),
988                 "ATTR": new RegExp( "^" + attributes ),
989                 "PSEUDO": new RegExp( "^" + pseudos ),
990                 "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
991                         "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
992                         "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
993                 "bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
994                 // For use in libraries implementing .is()
995                 // We use this for POS matching in `select`
996                 "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
997                         whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
998         },
999
1000         rnative = /^[^{]+\{\s*\[native \w/,
1001
1002         // Easily-parseable/retrievable ID or TAG or CLASS selectors
1003         rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
1004
1005         rinputs = /^(?:input|select|textarea|button)$/i,
1006         rheader = /^h\d$/i,
1007
1008         rescape = /'|\\/g,
1009
1010         // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
1011         runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
1012         funescape = function( _, escaped, escapedWhitespace ) {
1013                 var high = "0x" + escaped - 0x10000;
1014                 // NaN means non-codepoint
1015                 // Support: Firefox
1016                 // Workaround erroneous numeric interpretation of +"0x"
1017                 return high !== high || escapedWhitespace ?
1018                         escaped :
1019                         // BMP codepoint
1020                         high < 0 ?
1021                                 String.fromCharCode( high + 0x10000 ) :
1022                                 // Supplemental Plane codepoint (surrogate pair)
1023                                 String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
1024         };
1025
1026 // Optimize for push.apply( _, NodeList )
1027 try {
1028         push.apply(
1029                 (arr = slice.call( preferredDoc.childNodes )),
1030                 preferredDoc.childNodes
1031         );
1032         // Support: Android<4.0
1033         // Detect silently failing push.apply
1034         arr[ preferredDoc.childNodes.length ].nodeType;
1035 } catch ( e ) {
1036         push = { apply: arr.length ?
1037
1038                 // Leverage slice if possible
1039                 function( target, els ) {
1040                         push_native.apply( target, slice.call(els) );
1041                 } :
1042
1043                 // Support: IE<9
1044                 // Otherwise append directly
1045                 function( target, els ) {
1046                         var j = target.length,
1047                                 i = 0;
1048                         // Can't trust NodeList.length
1049                         while ( (target[j++] = els[i++]) ) {}
1050                         target.length = j - 1;
1051                 }
1052         };
1053 }
1054
1055 function Sizzle( selector, context, results, seed ) {
1056         var match, elem, m, nodeType,
1057                 // QSA vars
1058                 i, groups, old, nid, newContext, newSelector;
1059
1060         if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
1061                 setDocument( context );
1062         }
1063
1064         context = context || document;
1065         results = results || [];
1066
1067         if ( !selector || typeof selector !== "string" ) {
1068                 return results;
1069         }
1070
1071         if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {
1072                 return [];
1073         }
1074
1075         if ( documentIsHTML && !seed ) {
1076
1077                 // Shortcuts
1078                 if ( (match = rquickExpr.exec( selector )) ) {
1079                         // Speed-up: Sizzle("#ID")
1080                         if ( (m = match[1]) ) {
1081                                 if ( nodeType === 9 ) {
1082                                         elem = context.getElementById( m );
1083                                         // Check parentNode to catch when Blackberry 4.6 returns
1084                                         // nodes that are no longer in the document #6963
1085                                         if ( elem && elem.parentNode ) {
1086                                                 // Handle the case where IE, Opera, and Webkit return items
1087                                                 // by name instead of ID
1088                                                 if ( elem.id === m ) {
1089                                                         results.push( elem );
1090                                                         return results;
1091                                                 }
1092                                         } else {
1093                                                 return results;
1094                                         }
1095                                 } else {
1096                                         // Context is not a document
1097                                         if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
1098                                                 contains( context, elem ) && elem.id === m ) {
1099                                                 results.push( elem );
1100                                                 return results;
1101                                         }
1102                                 }
1103
1104                         // Speed-up: Sizzle("TAG")
1105                         } else if ( match[2] ) {
1106                                 push.apply( results, context.getElementsByTagName( selector ) );
1107                                 return results;
1108
1109                         // Speed-up: Sizzle(".CLASS")
1110                         } else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) {
1111                                 push.apply( results, context.getElementsByClassName( m ) );
1112                                 return results;
1113                         }
1114                 }
1115
1116                 // QSA path
1117                 if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
1118                         nid = old = expando;
1119                         newContext = context;
1120                         newSelector = nodeType === 9 && selector;
1121
1122                         // qSA works strangely on Element-rooted queries
1123                         // We can work around this by specifying an extra ID on the root
1124                         // and working up from there (Thanks to Andrew Dupont for the technique)
1125                         // IE 8 doesn't work on object elements
1126                         if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
1127                                 groups = tokenize( selector );
1128
1129                                 if ( (old = context.getAttribute("id")) ) {
1130                                         nid = old.replace( rescape, "\\$&" );
1131                                 } else {
1132                                         context.setAttribute( "id", nid );
1133                                 }
1134                                 nid = "[id='" + nid + "'] ";
1135
1136                                 i = groups.length;
1137                                 while ( i-- ) {
1138                                         groups[i] = nid + toSelector( groups[i] );
1139                                 }
1140                                 newContext = rsibling.test( selector ) && context.parentNode || context;
1141                                 newSelector = groups.join(",");
1142                         }
1143
1144                         if ( newSelector ) {
1145                                 try {
1146                                         push.apply( results,
1147                                                 newContext.querySelectorAll( newSelector )
1148                                         );
1149                                         return results;
1150                                 } catch(qsaError) {
1151                                 } finally {
1152                                         if ( !old ) {
1153                                                 context.removeAttribute("id");
1154                                         }
1155                                 }
1156                         }
1157                 }
1158         }
1159
1160         // All others
1161         return select( selector.replace( rtrim, "$1" ), context, results, seed );
1162 }
1163
1164 /**
1165  * Create key-value caches of limited size
1166  * @returns {Function(string, Object)} Returns the Object data after storing it on itself with
1167  *      property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
1168  *      deleting the oldest entry
1169  */
1170 function createCache() {
1171         var keys = [];
1172
1173         function cache( key, value ) {
1174                 // Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
1175                 if ( keys.push( key += " " ) > Expr.cacheLength ) {
1176                         // Only keep the most recent entries
1177                         delete cache[ keys.shift() ];
1178                 }
1179                 return (cache[ key ] = value);
1180         }
1181         return cache;
1182 }
1183
1184 /**
1185  * Mark a function for special use by Sizzle
1186  * @param {Function} fn The function to mark
1187  */
1188 function markFunction( fn ) {
1189         fn[ expando ] = true;
1190         return fn;
1191 }
1192
1193 /**
1194  * Support testing using an element
1195  * @param {Function} fn Passed the created div and expects a boolean result
1196  */
1197 function assert( fn ) {
1198         var div = document.createElement("div");
1199
1200         try {
1201                 return !!fn( div );
1202         } catch (e) {
1203                 return false;
1204         } finally {
1205                 // Remove from its parent by default
1206                 if ( div.parentNode ) {
1207                         div.parentNode.removeChild( div );
1208                 }
1209                 // release memory in IE
1210                 div = null;
1211         }
1212 }
1213
1214 /**
1215  * Adds the same handler for all of the specified attrs
1216  * @param {String} attrs Pipe-separated list of attributes
1217  * @param {Function} handler The method that will be applied
1218  */
1219 function addHandle( attrs, handler ) {
1220         var arr = attrs.split("|"),
1221                 i = attrs.length;
1222
1223         while ( i-- ) {
1224                 Expr.attrHandle[ arr[i] ] = handler;
1225         }
1226 }
1227
1228 /**
1229  * Checks document order of two siblings
1230  * @param {Element} a
1231  * @param {Element} b
1232  * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
1233  */
1234 function siblingCheck( a, b ) {
1235         var cur = b && a,
1236                 diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
1237                         ( ~b.sourceIndex || MAX_NEGATIVE ) -
1238                         ( ~a.sourceIndex || MAX_NEGATIVE );
1239
1240         // Use IE sourceIndex if available on both nodes
1241         if ( diff ) {
1242                 return diff;
1243         }
1244
1245         // Check if b follows a
1246         if ( cur ) {
1247                 while ( (cur = cur.nextSibling) ) {
1248                         if ( cur === b ) {
1249                                 return -1;
1250                         }
1251                 }
1252         }
1253
1254         return a ? 1 : -1;
1255 }
1256
1257 /**
1258  * Returns a function to use in pseudos for input types
1259  * @param {String} type
1260  */
1261 function createInputPseudo( type ) {
1262         return function( elem ) {
1263                 var name = elem.nodeName.toLowerCase();
1264                 return name === "input" && elem.type === type;
1265         };
1266 }
1267
1268 /**
1269  * Returns a function to use in pseudos for buttons
1270  * @param {String} type
1271  */
1272 function createButtonPseudo( type ) {
1273         return function( elem ) {
1274                 var name = elem.nodeName.toLowerCase();
1275                 return (name === "input" || name === "button") && elem.type === type;
1276         };
1277 }
1278
1279 /**
1280  * Returns a function to use in pseudos for positionals
1281  * @param {Function} fn
1282  */
1283 function createPositionalPseudo( fn ) {
1284         return markFunction(function( argument ) {
1285                 argument = +argument;
1286                 return markFunction(function( seed, matches ) {
1287                         var j,
1288                                 matchIndexes = fn( [], seed.length, argument ),
1289                                 i = matchIndexes.length;
1290
1291                         // Match elements found at the specified indexes
1292                         while ( i-- ) {
1293                                 if ( seed[ (j = matchIndexes[i]) ] ) {
1294                                         seed[j] = !(matches[j] = seed[j]);
1295                                 }
1296                         }
1297                 });
1298         });
1299 }
1300
1301 /**
1302  * Detect xml
1303  * @param {Element|Object} elem An element or a document
1304  */
1305 isXML = Sizzle.isXML = function( elem ) {
1306         // documentElement is verified for cases where it doesn't yet exist
1307         // (such as loading iframes in IE - #4833)
1308         var documentElement = elem && (elem.ownerDocument || elem).documentElement;
1309         return documentElement ? documentElement.nodeName !== "HTML" : false;
1310 };
1311
1312 // Expose support vars for convenience
1313 support = Sizzle.support = {};
1314
1315 /**
1316  * Sets document-related variables once based on the current document
1317  * @param {Element|Object} [doc] An element or document object to use to set the document
1318  * @returns {Object} Returns the current document
1319  */
1320 setDocument = Sizzle.setDocument = function( node ) {
1321         var doc = node ? node.ownerDocument || node : preferredDoc,
1322                 parent = doc.defaultView;
1323
1324         // If no document and documentElement is available, return
1325         if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
1326                 return document;
1327         }
1328
1329         // Set our document
1330         document = doc;
1331         docElem = doc.documentElement;
1332
1333         // Support tests
1334         documentIsHTML = !isXML( doc );
1335
1336         // Support: IE>8
1337         // If iframe document is assigned to "document" variable and if iframe has been reloaded,
1338         // IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936
1339         // IE6-8 do not support the defaultView property so parent will be undefined
1340         if ( parent && parent.attachEvent && parent !== parent.top ) {
1341                 parent.attachEvent( "onbeforeunload", function() {
1342                         setDocument();
1343                 });
1344         }
1345
1346         /* Attributes
1347         ---------------------------------------------------------------------- */
1348
1349         // Support: IE<8
1350         // Verify that getAttribute really returns attributes and not properties (excepting IE8 booleans)
1351         support.attributes = assert(function( div ) {
1352                 div.className = "i";
1353                 return !div.getAttribute("className");
1354         });
1355
1356         /* getElement(s)By*
1357         ---------------------------------------------------------------------- */
1358
1359         // Check if getElementsByTagName("*") returns only elements
1360         support.getElementsByTagName = assert(function( div ) {
1361                 div.appendChild( doc.createComment("") );
1362                 return !div.getElementsByTagName("*").length;
1363         });
1364
1365         // Check if getElementsByClassName can be trusted
1366         support.getElementsByClassName = assert(function( div ) {
1367                 div.innerHTML = "<div class='a'></div><div class='a i'></div>";
1368
1369                 // Support: Safari<4
1370                 // Catch class over-caching
1371                 div.firstChild.className = "i";
1372                 // Support: Opera<10
1373                 // Catch gEBCN failure to find non-leading classes
1374                 return div.getElementsByClassName("i").length === 2;
1375         });
1376
1377         // Support: IE<10
1378         // Check if getElementById returns elements by name
1379         // The broken getElementById methods don't pick up programatically-set names,
1380         // so use a roundabout getElementsByName test
1381         support.getById = assert(function( div ) {
1382                 docElem.appendChild( div ).id = expando;
1383                 return !doc.getElementsByName || !doc.getElementsByName( expando ).length;
1384         });
1385
1386         // ID find and filter
1387         if ( support.getById ) {
1388                 Expr.find["ID"] = function( id, context ) {
1389                         if ( typeof context.getElementById !== strundefined && documentIsHTML ) {
1390                                 var m = context.getElementById( id );
1391                                 // Check parentNode to catch when Blackberry 4.6 returns
1392                                 // nodes that are no longer in the document #6963
1393                                 return m && m.parentNode ? [m] : [];
1394                         }
1395                 };
1396                 Expr.filter["ID"] = function( id ) {
1397                         var attrId = id.replace( runescape, funescape );
1398                         return function( elem ) {
1399                                 return elem.getAttribute("id") === attrId;
1400                         };
1401                 };
1402         } else {
1403                 // Support: IE6/7
1404                 // getElementById is not reliable as a find shortcut
1405                 delete Expr.find["ID"];
1406
1407                 Expr.filter["ID"] =  function( id ) {
1408                         var attrId = id.replace( runescape, funescape );
1409                         return function( elem ) {
1410                                 var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
1411                                 return node && node.value === attrId;
1412                         };
1413                 };
1414         }
1415
1416         // Tag
1417         Expr.find["TAG"] = support.getElementsByTagName ?
1418                 function( tag, context ) {
1419                         if ( typeof context.getElementsByTagName !== strundefined ) {
1420                                 return context.getElementsByTagName( tag );
1421                         }
1422                 } :
1423                 function( tag, context ) {
1424                         var elem,
1425                                 tmp = [],
1426                                 i = 0,
1427                                 results = context.getElementsByTagName( tag );
1428
1429                         // Filter out possible comments
1430                         if ( tag === "*" ) {
1431                                 while ( (elem = results[i++]) ) {
1432                                         if ( elem.nodeType === 1 ) {
1433                                                 tmp.push( elem );
1434                                         }
1435                                 }
1436
1437                                 return tmp;
1438                         }
1439                         return results;
1440                 };
1441
1442         // Class
1443         Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
1444                 if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) {
1445                         return context.getElementsByClassName( className );
1446                 }
1447         };
1448
1449         /* QSA/matchesSelector
1450         ---------------------------------------------------------------------- */
1451
1452         // QSA and matchesSelector support
1453
1454         // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
1455         rbuggyMatches = [];
1456
1457         // qSa(:focus) reports false when true (Chrome 21)
1458         // We allow this because of a bug in IE8/9 that throws an error
1459         // whenever `document.activeElement` is accessed on an iframe
1460         // So, we allow :focus to pass through QSA all the time to avoid the IE error
1461         // See http://bugs.jquery.com/ticket/13378
1462         rbuggyQSA = [];
1463
1464         if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) {
1465                 // Build QSA regex
1466                 // Regex strategy adopted from Diego Perini
1467                 assert(function( div ) {
1468                         // Select is set to empty string on purpose
1469                         // This is to test IE's treatment of not explicitly
1470                         // setting a boolean content attribute,
1471                         // since its presence should be enough
1472                         // http://bugs.jquery.com/ticket/12359
1473                         div.innerHTML = "<select><option selected=''></option></select>";
1474
1475                         // Support: IE8
1476                         // Boolean attributes and "value" are not treated correctly
1477                         if ( !div.querySelectorAll("[selected]").length ) {
1478                                 rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
1479                         }
1480
1481                         // Webkit/Opera - :checked should return selected option elements
1482                         // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
1483                         // IE8 throws error here and will not see later tests
1484                         if ( !div.querySelectorAll(":checked").length ) {
1485                                 rbuggyQSA.push(":checked");
1486                         }
1487                 });
1488
1489                 assert(function( div ) {
1490
1491                         // Support: Opera 10-12/IE8
1492                         // ^= $= *= and empty values
1493                         // Should not select anything
1494                         // Support: Windows 8 Native Apps
1495                         // The type attribute is restricted during .innerHTML assignment
1496                         var input = doc.createElement("input");
1497                         input.setAttribute( "type", "hidden" );
1498                         div.appendChild( input ).setAttribute( "t", "" );
1499
1500                         if ( div.querySelectorAll("[t^='']").length ) {
1501                                 rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
1502                         }
1503
1504                         // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
1505                         // IE8 throws error here and will not see later tests
1506                         if ( !div.querySelectorAll(":enabled").length ) {
1507                                 rbuggyQSA.push( ":enabled", ":disabled" );
1508                         }
1509
1510                         // Opera 10-11 does not throw on post-comma invalid pseudos
1511                         div.querySelectorAll("*,:x");
1512                         rbuggyQSA.push(",.*:");
1513                 });
1514         }
1515
1516         if ( (support.matchesSelector = rnative.test( (matches = docElem.webkitMatchesSelector ||
1517                 docElem.mozMatchesSelector ||
1518                 docElem.oMatchesSelector ||
1519                 docElem.msMatchesSelector) )) ) {
1520
1521                 assert(function( div ) {
1522                         // Check to see if it's possible to do matchesSelector
1523                         // on a disconnected node (IE 9)
1524                         support.disconnectedMatch = matches.call( div, "div" );
1525
1526                         // This should fail with an exception
1527                         // Gecko does not error, returns false instead
1528                         matches.call( div, "[s!='']:x" );
1529                         rbuggyMatches.push( "!=", pseudos );
1530                 });
1531         }
1532
1533         rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
1534         rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
1535
1536         /* Contains
1537         ---------------------------------------------------------------------- */
1538
1539         // Element contains another
1540         // Purposefully does not implement inclusive descendent
1541         // As in, an element does not contain itself
1542         contains = rnative.test( docElem.contains ) || docElem.compareDocumentPosition ?
1543                 function( a, b ) {
1544                         var adown = a.nodeType === 9 ? a.documentElement : a,
1545                                 bup = b && b.parentNode;
1546                         return a === bup || !!( bup && bup.nodeType === 1 && (
1547                                 adown.contains ?
1548                                         adown.contains( bup ) :
1549                                         a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
1550                         ));
1551                 } :
1552                 function( a, b ) {
1553                         if ( b ) {
1554                                 while ( (b = b.parentNode) ) {
1555                                         if ( b === a ) {
1556                                                 return true;
1557                                         }
1558                                 }
1559                         }
1560                         return false;
1561                 };
1562
1563         /* Sorting
1564         ---------------------------------------------------------------------- */
1565
1566         // Document order sorting
1567         sortOrder = docElem.compareDocumentPosition ?
1568         function( a, b ) {
1569
1570                 // Flag for duplicate removal
1571                 if ( a === b ) {
1572                         hasDuplicate = true;
1573                         return 0;
1574                 }
1575
1576                 var compare = b.compareDocumentPosition && a.compareDocumentPosition && a.compareDocumentPosition( b );
1577
1578                 if ( compare ) {
1579                         // Disconnected nodes
1580                         if ( compare & 1 ||
1581                                 (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
1582
1583                                 // Choose the first element that is related to our preferred document
1584                                 if ( a === doc || contains(preferredDoc, a) ) {
1585                                         return -1;
1586                                 }
1587                                 if ( b === doc || contains(preferredDoc, b) ) {
1588                                         return 1;
1589                                 }
1590
1591                                 // Maintain original order
1592                                 return sortInput ?
1593                                         ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
1594                                         0;
1595                         }
1596
1597                         return compare & 4 ? -1 : 1;
1598                 }
1599
1600                 // Not directly comparable, sort on existence of method
1601                 return a.compareDocumentPosition ? -1 : 1;
1602         } :
1603         function( a, b ) {
1604                 var cur,
1605                         i = 0,
1606                         aup = a.parentNode,
1607                         bup = b.parentNode,
1608                         ap = [ a ],
1609                         bp = [ b ];
1610
1611                 // Exit early if the nodes are identical
1612                 if ( a === b ) {
1613                         hasDuplicate = true;
1614                         return 0;
1615
1616                 // Parentless nodes are either documents or disconnected
1617                 } else if ( !aup || !bup ) {
1618                         return a === doc ? -1 :
1619                                 b === doc ? 1 :
1620                                 aup ? -1 :
1621                                 bup ? 1 :
1622                                 sortInput ?
1623                                 ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
1624                                 0;
1625
1626                 // If the nodes are siblings, we can do a quick check
1627                 } else if ( aup === bup ) {
1628                         return siblingCheck( a, b );
1629                 }
1630
1631                 // Otherwise we need full lists of their ancestors for comparison
1632                 cur = a;
1633                 while ( (cur = cur.parentNode) ) {
1634                         ap.unshift( cur );
1635                 }
1636                 cur = b;
1637                 while ( (cur = cur.parentNode) ) {
1638                         bp.unshift( cur );
1639                 }
1640
1641                 // Walk down the tree looking for a discrepancy
1642                 while ( ap[i] === bp[i] ) {
1643                         i++;
1644                 }
1645
1646                 return i ?
1647                         // Do a sibling check if the nodes have a common ancestor
1648                         siblingCheck( ap[i], bp[i] ) :
1649
1650                         // Otherwise nodes in our document sort first
1651                         ap[i] === preferredDoc ? -1 :
1652                         bp[i] === preferredDoc ? 1 :
1653                         0;
1654         };
1655
1656         return doc;
1657 };
1658
1659 Sizzle.matches = function( expr, elements ) {
1660         return Sizzle( expr, null, null, elements );
1661 };
1662
1663 Sizzle.matchesSelector = function( elem, expr ) {
1664         // Set document vars if needed
1665         if ( ( elem.ownerDocument || elem ) !== document ) {
1666                 setDocument( elem );
1667         }
1668
1669         // Make sure that attribute selectors are quoted
1670         expr = expr.replace( rattributeQuotes, "='$1']" );
1671
1672         if ( support.matchesSelector && documentIsHTML &&
1673                 ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
1674                 ( !rbuggyQSA     || !rbuggyQSA.test( expr ) ) ) {
1675
1676                 try {
1677                         var ret = matches.call( elem, expr );
1678
1679                         // IE 9's matchesSelector returns false on disconnected nodes
1680                         if ( ret || support.disconnectedMatch ||
1681                                         // As well, disconnected nodes are said to be in a document
1682                                         // fragment in IE 9
1683                                         elem.document && elem.document.nodeType !== 11 ) {
1684                                 return ret;
1685                         }
1686                 } catch(e) {}
1687         }
1688
1689         return Sizzle( expr, document, null, [elem] ).length > 0;
1690 };
1691
1692 Sizzle.contains = function( context, elem ) {
1693         // Set document vars if needed
1694         if ( ( context.ownerDocument || context ) !== document ) {
1695                 setDocument( context );
1696         }
1697         return contains( context, elem );
1698 };
1699
1700 Sizzle.attr = function( elem, name ) {
1701         // Set document vars if needed
1702         if ( ( elem.ownerDocument || elem ) !== document ) {
1703                 setDocument( elem );
1704         }
1705
1706         var fn = Expr.attrHandle[ name.toLowerCase() ],
1707                 // Don't get fooled by Object.prototype properties (jQuery #13807)
1708                 val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
1709                         fn( elem, name, !documentIsHTML ) :
1710                         undefined;
1711
1712         return val === undefined ?
1713                 support.attributes || !documentIsHTML ?
1714                         elem.getAttribute( name ) :
1715                         (val = elem.getAttributeNode(name)) && val.specified ?
1716                                 val.value :
1717                                 null :
1718                 val;
1719 };
1720
1721 Sizzle.error = function( msg ) {
1722         throw new Error( "Syntax error, unrecognized expression: " + msg );
1723 };
1724
1725 /**
1726  * Document sorting and removing duplicates
1727  * @param {ArrayLike} results
1728  */
1729 Sizzle.uniqueSort = function( results ) {
1730         var elem,
1731                 duplicates = [],
1732                 j = 0,
1733                 i = 0;
1734
1735         // Unless we *know* we can detect duplicates, assume their presence
1736         hasDuplicate = !support.detectDuplicates;
1737         sortInput = !support.sortStable && results.slice( 0 );
1738         results.sort( sortOrder );
1739
1740         if ( hasDuplicate ) {
1741                 while ( (elem = results[i++]) ) {
1742                         if ( elem === results[ i ] ) {
1743                                 j = duplicates.push( i );
1744                         }
1745                 }
1746                 while ( j-- ) {
1747                         results.splice( duplicates[ j ], 1 );
1748                 }
1749         }
1750
1751         return results;
1752 };
1753
1754 /**
1755  * Utility function for retrieving the text value of an array of DOM nodes
1756  * @param {Array|Element} elem
1757  */
1758 getText = Sizzle.getText = function( elem ) {
1759         var node,
1760                 ret = "",
1761                 i = 0,
1762                 nodeType = elem.nodeType;
1763
1764         if ( !nodeType ) {
1765                 // If no nodeType, this is expected to be an array
1766                 for ( ; (node = elem[i]); i++ ) {
1767                         // Do not traverse comment nodes
1768                         ret += getText( node );
1769                 }
1770         } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
1771                 // Use textContent for elements
1772                 // innerText usage removed for consistency of new lines (see #11153)
1773                 if ( typeof elem.textContent === "string" ) {
1774                         return elem.textContent;
1775                 } else {
1776                         // Traverse its children
1777                         for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
1778                                 ret += getText( elem );
1779                         }
1780                 }
1781         } else if ( nodeType === 3 || nodeType === 4 ) {
1782                 return elem.nodeValue;
1783         }
1784         // Do not include comment or processing instruction nodes
1785
1786         return ret;
1787 };
1788
1789 Expr = Sizzle.selectors = {
1790
1791         // Can be adjusted by the user
1792         cacheLength: 50,
1793
1794         createPseudo: markFunction,
1795
1796         match: matchExpr,
1797
1798         attrHandle: {},
1799
1800         find: {},
1801
1802         relative: {
1803                 ">": { dir: "parentNode", first: true },
1804                 " ": { dir: "parentNode" },
1805                 "+": { dir: "previousSibling", first: true },
1806                 "~": { dir: "previousSibling" }
1807         },
1808
1809         preFilter: {
1810                 "ATTR": function( match ) {
1811                         match[1] = match[1].replace( runescape, funescape );
1812
1813                         // Move the given value to match[3] whether quoted or unquoted
1814                         match[3] = ( match[4] || match[5] || "" ).replace( runescape, funescape );
1815
1816                         if ( match[2] === "~=" ) {
1817                                 match[3] = " " + match[3] + " ";
1818                         }
1819
1820                         return match.slice( 0, 4 );
1821                 },
1822
1823                 "CHILD": function( match ) {
1824                         /* matches from matchExpr["CHILD"]
1825                                 1 type (only|nth|...)
1826                                 2 what (child|of-type)
1827                                 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
1828                                 4 xn-component of xn+y argument ([+-]?\d*n|)
1829                                 5 sign of xn-component
1830                                 6 x of xn-component
1831                                 7 sign of y-component
1832                                 8 y of y-component
1833                         */
1834                         match[1] = match[1].toLowerCase();
1835
1836                         if ( match[1].slice( 0, 3 ) === "nth" ) {
1837                                 // nth-* requires argument
1838                                 if ( !match[3] ) {
1839                                         Sizzle.error( match[0] );
1840                                 }
1841
1842                                 // numeric x and y parameters for Expr.filter.CHILD
1843                                 // remember that false/true cast respectively to 0/1
1844                                 match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
1845                                 match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
1846
1847                         // other types prohibit arguments
1848                         } else if ( match[3] ) {
1849                                 Sizzle.error( match[0] );
1850                         }
1851
1852                         return match;
1853                 },
1854
1855                 "PSEUDO": function( match ) {
1856                         var excess,
1857                                 unquoted = !match[5] && match[2];
1858
1859                         if ( matchExpr["CHILD"].test( match[0] ) ) {
1860                                 return null;
1861                         }
1862
1863                         // Accept quoted arguments as-is
1864                         if ( match[3] && match[4] !== undefined ) {
1865                                 match[2] = match[4];
1866
1867                         // Strip excess characters from unquoted arguments
1868                         } else if ( unquoted && rpseudo.test( unquoted ) &&
1869                                 // Get excess from tokenize (recursively)
1870                                 (excess = tokenize( unquoted, true )) &&
1871                                 // advance to the next closing parenthesis
1872                                 (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
1873
1874                                 // excess is a negative index
1875                                 match[0] = match[0].slice( 0, excess );
1876                                 match[2] = unquoted.slice( 0, excess );
1877                         }
1878
1879                         // Return only captures needed by the pseudo filter method (type and argument)
1880                         return match.slice( 0, 3 );
1881                 }
1882         },
1883
1884         filter: {
1885
1886                 "TAG": function( nodeNameSelector ) {
1887                         var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
1888                         return nodeNameSelector === "*" ?
1889                                 function() { return true; } :
1890                                 function( elem ) {
1891                                         return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
1892                                 };
1893                 },
1894
1895                 "CLASS": function( className ) {
1896                         var pattern = classCache[ className + " " ];
1897
1898                         return pattern ||
1899                                 (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
1900                                 classCache( className, function( elem ) {
1901                                         return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "" );
1902                                 });
1903                 },
1904
1905                 "ATTR": function( name, operator, check ) {
1906                         return function( elem ) {
1907                                 var result = Sizzle.attr( elem, name );
1908
1909                                 if ( result == null ) {
1910                                         return operator === "!=";
1911                                 }
1912                                 if ( !operator ) {
1913                                         return true;
1914                                 }
1915
1916                                 result += "";
1917
1918                                 return operator === "=" ? result === check :
1919                                         operator === "!=" ? result !== check :
1920                                         operator === "^=" ? check && result.indexOf( check ) === 0 :
1921                                         operator === "*=" ? check && result.indexOf( check ) > -1 :
1922                                         operator === "$=" ? check && result.slice( -check.length ) === check :
1923                                         operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 :
1924                                         operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
1925                                         false;
1926                         };
1927                 },
1928
1929                 "CHILD": function( type, what, argument, first, last ) {
1930                         var simple = type.slice( 0, 3 ) !== "nth",
1931                                 forward = type.slice( -4 ) !== "last",
1932                                 ofType = what === "of-type";
1933
1934                         return first === 1 && last === 0 ?
1935
1936                                 // Shortcut for :nth-*(n)
1937                                 function( elem ) {
1938                                         return !!elem.parentNode;
1939                                 } :
1940
1941                                 function( elem, context, xml ) {
1942                                         var cache, outerCache, node, diff, nodeIndex, start,
1943                                                 dir = simple !== forward ? "nextSibling" : "previousSibling",
1944                                                 parent = elem.parentNode,
1945                                                 name = ofType && elem.nodeName.toLowerCase(),
1946                                                 useCache = !xml && !ofType;
1947
1948                                         if ( parent ) {
1949
1950                                                 // :(first|last|only)-(child|of-type)
1951                                                 if ( simple ) {
1952                                                         while ( dir ) {
1953                                                                 node = elem;
1954                                                                 while ( (node = node[ dir ]) ) {
1955                                                                         if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {
1956                                                                                 return false;
1957                                                                         }
1958                                                                 }
1959                                                                 // Reverse direction for :only-* (if we haven't yet done so)
1960                                                                 start = dir = type === "only" && !start && "nextSibling";
1961                                                         }
1962                                                         return true;
1963                                                 }
1964
1965                                                 start = [ forward ? parent.firstChild : parent.lastChild ];
1966
1967                                                 // non-xml :nth-child(...) stores cache data on `parent`
1968                                                 if ( forward && useCache ) {
1969                                                         // Seek `elem` from a previously-cached index
1970                                                         outerCache = parent[ expando ] || (parent[ expando ] = {});
1971                                                         cache = outerCache[ type ] || [];
1972                                                         nodeIndex = cache[0] === dirruns && cache[1];
1973                                                         diff = cache[0] === dirruns && cache[2];
1974                                                         node = nodeIndex && parent.childNodes[ nodeIndex ];
1975
1976                                                         while ( (node = ++nodeIndex && node && node[ dir ] ||
1977
1978                                                                 // Fallback to seeking `elem` from the start
1979                                                                 (diff = nodeIndex = 0) || start.pop()) ) {
1980
1981                                                                 // When found, cache indexes on `parent` and break
1982                                                                 if ( node.nodeType === 1 && ++diff && node === elem ) {
1983                                                                         outerCache[ type ] = [ dirruns, nodeIndex, diff ];
1984                                                                         break;
1985                                                                 }
1986                                                         }
1987
1988                                                 // Use previously-cached element index if available
1989                                                 } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {
1990                                                         diff = cache[1];
1991
1992                                                 // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...)
1993                                                 } else {
1994                                                         // Use the same loop as above to seek `elem` from the start
1995                                                         while ( (node = ++nodeIndex && node && node[ dir ] ||
1996                                                                 (diff = nodeIndex = 0) || start.pop()) ) {
1997
1998                                                                 if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {
1999                                                                         // Cache the index of each encountered element
2000                                                                         if ( useCache ) {
2001                                                                                 (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];
2002                                                                         }
2003
2004                                                                         if ( node === elem ) {
2005                                                                                 break;
2006                                                                         }
2007                                                                 }
2008                                                         }
2009                                                 }
2010
2011                                                 // Incorporate the offset, then check against cycle size
2012                                                 diff -= last;
2013                                                 return diff === first || ( diff % first === 0 && diff / first >= 0 );
2014                                         }
2015                                 };
2016                 },
2017
2018                 "PSEUDO": function( pseudo, argument ) {
2019                         // pseudo-class names are case-insensitive
2020                         // http://www.w3.org/TR/selectors/#pseudo-classes
2021                         // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
2022                         // Remember that setFilters inherits from pseudos
2023                         var args,
2024                                 fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
2025                                         Sizzle.error( "unsupported pseudo: " + pseudo );
2026
2027                         // The user may use createPseudo to indicate that
2028                         // arguments are needed to create the filter function
2029                         // just as Sizzle does
2030                         if ( fn[ expando ] ) {
2031                                 return fn( argument );
2032                         }
2033
2034                         // But maintain support for old signatures
2035                         if ( fn.length > 1 ) {
2036                                 args = [ pseudo, pseudo, "", argument ];
2037                                 return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
2038                                         markFunction(function( seed, matches ) {
2039                                                 var idx,
2040                                                         matched = fn( seed, argument ),
2041                                                         i = matched.length;
2042                                                 while ( i-- ) {
2043                                                         idx = indexOf.call( seed, matched[i] );
2044                                                         seed[ idx ] = !( matches[ idx ] = matched[i] );
2045                                                 }
2046                                         }) :
2047                                         function( elem ) {
2048                                                 return fn( elem, 0, args );
2049                                         };
2050                         }
2051
2052                         return fn;
2053                 }
2054         },
2055
2056         pseudos: {
2057                 // Potentially complex pseudos
2058                 "not": markFunction(function( selector ) {
2059                         // Trim the selector passed to compile
2060                         // to avoid treating leading and trailing
2061                         // spaces as combinators
2062                         var input = [],
2063                                 results = [],
2064                                 matcher = compile( selector.replace( rtrim, "$1" ) );
2065
2066                         return matcher[ expando ] ?
2067                                 markFunction(function( seed, matches, context, xml ) {
2068                                         var elem,
2069                                                 unmatched = matcher( seed, null, xml, [] ),
2070                                                 i = seed.length;
2071
2072                                         // Match elements unmatched by `matcher`
2073                                         while ( i-- ) {
2074                                                 if ( (elem = unmatched[i]) ) {
2075                                                         seed[i] = !(matches[i] = elem);
2076                                                 }
2077                                         }
2078                                 }) :
2079                                 function( elem, context, xml ) {
2080                                         input[0] = elem;
2081                                         matcher( input, null, xml, results );
2082                                         return !results.pop();
2083                                 };
2084                 }),
2085
2086                 "has": markFunction(function( selector ) {
2087                         return function( elem ) {
2088                                 return Sizzle( selector, elem ).length > 0;
2089                         };
2090                 }),
2091
2092                 "contains": markFunction(function( text ) {
2093                         return function( elem ) {
2094                                 return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
2095                         };
2096                 }),
2097
2098                 // "Whether an element is represented by a :lang() selector
2099                 // is based solely on the element's language value
2100                 // being equal to the identifier C,
2101                 // or beginning with the identifier C immediately followed by "-".
2102                 // The matching of C against the element's language value is performed case-insensitively.
2103                 // The identifier C does not have to be a valid language name."
2104                 // http://www.w3.org/TR/selectors/#lang-pseudo
2105                 "lang": markFunction( function( lang ) {
2106                         // lang value must be a valid identifier
2107                         if ( !ridentifier.test(lang || "") ) {
2108                                 Sizzle.error( "unsupported lang: " + lang );
2109                         }
2110                         lang = lang.replace( runescape, funescape ).toLowerCase();
2111                         return function( elem ) {
2112                                 var elemLang;
2113                                 do {
2114                                         if ( (elemLang = documentIsHTML ?
2115                                                 elem.lang :
2116                                                 elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
2117
2118                                                 elemLang = elemLang.toLowerCase();
2119                                                 return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
2120                                         }
2121                                 } while ( (elem = elem.parentNode) && elem.nodeType === 1 );
2122                                 return false;
2123                         };
2124                 }),
2125
2126                 // Miscellaneous
2127                 "target": function( elem ) {
2128                         var hash = window.location && window.location.hash;
2129                         return hash && hash.slice( 1 ) === elem.id;
2130                 },
2131
2132                 "root": function( elem ) {
2133                         return elem === docElem;
2134                 },
2135
2136                 "focus": function( elem ) {
2137                         return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
2138                 },
2139
2140                 // Boolean properties
2141                 "enabled": function( elem ) {
2142                         return elem.disabled === false;
2143                 },
2144
2145                 "disabled": function( elem ) {
2146                         return elem.disabled === true;
2147                 },
2148
2149                 "checked": function( elem ) {
2150                         // In CSS3, :checked should return both checked and selected elements
2151                         // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
2152                         var nodeName = elem.nodeName.toLowerCase();
2153                         return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
2154                 },
2155
2156                 "selected": function( elem ) {
2157                         // Accessing this property makes selected-by-default
2158                         // options in Safari work properly
2159                         if ( elem.parentNode ) {
2160                                 elem.parentNode.selectedIndex;
2161                         }
2162
2163                         return elem.selected === true;
2164                 },
2165
2166                 // Contents
2167                 "empty": function( elem ) {
2168                         // http://www.w3.org/TR/selectors/#empty-pseudo
2169                         // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)),
2170                         //   not comment, processing instructions, or others
2171                         // Thanks to Diego Perini for the nodeName shortcut
2172                         //   Greater than "@" means alpha characters (specifically not starting with "#" or "?")
2173                         for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
2174                                 if ( elem.nodeName > "@" || elem.nodeType === 3 || elem.nodeType === 4 ) {
2175                                         return false;
2176                                 }
2177                         }
2178                         return true;
2179                 },
2180
2181                 "parent": function( elem ) {
2182                         return !Expr.pseudos["empty"]( elem );
2183                 },
2184
2185                 // Element/input types
2186                 "header": function( elem ) {
2187                         return rheader.test( elem.nodeName );
2188                 },
2189
2190                 "input": function( elem ) {
2191                         return rinputs.test( elem.nodeName );
2192                 },
2193
2194                 "button": function( elem ) {
2195                         var name = elem.nodeName.toLowerCase();
2196                         return name === "input" && elem.type === "button" || name === "button";
2197                 },
2198
2199                 "text": function( elem ) {
2200                         var attr;
2201                         // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
2202                         // use getAttribute instead to test this case
2203                         return elem.nodeName.toLowerCase() === "input" &&
2204                                 elem.type === "text" &&
2205                                 ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === elem.type );
2206                 },
2207
2208                 // Position-in-collection
2209                 "first": createPositionalPseudo(function() {
2210                         return [ 0 ];
2211                 }),
2212
2213                 "last": createPositionalPseudo(function( matchIndexes, length ) {
2214                         return [ length - 1 ];
2215                 }),
2216
2217                 "eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
2218                         return [ argument < 0 ? argument + length : argument ];
2219                 }),
2220
2221                 "even": createPositionalPseudo(function( matchIndexes, length ) {
2222                         var i = 0;
2223                         for ( ; i < length; i += 2 ) {
2224                                 matchIndexes.push( i );
2225                         }
2226                         return matchIndexes;
2227                 }),
2228
2229                 "odd": createPositionalPseudo(function( matchIndexes, length ) {
2230                         var i = 1;
2231                         for ( ; i < length; i += 2 ) {
2232                                 matchIndexes.push( i );
2233                         }
2234                         return matchIndexes;
2235                 }),
2236
2237                 "lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
2238                         var i = argument < 0 ? argument + length : argument;
2239                         for ( ; --i >= 0; ) {
2240                                 matchIndexes.push( i );
2241                         }
2242                         return matchIndexes;
2243                 }),
2244
2245                 "gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
2246                         var i = argument < 0 ? argument + length : argument;
2247                         for ( ; ++i < length; ) {
2248                                 matchIndexes.push( i );
2249                         }
2250                         return matchIndexes;
2251                 })
2252         }
2253 };
2254
2255 Expr.pseudos["nth"] = Expr.pseudos["eq"];
2256
2257 // Add button/input type pseudos
2258 for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
2259         Expr.pseudos[ i ] = createInputPseudo( i );
2260 }
2261 for ( i in { submit: true, reset: true } ) {
2262         Expr.pseudos[ i ] = createButtonPseudo( i );
2263 }
2264
2265 // Easy API for creating new setFilters
2266 function setFilters() {}
2267 setFilters.prototype = Expr.filters = Expr.pseudos;
2268 Expr.setFilters = new setFilters();
2269
2270 function tokenize( selector, parseOnly ) {
2271         var matched, match, tokens, type,
2272                 soFar, groups, preFilters,
2273                 cached = tokenCache[ selector + " " ];
2274
2275         if ( cached ) {
2276                 return parseOnly ? 0 : cached.slice( 0 );
2277         }
2278
2279         soFar = selector;
2280         groups = [];
2281         preFilters = Expr.preFilter;
2282
2283         while ( soFar ) {
2284
2285                 // Comma and first run
2286                 if ( !matched || (match = rcomma.exec( soFar )) ) {
2287                         if ( match ) {
2288                                 // Don't consume trailing commas as valid
2289                                 soFar = soFar.slice( match[0].length ) || soFar;
2290                         }
2291                         groups.push( tokens = [] );
2292                 }
2293
2294                 matched = false;
2295
2296                 // Combinators
2297                 if ( (match = rcombinators.exec( soFar )) ) {
2298                         matched = match.shift();
2299                         tokens.push({
2300                                 value: matched,
2301                                 // Cast descendant combinators to space
2302                                 type: match[0].replace( rtrim, " " )
2303                         });
2304                         soFar = soFar.slice( matched.length );
2305                 }
2306
2307                 // Filters
2308                 for ( type in Expr.filter ) {
2309                         if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
2310                                 (match = preFilters[ type ]( match ))) ) {
2311                                 matched = match.shift();
2312                                 tokens.push({
2313                                         value: matched,
2314                                         type: type,
2315                                         matches: match
2316                                 });
2317                                 soFar = soFar.slice( matched.length );
2318                         }
2319                 }
2320
2321                 if ( !matched ) {
2322                         break;
2323                 }
2324         }
2325
2326         // Return the length of the invalid excess
2327         // if we're just parsing
2328         // Otherwise, throw an error or return tokens
2329         return parseOnly ?
2330                 soFar.length :
2331                 soFar ?
2332                         Sizzle.error( selector ) :
2333                         // Cache the tokens
2334                         tokenCache( selector, groups ).slice( 0 );
2335 }
2336
2337 function toSelector( tokens ) {
2338         var i = 0,
2339                 len = tokens.length,
2340                 selector = "";
2341         for ( ; i < len; i++ ) {
2342                 selector += tokens[i].value;
2343         }
2344         return selector;
2345 }
2346
2347 function addCombinator( matcher, combinator, base ) {
2348         var dir = combinator.dir,
2349                 checkNonElements = base && dir === "parentNode",
2350                 doneName = done++;
2351
2352         return combinator.first ?
2353                 // Check against closest ancestor/preceding element
2354                 function( elem, context, xml ) {
2355                         while ( (elem = elem[ dir ]) ) {
2356                                 if ( elem.nodeType === 1 || checkNonElements ) {
2357                                         return matcher( elem, context, xml );
2358                                 }
2359                         }
2360                 } :
2361
2362                 // Check against all ancestor/preceding elements
2363                 function( elem, context, xml ) {
2364                         var data, cache, outerCache,
2365                                 dirkey = dirruns + " " + doneName;
2366
2367                         // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching
2368                         if ( xml ) {
2369                                 while ( (elem = elem[ dir ]) ) {
2370                                         if ( elem.nodeType === 1 || checkNonElements ) {
2371                                                 if ( matcher( elem, context, xml ) ) {
2372                                                         return true;
2373                                                 }
2374                                         }
2375                                 }
2376                         } else {
2377                                 while ( (elem = elem[ dir ]) ) {
2378                                         if ( elem.nodeType === 1 || checkNonElements ) {
2379                                                 outerCache = elem[ expando ] || (elem[ expando ] = {});
2380                                                 if ( (cache = outerCache[ dir ]) && cache[0] === dirkey ) {
2381                                                         if ( (data = cache[1]) === true || data === cachedruns ) {
2382                                                                 return data === true;
2383                                                         }
2384                                                 } else {
2385                                                         cache = outerCache[ dir ] = [ dirkey ];
2386                                                         cache[1] = matcher( elem, context, xml ) || cachedruns;
2387                                                         if ( cache[1] === true ) {
2388                                                                 return true;
2389                                                         }
2390                                                 }
2391                                         }
2392                                 }
2393                         }
2394                 };
2395 }
2396
2397 function elementMatcher( matchers ) {
2398         return matchers.length > 1 ?
2399                 function( elem, context, xml ) {
2400                         var i = matchers.length;
2401                         while ( i-- ) {
2402                                 if ( !matchers[i]( elem, context, xml ) ) {
2403                                         return false;
2404                                 }
2405                         }
2406                         return true;
2407                 } :
2408                 matchers[0];
2409 }
2410
2411 function condense( unmatched, map, filter, context, xml ) {
2412         var elem,
2413                 newUnmatched = [],
2414                 i = 0,
2415                 len = unmatched.length,
2416                 mapped = map != null;
2417
2418         for ( ; i < len; i++ ) {
2419                 if ( (elem = unmatched[i]) ) {
2420                         if ( !filter || filter( elem, context, xml ) ) {
2421                                 newUnmatched.push( elem );
2422                                 if ( mapped ) {
2423                                         map.push( i );
2424                                 }
2425                         }
2426                 }
2427         }
2428
2429         return newUnmatched;
2430 }
2431
2432 function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
2433         if ( postFilter && !postFilter[ expando ] ) {
2434                 postFilter = setMatcher( postFilter );
2435         }
2436         if ( postFinder && !postFinder[ expando ] ) {
2437                 postFinder = setMatcher( postFinder, postSelector );
2438         }
2439         return markFunction(function( seed, results, context, xml ) {
2440                 var temp, i, elem,
2441                         preMap = [],
2442                         postMap = [],
2443                         preexisting = results.length,
2444
2445                         // Get initial elements from seed or context
2446                         elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
2447
2448                         // Prefilter to get matcher input, preserving a map for seed-results synchronization
2449                         matcherIn = preFilter && ( seed || !selector ) ?
2450                                 condense( elems, preMap, preFilter, context, xml ) :
2451                                 elems,
2452
2453                         matcherOut = matcher ?
2454                                 // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
2455                                 postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
2456
2457                                         // ...intermediate processing is necessary
2458                                         [] :
2459
2460                                         // ...otherwise use results directly
2461                                         results :
2462                                 matcherIn;
2463
2464                 // Find primary matches
2465                 if ( matcher ) {
2466                         matcher( matcherIn, matcherOut, context, xml );
2467                 }
2468
2469                 // Apply postFilter
2470                 if ( postFilter ) {
2471                         temp = condense( matcherOut, postMap );
2472                         postFilter( temp, [], context, xml );
2473
2474                         // Un-match failing elements by moving them back to matcherIn
2475                         i = temp.length;
2476                         while ( i-- ) {
2477                                 if ( (elem = temp[i]) ) {
2478                                         matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
2479                                 }
2480                         }
2481                 }
2482
2483                 if ( seed ) {
2484                         if ( postFinder || preFilter ) {
2485                                 if ( postFinder ) {
2486                                         // Get the final matcherOut by condensing this intermediate into postFinder contexts
2487                                         temp = [];
2488                                         i = matcherOut.length;
2489                                         while ( i-- ) {
2490                                                 if ( (elem = matcherOut[i]) ) {
2491                                                         // Restore matcherIn since elem is not yet a final match
2492                                                         temp.push( (matcherIn[i] = elem) );
2493                                                 }
2494                                         }
2495                                         postFinder( null, (matcherOut = []), temp, xml );
2496                                 }
2497
2498                                 // Move matched elements from seed to results to keep them synchronized
2499                                 i = matcherOut.length;
2500                                 while ( i-- ) {
2501                                         if ( (elem = matcherOut[i]) &&
2502                                                 (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
2503
2504                                                 seed[temp] = !(results[temp] = elem);
2505                                         }
2506                                 }
2507                         }
2508
2509                 // Add elements to results, through postFinder if defined
2510                 } else {
2511                         matcherOut = condense(
2512                                 matcherOut === results ?
2513                                         matcherOut.splice( preexisting, matcherOut.length ) :
2514                                         matcherOut
2515                         );
2516                         if ( postFinder ) {
2517                                 postFinder( null, results, matcherOut, xml );
2518                         } else {
2519                                 push.apply( results, matcherOut );
2520                         }
2521                 }
2522         });
2523 }
2524
2525 function matcherFromTokens( tokens ) {
2526         var checkContext, matcher, j,
2527                 len = tokens.length,
2528                 leadingRelative = Expr.relative[ tokens[0].type ],
2529                 implicitRelative = leadingRelative || Expr.relative[" "],
2530                 i = leadingRelative ? 1 : 0,
2531
2532                 // The foundational matcher ensures that elements are reachable from top-level context(s)
2533                 matchContext = addCombinator( function( elem ) {
2534                         return elem === checkContext;
2535                 }, implicitRelative, true ),
2536                 matchAnyContext = addCombinator( function( elem ) {
2537                         return indexOf.call( checkContext, elem ) > -1;
2538                 }, implicitRelative, true ),
2539                 matchers = [ function( elem, context, xml ) {
2540                         return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
2541                                 (checkContext = context).nodeType ?
2542                                         matchContext( elem, context, xml ) :
2543                                         matchAnyContext( elem, context, xml ) );
2544                 } ];
2545
2546         for ( ; i < len; i++ ) {
2547                 if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
2548                         matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
2549                 } else {
2550                         matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
2551
2552                         // Return special upon seeing a positional matcher
2553                         if ( matcher[ expando ] ) {
2554                                 // Find the next relative operator (if any) for proper handling
2555                                 j = ++i;
2556                                 for ( ; j < len; j++ ) {
2557                                         if ( Expr.relative[ tokens[j].type ] ) {
2558                                                 break;
2559                                         }
2560                                 }
2561                                 return setMatcher(
2562                                         i > 1 && elementMatcher( matchers ),
2563                                         i > 1 && toSelector(
2564                                                 // If the preceding token was a descendant combinator, insert an implicit any-element `*`
2565                                                 tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
2566                                         ).replace( rtrim, "$1" ),
2567                                         matcher,
2568                                         i < j && matcherFromTokens( tokens.slice( i, j ) ),
2569                                         j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
2570                                         j < len && toSelector( tokens )
2571                                 );
2572                         }
2573                         matchers.push( matcher );
2574                 }
2575         }
2576
2577         return elementMatcher( matchers );
2578 }
2579
2580 function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
2581         // A counter to specify which element is currently being matched
2582         var matcherCachedRuns = 0,
2583                 bySet = setMatchers.length > 0,
2584                 byElement = elementMatchers.length > 0,
2585                 superMatcher = function( seed, context, xml, results, expandContext ) {
2586                         var elem, j, matcher,
2587                                 setMatched = [],
2588                                 matchedCount = 0,
2589                                 i = "0",
2590                                 unmatched = seed && [],
2591                                 outermost = expandContext != null,
2592                                 contextBackup = outermostContext,
2593                                 // We must always have either seed elements or context
2594                                 elems = seed || byElement && Expr.find["TAG"]( "*", expandContext && context.parentNode || context ),
2595                                 // Use integer dirruns iff this is the outermost matcher
2596                                 dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1);
2597
2598                         if ( outermost ) {
2599                                 outermostContext = context !== document && context;
2600                                 cachedruns = matcherCachedRuns;
2601                         }
2602
2603                         // Add elements passing elementMatchers directly to results
2604                         // Keep `i` a string if there are no elements so `matchedCount` will be "00" below
2605                         for ( ; (elem = elems[i]) != null; i++ ) {
2606                                 if ( byElement && elem ) {
2607                                         j = 0;
2608                                         while ( (matcher = elementMatchers[j++]) ) {
2609                                                 if ( matcher( elem, context, xml ) ) {
2610                                                         results.push( elem );
2611                                                         break;
2612                                                 }
2613                                         }
2614                                         if ( outermost ) {
2615                                                 dirruns = dirrunsUnique;
2616                                                 cachedruns = ++matcherCachedRuns;
2617                                         }
2618                                 }
2619
2620                                 // Track unmatched elements for set filters
2621                                 if ( bySet ) {
2622                                         // They will have gone through all possible matchers
2623                                         if ( (elem = !matcher && elem) ) {
2624                                                 matchedCount--;
2625                                         }
2626
2627                                         // Lengthen the array for every element, matched or not
2628                                         if ( seed ) {
2629                                                 unmatched.push( elem );
2630                                         }
2631                                 }
2632                         }
2633
2634                         // Apply set filters to unmatched elements
2635                         matchedCount += i;
2636                         if ( bySet && i !== matchedCount ) {
2637                                 j = 0;
2638                                 while ( (matcher = setMatchers[j++]) ) {
2639                                         matcher( unmatched, setMatched, context, xml );
2640                                 }
2641
2642                                 if ( seed ) {
2643                                         // Reintegrate element matches to eliminate the need for sorting
2644                                         if ( matchedCount > 0 ) {
2645                                                 while ( i-- ) {
2646                                                         if ( !(unmatched[i] || setMatched[i]) ) {
2647                                                                 setMatched[i] = pop.call( results );
2648                                                         }
2649                                                 }
2650                                         }
2651
2652                                         // Discard index placeholder values to get only actual matches
2653                                         setMatched = condense( setMatched );
2654                                 }
2655
2656                                 // Add matches to results
2657                                 push.apply( results, setMatched );
2658
2659                                 // Seedless set matches succeeding multiple successful matchers stipulate sorting
2660                                 if ( outermost && !seed && setMatched.length > 0 &&
2661                                         ( matchedCount + setMatchers.length ) > 1 ) {
2662
2663                                         Sizzle.uniqueSort( results );
2664                                 }
2665                         }
2666
2667                         // Override manipulation of globals by nested matchers
2668                         if ( outermost ) {
2669                                 dirruns = dirrunsUnique;
2670                                 outermostContext = contextBackup;
2671                         }
2672
2673                         return unmatched;
2674                 };
2675
2676         return bySet ?
2677                 markFunction( superMatcher ) :
2678                 superMatcher;
2679 }
2680
2681 compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) {
2682         var i,
2683                 setMatchers = [],
2684                 elementMatchers = [],
2685                 cached = compilerCache[ selector + " " ];
2686
2687         if ( !cached ) {
2688                 // Generate a function of recursive functions that can be used to check each element
2689                 if ( !group ) {
2690                         group = tokenize( selector );
2691                 }
2692                 i = group.length;
2693                 while ( i-- ) {
2694                         cached = matcherFromTokens( group[i] );
2695                         if ( cached[ expando ] ) {
2696                                 setMatchers.push( cached );
2697                         } else {
2698                                 elementMatchers.push( cached );
2699                         }
2700                 }
2701
2702                 // Cache the compiled function
2703                 cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
2704         }
2705         return cached;
2706 };
2707
2708 function multipleContexts( selector, contexts, results ) {
2709         var i = 0,
2710                 len = contexts.length;
2711         for ( ; i < len; i++ ) {
2712                 Sizzle( selector, contexts[i], results );
2713         }
2714         return results;
2715 }
2716
2717 function select( selector, context, results, seed ) {
2718         var i, tokens, token, type, find,
2719                 match = tokenize( selector );
2720
2721         if ( !seed ) {
2722                 // Try to minimize operations if there is only one group
2723                 if ( match.length === 1 ) {
2724
2725                         // Take a shortcut and set the context if the root selector is an ID
2726                         tokens = match[0] = match[0].slice( 0 );
2727                         if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
2728                                         support.getById && context.nodeType === 9 && documentIsHTML &&
2729                                         Expr.relative[ tokens[1].type ] ) {
2730
2731                                 context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
2732                                 if ( !context ) {
2733                                         return results;
2734                                 }
2735                                 selector = selector.slice( tokens.shift().value.length );
2736                         }
2737
2738                         // Fetch a seed set for right-to-left matching
2739                         i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
2740                         while ( i-- ) {
2741                                 token = tokens[i];
2742
2743                                 // Abort if we hit a combinator
2744                                 if ( Expr.relative[ (type = token.type) ] ) {
2745                                         break;
2746                                 }
2747                                 if ( (find = Expr.find[ type ]) ) {
2748                                         // Search, expanding context for leading sibling combinators
2749                                         if ( (seed = find(
2750                                                 token.matches[0].replace( runescape, funescape ),
2751                                                 rsibling.test( tokens[0].type ) && context.parentNode || context
2752                                         )) ) {
2753
2754                                                 // If seed is empty or no tokens remain, we can return early
2755                                                 tokens.splice( i, 1 );
2756                                                 selector = seed.length && toSelector( tokens );
2757                                                 if ( !selector ) {
2758                                                         push.apply( results, seed );
2759                                                         return results;
2760                                                 }
2761
2762                                                 break;
2763                                         }
2764                                 }
2765                         }
2766                 }
2767         }
2768
2769         // Compile and execute a filtering function
2770         // Provide `match` to avoid retokenization if we modified the selector above
2771         compile( selector, match )(
2772                 seed,
2773                 context,
2774                 !documentIsHTML,
2775                 results,
2776                 rsibling.test( selector )
2777         );
2778         return results;
2779 }
2780
2781 // One-time assignments
2782
2783 // Sort stability
2784 support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
2785
2786 // Support: Chrome<14
2787 // Always assume duplicates if they aren't passed to the comparison function
2788 support.detectDuplicates = hasDuplicate;
2789
2790 // Initialize against the default document
2791 setDocument();
2792
2793 // Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
2794 // Detached nodes confoundingly follow *each other*
2795 support.sortDetached = assert(function( div1 ) {
2796         // Should return 1, but returns 4 (following)
2797         return div1.compareDocumentPosition( document.createElement("div") ) & 1;
2798 });
2799
2800 // Support: IE<8
2801 // Prevent attribute/property "interpolation"
2802 // http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
2803 if ( !assert(function( div ) {
2804         div.innerHTML = "<a href='#'></a>";
2805         return div.firstChild.getAttribute("href") === "#" ;
2806 }) ) {
2807         addHandle( "type|href|height|width", function( elem, name, isXML ) {
2808                 if ( !isXML ) {
2809                         return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
2810                 }
2811         });
2812 }
2813
2814 // Support: IE<9
2815 // Use defaultValue in place of getAttribute("value")
2816 if ( !support.attributes || !assert(function( div ) {
2817         div.innerHTML = "<input/>";
2818         div.firstChild.setAttribute( "value", "" );
2819         return div.firstChild.getAttribute( "value" ) === "";
2820 }) ) {
2821         addHandle( "value", function( elem, name, isXML ) {
2822                 if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
2823                         return elem.defaultValue;
2824                 }
2825         });
2826 }
2827
2828 // Support: IE<9
2829 // Use getAttributeNode to fetch booleans when getAttribute lies
2830 if ( !assert(function( div ) {
2831         return div.getAttribute("disabled") == null;
2832 }) ) {
2833         addHandle( booleans, function( elem, name, isXML ) {
2834                 var val;
2835                 if ( !isXML ) {
2836                         return (val = elem.getAttributeNode( name )) && val.specified ?
2837                                 val.value :
2838                                 elem[ name ] === true ? name.toLowerCase() : null;
2839                 }
2840         });
2841 }
2842
2843 jQuery.find = Sizzle;
2844 jQuery.expr = Sizzle.selectors;
2845 jQuery.expr[":"] = jQuery.expr.pseudos;
2846 jQuery.unique = Sizzle.uniqueSort;
2847 jQuery.text = Sizzle.getText;
2848 jQuery.isXMLDoc = Sizzle.isXML;
2849 jQuery.contains = Sizzle.contains;
2850
2851
2852 })( window );
2853 // String to Object options format cache
2854 var optionsCache = {};
2855
2856 // Convert String-formatted options into Object-formatted ones and store in cache
2857 function createOptions( options ) {
2858         var object = optionsCache[ options ] = {};
2859         jQuery.each( options.match( core_rnotwhite ) || [], function( _, flag ) {
2860                 object[ flag ] = true;
2861         });
2862         return object;
2863 }
2864
2865 /*
2866  * Create a callback list using the following parameters:
2867  *
2868  *      options: an optional list of space-separated options that will change how
2869  *                      the callback list behaves or a more traditional option object
2870  *
2871  * By default a callback list will act like an event callback list and can be
2872  * "fired" multiple times.
2873  *
2874  * Possible options:
2875  *
2876  *      once:                   will ensure the callback list can only be fired once (like a Deferred)
2877  *
2878  *      memory:                 will keep track of previous values and will call any callback added
2879  *                                      after the list has been fired right away with the latest "memorized"
2880  *                                      values (like a Deferred)
2881  *
2882  *      unique:                 will ensure a callback can only be added once (no duplicate in the list)
2883  *
2884  *      stopOnFalse:    interrupt callings when a callback returns false
2885  *
2886  */
2887 jQuery.Callbacks = function( options ) {
2888
2889         // Convert options from String-formatted to Object-formatted if needed
2890         // (we check in cache first)
2891         options = typeof options === "string" ?
2892                 ( optionsCache[ options ] || createOptions( options ) ) :
2893                 jQuery.extend( {}, options );
2894
2895         var // Last fire value (for non-forgettable lists)
2896                 memory,
2897                 // Flag to know if list was already fired
2898                 fired,
2899                 // Flag to know if list is currently firing
2900                 firing,
2901                 // First callback to fire (used internally by add and fireWith)
2902                 firingStart,
2903                 // End of the loop when firing
2904                 firingLength,
2905                 // Index of currently firing callback (modified by remove if needed)
2906                 firingIndex,
2907                 // Actual callback list
2908                 list = [],
2909                 // Stack of fire calls for repeatable lists
2910                 stack = !options.once && [],
2911                 // Fire callbacks
2912                 fire = function( data ) {
2913                         memory = options.memory && data;
2914                         fired = true;
2915                         firingIndex = firingStart || 0;
2916                         firingStart = 0;
2917                         firingLength = list.length;
2918                         firing = true;
2919                         for ( ; list && firingIndex < firingLength; firingIndex++ ) {
2920                                 if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
2921                                         memory = false; // To prevent further calls using add
2922                                         break;
2923                                 }
2924                         }
2925                         firing = false;
2926                         if ( list ) {
2927                                 if ( stack ) {
2928                                         if ( stack.length ) {
2929                                                 fire( stack.shift() );
2930                                         }
2931                                 } else if ( memory ) {
2932                                         list = [];
2933                                 } else {
2934                                         self.disable();
2935                                 }
2936                         }
2937                 },
2938                 // Actual Callbacks object
2939                 self = {
2940                         // Add a callback or a collection of callbacks to the list
2941                         add: function() {
2942                                 if ( list ) {
2943                                         // First, we save the current length
2944                                         var start = list.length;
2945                                         (function add( args ) {
2946                                                 jQuery.each( args, function( _, arg ) {
2947                                                         var type = jQuery.type( arg );
2948                                                         if ( type === "function" ) {
2949                                                                 if ( !options.unique || !self.has( arg ) ) {
2950                                                                         list.push( arg );
2951                                                                 }
2952                                                         } else if ( arg && arg.length && type !== "string" ) {
2953                                                                 // Inspect recursively
2954                                                                 add( arg );
2955                                                         }
2956                                                 });
2957                                         })( arguments );
2958                                         // Do we need to add the callbacks to the
2959                                         // current firing batch?
2960                                         if ( firing ) {
2961                                                 firingLength = list.length;
2962                                         // With memory, if we're not firing then
2963                                         // we should call right away
2964                                         } else if ( memory ) {
2965                                                 firingStart = start;
2966                                                 fire( memory );
2967                                         }
2968                                 }
2969                                 return this;
2970                         },
2971                         // Remove a callback from the list
2972                         remove: function() {
2973                                 if ( list ) {
2974                                         jQuery.each( arguments, function( _, arg ) {
2975                                                 var index;
2976                                                 while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
2977                                                         list.splice( index, 1 );
2978                                                         // Handle firing indexes
2979                                                         if ( firing ) {
2980                                                                 if ( index <= firingLength ) {
2981                                                                         firingLength--;
2982                                                                 }
2983                                                                 if ( index <= firingIndex ) {
2984                                                                         firingIndex--;
2985                                                                 }
2986                                                         }
2987                                                 }
2988                                         });
2989                                 }
2990                                 return this;
2991                         },
2992                         // Check if a given callback is in the list.
2993                         // If no argument is given, return whether or not list has callbacks attached.
2994                         has: function( fn ) {
2995                                 return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );
2996                         },
2997                         // Remove all callbacks from the list
2998                         empty: function() {
2999                                 list = [];
3000                                 firingLength = 0;
3001                                 return this;
3002                         },
3003                         // Have the list do nothing anymore
3004                         disable: function() {
3005                                 list = stack = memory = undefined;
3006                                 return this;
3007                         },
3008                         // Is it disabled?
3009                         disabled: function() {
3010                                 return !list;
3011                         },
3012                         // Lock the list in its current state
3013                         lock: function() {
3014                                 stack = undefined;
3015                                 if ( !memory ) {
3016                                         self.disable();
3017                                 }
3018                                 return this;
3019                         },
3020                         // Is it locked?
3021                         locked: function() {
3022                                 return !stack;
3023                         },
3024                         // Call all callbacks with the given context and arguments
3025                         fireWith: function( context, args ) {
3026                                 if ( list && ( !fired || stack ) ) {
3027                                         args = args || [];
3028                                         args = [ context, args.slice ? args.slice() : args ];
3029                                         if ( firing ) {
3030                                                 stack.push( args );
3031                                         } else {
3032                                                 fire( args );
3033                                         }
3034                                 }
3035                                 return this;
3036                         },
3037                         // Call all the callbacks with the given arguments
3038                         fire: function() {
3039                                 self.fireWith( this, arguments );
3040                                 return this;
3041                         },
3042                         // To know if the callbacks have already been called at least once
3043                         fired: function() {
3044                                 return !!fired;
3045                         }
3046                 };
3047
3048         return self;
3049 };
3050 jQuery.extend({
3051
3052         Deferred: function( func ) {
3053                 var tuples = [
3054                                 // action, add listener, listener list, final state
3055                                 [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
3056                                 [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
3057                                 [ "notify", "progress", jQuery.Callbacks("memory") ]
3058                         ],
3059                         state = "pending",
3060                         promise = {
3061                                 state: function() {
3062                                         return state;
3063                                 },
3064                                 always: function() {
3065                                         deferred.done( arguments ).fail( arguments );
3066                                         return this;
3067                                 },
3068                                 then: function( /* fnDone, fnFail, fnProgress */ ) {
3069                                         var fns = arguments;
3070                                         return jQuery.Deferred(function( newDefer ) {
3071                                                 jQuery.each( tuples, function( i, tuple ) {
3072                                                         var action = tuple[ 0 ],
3073                                                                 fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
3074                                                         // deferred[ done | fail | progress ] for forwarding actions to newDefer
3075                                                         deferred[ tuple[1] ](function() {
3076                                                                 var returned = fn && fn.apply( this, arguments );
3077                                                                 if ( returned && jQuery.isFunction( returned.promise ) ) {
3078                                                                         returned.promise()
3079                                                                                 .done( newDefer.resolve )
3080                                                                                 .fail( newDefer.reject )
3081                                                                                 .progress( newDefer.notify );
3082                                                                 } else {
3083                                                                         newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
3084                                                                 }
3085                                                         });
3086                                                 });
3087                                                 fns = null;
3088                                         }).promise();
3089                                 },
3090                                 // Get a promise for this deferred
3091                                 // If obj is provided, the promise aspect is added to the object
3092                                 promise: function( obj ) {
3093                                         return obj != null ? jQuery.extend( obj, promise ) : promise;
3094                                 }
3095                         },
3096                         deferred = {};
3097
3098                 // Keep pipe for back-compat
3099                 promise.pipe = promise.then;
3100
3101                 // Add list-specific methods
3102                 jQuery.each( tuples, function( i, tuple ) {
3103                         var list = tuple[ 2 ],
3104                                 stateString = tuple[ 3 ];
3105
3106                         // promise[ done | fail | progress ] = list.add
3107                         promise[ tuple[1] ] = list.add;
3108
3109                         // Handle state
3110                         if ( stateString ) {
3111                                 list.add(function() {
3112                                         // state = [ resolved | rejected ]
3113                                         state = stateString;
3114
3115                                 // [ reject_list | resolve_list ].disable; progress_list.lock
3116                                 }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
3117                         }
3118
3119                         // deferred[ resolve | reject | notify ]
3120                         deferred[ tuple[0] ] = function() {
3121                                 deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
3122                                 return this;
3123                         };
3124                         deferred[ tuple[0] + "With" ] = list.fireWith;
3125                 });
3126
3127                 // Make the deferred a promise
3128                 promise.promise( deferred );
3129
3130                 // Call given func if any
3131                 if ( func ) {
3132                         func.call( deferred, deferred );
3133                 }
3134
3135                 // All done!
3136                 return deferred;
3137         },
3138
3139         // Deferred helper
3140         when: function( subordinate /* , ..., subordinateN */ ) {
3141                 var i = 0,
3142                         resolveValues = core_slice.call( arguments ),
3143                         length = resolveValues.length,
3144
3145                         // the count of uncompleted subordinates
3146                         remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
3147
3148                         // the master Deferred. If resolveValues consist of only a single Deferred, just use that.
3149                         deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
3150
3151                         // Update function for both resolve and progress values
3152                         updateFunc = function( i, contexts, values ) {
3153                                 return function( value ) {
3154                                         contexts[ i ] = this;
3155                                         values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value;
3156                                         if( values === progressValues ) {
3157                                                 deferred.notifyWith( contexts, values );
3158                                         } else if ( !( --remaining ) ) {
3159                                                 deferred.resolveWith( contexts, values );
3160                                         }
3161                                 };
3162                         },
3163
3164                         progressValues, progressContexts, resolveContexts;
3165
3166                 // add listeners to Deferred subordinates; treat others as resolved
3167                 if ( length > 1 ) {
3168                         progressValues = new Array( length );
3169                         progressContexts = new Array( length );
3170                         resolveContexts = new Array( length );
3171                         for ( ; i < length; i++ ) {
3172                                 if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
3173                                         resolveValues[ i ].promise()
3174                                                 .done( updateFunc( i, resolveContexts, resolveValues ) )
3175                                                 .fail( deferred.reject )
3176                                                 .progress( updateFunc( i, progressContexts, progressValues ) );
3177                                 } else {
3178                                         --remaining;
3179                                 }
3180                         }
3181                 }
3182
3183                 // if we're not waiting on anything, resolve the master
3184                 if ( !remaining ) {
3185                         deferred.resolveWith( resolveContexts, resolveValues );
3186                 }
3187
3188                 return deferred.promise();
3189         }
3190 });
3191 jQuery.support = (function( support ) {
3192         var input = document.createElement("input"),
3193                 fragment = document.createDocumentFragment(),
3194                 div = document.createElement("div"),
3195                 select = document.createElement("select"),
3196                 opt = select.appendChild( document.createElement("option") );
3197
3198         // Finish early in limited environments
3199         if ( !input.type ) {
3200                 return support;
3201         }
3202
3203         input.type = "checkbox";
3204
3205         // Support: Safari 5.1, iOS 5.1, Android 4.x, Android 2.3
3206         // Check the default checkbox/radio value ("" on old WebKit; "on" elsewhere)
3207         support.checkOn = input.value !== "";
3208
3209         // Must access the parent to make an option select properly
3210         // Support: IE9, IE10
3211         support.optSelected = opt.selected;
3212
3213         // Will be defined later
3214         support.reliableMarginRight = true;
3215         support.boxSizingReliable = true;
3216         support.pixelPosition = false;
3217
3218         // Make sure checked status is properly cloned
3219         // Support: IE9, IE10
3220         input.checked = true;
3221         support.noCloneChecked = input.cloneNode( true ).checked;
3222
3223         // Make sure that the options inside disabled selects aren't marked as disabled
3224         // (WebKit marks them as disabled)
3225         select.disabled = true;
3226         support.optDisabled = !opt.disabled;
3227
3228         // Check if an input maintains its value after becoming a radio
3229         // Support: IE9, IE10
3230         input = document.createElement("input");
3231         input.value = "t";
3232         input.type = "radio";
3233         support.radioValue = input.value === "t";
3234
3235         // #11217 - WebKit loses check when the name is after the checked attribute
3236         input.setAttribute( "checked", "t" );
3237         input.setAttribute( "name", "t" );
3238
3239         fragment.appendChild( input );
3240
3241         // Support: Safari 5.1, Android 4.x, Android 2.3
3242         // old WebKit doesn't clone checked state correctly in fragments
3243         support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
3244
3245         // Support: Firefox, Chrome, Safari
3246         // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP)
3247         support.focusinBubbles = "onfocusin" in window;
3248
3249         div.style.backgroundClip = "content-box";
3250         div.cloneNode( true ).style.backgroundClip = "";
3251         support.clearCloneStyle = div.style.backgroundClip === "content-box";
3252
3253         // Run tests that need a body at doc ready
3254         jQuery(function() {
3255                 var container, marginDiv,
3256                         // Support: Firefox, Android 2.3 (Prefixed box-sizing versions).
3257                         divReset = "padding:0;margin:0;border:0;display:block;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box",
3258                         body = document.getElementsByTagName("body")[ 0 ];
3259
3260                 if ( !body ) {
3261                         // Return for frameset docs that don't have a body
3262                         return;
3263                 }
3264
3265                 container = document.createElement("div");
3266                 container.style.cssText = "border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px";
3267
3268                 // Check box-sizing and margin behavior.
3269                 body.appendChild( container ).appendChild( div );
3270                 div.innerHTML = "";
3271                 // Support: Firefox, Android 2.3 (Prefixed box-sizing versions).
3272                 div.style.cssText = "-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%";
3273
3274                 // Workaround failing boxSizing test due to offsetWidth returning wrong value
3275                 // with some non-1 values of body zoom, ticket #13543
3276                 jQuery.swap( body, body.style.zoom != null ? { zoom: 1 } : {}, function() {
3277                         support.boxSizing = div.offsetWidth === 4;
3278                 });
3279
3280                 // Use window.getComputedStyle because jsdom on node.js will break without it.
3281                 if ( window.getComputedStyle ) {
3282                         support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%";
3283                         support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px";
3284
3285                         // Support: Android 2.3
3286                         // Check if div with explicit width and no margin-right incorrectly
3287                         // gets computed margin-right based on width of container. (#3333)
3288                         // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
3289                         marginDiv = div.appendChild( document.createElement("div") );
3290                         marginDiv.style.cssText = div.style.cssText = divReset;
3291                         marginDiv.style.marginRight = marginDiv.style.width = "0";
3292                         div.style.width = "1px";
3293
3294                         support.reliableMarginRight =
3295                                 !parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight );
3296                 }
3297
3298                 body.removeChild( container );
3299         });
3300
3301         return support;
3302 })( {} );
3303
3304 /*
3305         Implementation Summary
3306
3307         1. Enforce API surface and semantic compatibility with 1.9.x branch
3308         2. Improve the module's maintainability by reducing the storage
3309                 paths to a single mechanism.
3310         3. Use the same single mechanism to support "private" and "user" data.
3311         4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData)
3312         5. Avoid exposing implementation details on user objects (eg. expando properties)
3313         6. Provide a clear path for implementation upgrade to WeakMap in 2014
3314 */
3315 var data_user, data_priv,
3316         rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/,
3317         rmultiDash = /([A-Z])/g;
3318
3319 function Data() {
3320         // Support: Android < 4,
3321         // Old WebKit does not have Object.preventExtensions/freeze method,
3322         // return new empty object instead with no [[set]] accessor
3323         Object.defineProperty( this.cache = {}, 0, {
3324                 get: function() {
3325                         return {};
3326                 }
3327         });
3328
3329         this.expando = jQuery.expando + Math.random();
3330 }
3331
3332 Data.uid = 1;
3333
3334 Data.accepts = function( owner ) {
3335         // Accepts only:
3336         //  - Node
3337         //    - Node.ELEMENT_NODE
3338         //    - Node.DOCUMENT_NODE
3339         //  - Object
3340         //    - Any
3341         return owner.nodeType ?
3342                 owner.nodeType === 1 || owner.nodeType === 9 : true;
3343 };
3344
3345 Data.prototype = {
3346         key: function( owner ) {
3347                 // We can accept data for non-element nodes in modern browsers,
3348                 // but we should not, see #8335.
3349                 // Always return the key for a frozen object.
3350                 if ( !Data.accepts( owner ) ) {
3351                         return 0;
3352                 }
3353
3354                 var descriptor = {},
3355                         // Check if the owner object already has a cache key
3356                         unlock = owner[ this.expando ];
3357
3358                 // If not, create one
3359                 if ( !unlock ) {
3360                         unlock = Data.uid++;
3361
3362                         // Secure it in a non-enumerable, non-writable property
3363                         try {
3364                                 descriptor[ this.expando ] = { value: unlock };
3365                                 Object.defineProperties( owner, descriptor );
3366
3367                         // Support: Android < 4
3368                         // Fallback to a less secure definition
3369                         } catch ( e ) {
3370                                 descriptor[ this.expando ] = unlock;
3371                                 jQuery.extend( owner, descriptor );
3372                         }
3373                 }
3374
3375                 // Ensure the cache object
3376                 if ( !this.cache[ unlock ] ) {
3377                         this.cache[ unlock ] = {};
3378                 }
3379
3380                 return unlock;
3381         },
3382         set: function( owner, data, value ) {
3383                 var prop,
3384                         // There may be an unlock assigned to this node,
3385                         // if there is no entry for this "owner", create one inline
3386                         // and set the unlock as though an owner entry had always existed
3387                         unlock = this.key( owner ),
3388                         cache = this.cache[ unlock ];
3389
3390                 // Handle: [ owner, key, value ] args
3391                 if ( typeof data === "string" ) {
3392                         cache[ data ] = value;
3393
3394                 // Handle: [ owner, { properties } ] args
3395                 } else {
3396                         // Fresh assignments by object are shallow copied
3397                         if ( jQuery.isEmptyObject( cache ) ) {
3398                                 jQuery.extend( this.cache[ unlock ], data );
3399                         // Otherwise, copy the properties one-by-one to the cache object
3400                         } else {
3401                                 for ( prop in data ) {
3402                                         cache[ prop ] = data[ prop ];
3403                                 }
3404                         }
3405                 }
3406                 return cache;
3407         },
3408         get: function( owner, key ) {
3409                 // Either a valid cache is found, or will be created.
3410                 // New caches will be created and the unlock returned,
3411                 // allowing direct access to the newly created
3412                 // empty data object. A valid owner object must be provided.
3413                 var cache = this.cache[ this.key( owner ) ];
3414
3415                 return key === undefined ?
3416                         cache : cache[ key ];
3417         },
3418         access: function( owner, key, value ) {
3419                 var stored;
3420                 // In cases where either:
3421                 //
3422                 //   1. No key was specified
3423                 //   2. A string key was specified, but no value provided
3424                 //
3425                 // Take the "read" path and allow the get method to determine
3426                 // which value to return, respectively either:
3427                 //
3428                 //   1. The entire cache object
3429                 //   2. The data stored at the key
3430                 //
3431                 if ( key === undefined ||
3432                                 ((key && typeof key === "string") && value === undefined) ) {
3433
3434                         stored = this.get( owner, key );
3435
3436                         return stored !== undefined ?
3437                                 stored : this.get( owner, jQuery.camelCase(key) );
3438                 }
3439
3440                 // [*]When the key is not a string, or both a key and value
3441                 // are specified, set or extend (existing objects) with either:
3442                 //
3443                 //   1. An object of properties
3444                 //   2. A key and value
3445                 //
3446                 this.set( owner, key, value );
3447
3448                 // Since the "set" path can have two possible entry points
3449                 // return the expected data based on which path was taken[*]
3450                 return value !== undefined ? value : key;
3451         },
3452         remove: function( owner, key ) {
3453                 var i, name, camel,
3454                         unlock = this.key( owner ),
3455                         cache = this.cache[ unlock ];
3456
3457                 if ( key === undefined ) {
3458                         this.cache[ unlock ] = {};
3459
3460                 } else {
3461                         // Support array or space separated string of keys
3462                         if ( jQuery.isArray( key ) ) {
3463                                 // If "name" is an array of keys...
3464                                 // When data is initially created, via ("key", "val") signature,
3465                                 // keys will be converted to camelCase.
3466                                 // Since there is no way to tell _how_ a key was added, remove
3467                                 // both plain key and camelCase key. #12786
3468                                 // This will only penalize the array argument path.
3469                                 name = key.concat( key.map( jQuery.camelCase ) );
3470                         } else {
3471                                 camel = jQuery.camelCase( key );
3472                                 // Try the string as a key before any manipulation
3473                                 if ( key in cache ) {
3474                                         name = [ key, camel ];
3475                                 } else {
3476                                         // If a key with the spaces exists, use it.
3477                                         // Otherwise, create an array by matching non-whitespace
3478                                         name = camel;
3479                                         name = name in cache ?
3480                                                 [ name ] : ( name.match( core_rnotwhite ) || [] );
3481                                 }
3482                         }
3483
3484                         i = name.length;
3485                         while ( i-- ) {
3486                                 delete cache[ name[ i ] ];
3487                         }
3488                 }
3489         },
3490         hasData: function( owner ) {
3491                 return !jQuery.isEmptyObject(
3492                         this.cache[ owner[ this.expando ] ] || {}
3493                 );
3494         },
3495         discard: function( owner ) {
3496                 if ( owner[ this.expando ] ) {
3497                         delete this.cache[ owner[ this.expando ] ];
3498                 }
3499         }
3500 };
3501
3502 // These may be used throughout the jQuery core codebase
3503 data_user = new Data();
3504 data_priv = new Data();
3505
3506
3507 jQuery.extend({
3508         acceptData: Data.accepts,
3509
3510         hasData: function( elem ) {
3511                 return data_user.hasData( elem ) || data_priv.hasData( elem );
3512         },
3513
3514         data: function( elem, name, data ) {
3515                 return data_user.access( elem, name, data );
3516         },
3517
3518         removeData: function( elem, name ) {
3519                 data_user.remove( elem, name );
3520         },
3521
3522         // TODO: Now that all calls to _data and _removeData have been replaced
3523         // with direct calls to data_priv methods, these can be deprecated.
3524         _data: function( elem, name, data ) {
3525                 return data_priv.access( elem, name, data );
3526         },
3527
3528         _removeData: function( elem, name ) {
3529                 data_priv.remove( elem, name );
3530         }
3531 });
3532
3533 jQuery.fn.extend({
3534         data: function( key, value ) {
3535                 var attrs, name,
3536                         elem = this[ 0 ],
3537                         i = 0,
3538                         data = null;
3539
3540                 // Gets all values
3541                 if ( key === undefined ) {
3542                         if ( this.length ) {
3543                                 data = data_user.get( elem );
3544
3545                                 if ( elem.nodeType === 1 && !data_priv.get( elem, "hasDataAttrs" ) ) {
3546                                         attrs = elem.attributes;
3547                                         for ( ; i < attrs.length; i++ ) {
3548                                                 name = attrs[ i ].name;
3549
3550                                                 if ( name.indexOf( "data-" ) === 0 ) {
3551                                                         name = jQuery.camelCase( name.slice(5) );
3552                                                         dataAttr( elem, name, data[ name ] );
3553                                                 }
3554                                         }
3555                                         data_priv.set( elem, "hasDataAttrs", true );
3556                                 }
3557                         }
3558
3559                         return data;
3560                 }
3561
3562                 // Sets multiple values
3563                 if ( typeof key === "object" ) {
3564                         return this.each(function() {
3565                                 data_user.set( this, key );
3566                         });
3567                 }
3568
3569                 return jQuery.access( this, function( value ) {
3570                         var data,
3571                                 camelKey = jQuery.camelCase( key );
3572
3573                         // The calling jQuery object (element matches) is not empty
3574                         // (and therefore has an element appears at this[ 0 ]) and the
3575                         // `value` parameter was not undefined. An empty jQuery object
3576                         // will result in `undefined` for elem = this[ 0 ] which will
3577                         // throw an exception if an attempt to read a data cache is made.
3578                         if ( elem && value === undefined ) {
3579                                 // Attempt to get data from the cache
3580                                 // with the key as-is
3581                                 data = data_user.get( elem, key );
3582                                 if ( data !== undefined ) {
3583                                         return data;
3584                                 }
3585
3586                                 // Attempt to get data from the cache
3587                                 // with the key camelized
3588                                 data = data_user.get( elem, camelKey );
3589                                 if ( data !== undefined ) {
3590                                         return data;
3591                                 }
3592
3593                                 // Attempt to "discover" the data in
3594                                 // HTML5 custom data-* attrs
3595                                 data = dataAttr( elem, camelKey, undefined );
3596                                 if ( data !== undefined ) {
3597                                         return data;
3598                                 }
3599
3600                                 // We tried really hard, but the data doesn't exist.
3601                                 return;
3602                         }
3603
3604                         // Set the data...
3605                         this.each(function() {
3606                                 // First, attempt to store a copy or reference of any
3607                                 // data that might've been store with a camelCased key.
3608                                 var data = data_user.get( this, camelKey );
3609
3610                                 // For HTML5 data-* attribute interop, we have to
3611                                 // store property names with dashes in a camelCase form.
3612                                 // This might not apply to all properties...*
3613                                 data_user.set( this, camelKey, value );
3614
3615                                 // *... In the case of properties that might _actually_
3616                                 // have dashes, we need to also store a copy of that
3617                                 // unchanged property.
3618                                 if ( key.indexOf("-") !== -1 && data !== undefined ) {
3619                                         data_user.set( this, key, value );
3620                                 }
3621                         });
3622                 }, null, value, arguments.length > 1, null, true );
3623         },
3624
3625         removeData: function( key ) {
3626                 return this.each(function() {
3627                         data_user.remove( this, key );
3628                 });
3629         }
3630 });
3631
3632 function dataAttr( elem, key, data ) {
3633         var name;
3634
3635         // If nothing was found internally, try to fetch any
3636         // data from the HTML5 data-* attribute
3637         if ( data === undefined && elem.nodeType === 1 ) {
3638                 name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
3639                 data = elem.getAttribute( name );
3640
3641                 if ( typeof data === "string" ) {
3642                         try {
3643                                 data = data === "true" ? true :
3644                                         data === "false" ? false :
3645                                         data === "null" ? null :
3646                                         // Only convert to a number if it doesn't change the string
3647                                         +data + "" === data ? +data :
3648                                         rbrace.test( data ) ? JSON.parse( data ) :
3649                                         data;
3650                         } catch( e ) {}
3651
3652                         // Make sure we set the data so it isn't changed later
3653                         data_user.set( elem, key, data );
3654                 } else {
3655                         data = undefined;
3656                 }
3657         }
3658         return data;
3659 }
3660 jQuery.extend({
3661         queue: function( elem, type, data ) {
3662                 var queue;
3663
3664                 if ( elem ) {
3665                         type = ( type || "fx" ) + "queue";
3666                         queue = data_priv.get( elem, type );
3667
3668                         // Speed up dequeue by getting out quickly if this is just a lookup
3669                         if ( data ) {
3670                                 if ( !queue || jQuery.isArray( data ) ) {
3671                                         queue = data_priv.access( elem, type, jQuery.makeArray(data) );
3672                                 } else {
3673                                         queue.push( data );
3674                                 }
3675                         }
3676                         return queue || [];
3677                 }
3678         },
3679
3680         dequeue: function( elem, type ) {
3681                 type = type || "fx";
3682
3683                 var queue = jQuery.queue( elem, type ),
3684                         startLength = queue.length,
3685                         fn = queue.shift(),
3686                         hooks = jQuery._queueHooks( elem, type ),
3687                         next = function() {
3688                                 jQuery.dequeue( elem, type );
3689                         };
3690
3691                 // If the fx queue is dequeued, always remove the progress sentinel
3692                 if ( fn === "inprogress" ) {
3693                         fn = queue.shift();
3694                         startLength--;
3695                 }
3696
3697                 if ( fn ) {
3698
3699                         // Add a progress sentinel to prevent the fx queue from being
3700                         // automatically dequeued
3701                         if ( type === "fx" ) {
3702                                 queue.unshift( "inprogress" );
3703                         }
3704
3705                         // clear up the last queue stop function
3706                         delete hooks.stop;
3707                         fn.call( elem, next, hooks );
3708                 }
3709
3710                 if ( !startLength && hooks ) {
3711                         hooks.empty.fire();
3712                 }
3713         },
3714
3715         // not intended for public consumption - generates a queueHooks object, or returns the current one
3716         _queueHooks: function( elem, type ) {
3717                 var key = type + "queueHooks";
3718                 return data_priv.get( elem, key ) || data_priv.access( elem, key, {
3719                         empty: jQuery.Callbacks("once memory").add(function() {
3720                                 data_priv.remove( elem, [ type + "queue", key ] );
3721                         })
3722                 });
3723         }
3724 });
3725
3726 jQuery.fn.extend({
3727         queue: function( type, data ) {
3728                 var setter = 2;
3729
3730                 if ( typeof type !== "string" ) {
3731                         data = type;
3732                         type = "fx";
3733                         setter--;
3734                 }
3735
3736                 if ( arguments.length < setter ) {
3737                         return jQuery.queue( this[0], type );
3738                 }
3739
3740                 return data === undefined ?
3741                         this :
3742                         this.each(function() {
3743                                 var queue = jQuery.queue( this, type, data );
3744
3745                                 // ensure a hooks for this queue
3746                                 jQuery._queueHooks( this, type );
3747
3748                                 if ( type === "fx" && queue[0] !== "inprogress" ) {
3749                                         jQuery.dequeue( this, type );
3750                                 }
3751                         });
3752         },
3753         dequeue: function( type ) {
3754                 return this.each(function() {
3755                         jQuery.dequeue( this, type );
3756                 });
3757         },
3758         // Based off of the plugin by Clint Helfers, with permission.
3759         // http://blindsignals.com/index.php/2009/07/jquery-delay/
3760         delay: function( time, type ) {
3761                 time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
3762                 type = type || "fx";
3763
3764                 return this.queue( type, function( next, hooks ) {
3765                         var timeout = setTimeout( next, time );
3766                         hooks.stop = function() {
3767                                 clearTimeout( timeout );
3768                         };
3769                 });
3770         },
3771         clearQueue: function( type ) {
3772                 return this.queue( type || "fx", [] );
3773         },
3774         // Get a promise resolved when queues of a certain type
3775         // are emptied (fx is the type by default)
3776         promise: function( type, obj ) {
3777                 var tmp,
3778                         count = 1,
3779                         defer = jQuery.Deferred(),
3780                         elements = this,
3781                         i = this.length,
3782                         resolve = function() {
3783                                 if ( !( --count ) ) {
3784                                         defer.resolveWith( elements, [ elements ] );
3785                                 }
3786                         };
3787
3788                 if ( typeof type !== "string" ) {
3789                         obj = type;
3790                         type = undefined;
3791                 }
3792                 type = type || "fx";
3793
3794                 while( i-- ) {
3795                         tmp = data_priv.get( elements[ i ], type + "queueHooks" );
3796                         if ( tmp && tmp.empty ) {
3797                                 count++;
3798                                 tmp.empty.add( resolve );
3799                         }
3800                 }
3801                 resolve();
3802                 return defer.promise( obj );
3803         }
3804 });
3805 var nodeHook, boolHook,
3806         rclass = /[\t\r\n\f]/g,
3807         rreturn = /\r/g,
3808         rfocusable = /^(?:input|select|textarea|button)$/i;
3809
3810 jQuery.fn.extend({
3811         attr: function( name, value ) {
3812                 return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
3813         },
3814
3815         removeAttr: function( name ) {
3816                 return this.each(function() {
3817                         jQuery.removeAttr( this, name );
3818                 });
3819         },
3820
3821         prop: function( name, value ) {
3822                 return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );
3823         },
3824
3825         removeProp: function( name ) {
3826                 return this.each(function() {
3827                         delete this[ jQuery.propFix[ name ] || name ];
3828                 });
3829         },
3830
3831         addClass: function( value ) {
3832                 var classes, elem, cur, clazz, j,
3833                         i = 0,
3834                         len = this.length,
3835                         proceed = typeof value === "string" && value;
3836
3837                 if ( jQuery.isFunction( value ) ) {
3838                         return this.each(function( j ) {
3839                                 jQuery( this ).addClass( value.call( this, j, this.className ) );
3840                         });
3841                 }
3842
3843                 if ( proceed ) {
3844                         // The disjunction here is for better compressibility (see removeClass)
3845                         classes = ( value || "" ).match( core_rnotwhite ) || [];
3846
3847                         for ( ; i < len; i++ ) {
3848                                 elem = this[ i ];
3849                                 cur = elem.nodeType === 1 && ( elem.className ?
3850                                         ( " " + elem.className + " " ).replace( rclass, " " ) :
3851                                         " "
3852                                 );
3853
3854                                 if ( cur ) {
3855                                         j = 0;
3856                                         while ( (clazz = classes[j++]) ) {
3857                                                 if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
3858                                                         cur += clazz + " ";
3859                                                 }
3860                                         }
3861                                         elem.className = jQuery.trim( cur );
3862
3863                                 }
3864                         }
3865                 }
3866
3867                 return this;
3868         },
3869
3870         removeClass: function( value ) {
3871                 var classes, elem, cur, clazz, j,
3872                         i = 0,
3873                         len = this.length,
3874                         proceed = arguments.length === 0 || typeof value === "string" && value;
3875
3876                 if ( jQuery.isFunction( value ) ) {
3877                         return this.each(function( j ) {
3878                                 jQuery( this ).removeClass( value.call( this, j, this.className ) );
3879                         });
3880                 }
3881                 if ( proceed ) {
3882                         classes = ( value || "" ).match( core_rnotwhite ) || [];
3883
3884                         for ( ; i < len; i++ ) {
3885                                 elem = this[ i ];
3886                                 // This expression is here for better compressibility (see addClass)
3887                                 cur = elem.nodeType === 1 && ( elem.className ?
3888                                         ( " " + elem.className + " " ).replace( rclass, " " ) :
3889                                         ""
3890                                 );
3891
3892                                 if ( cur ) {
3893                                         j = 0;
3894                                         while ( (clazz = classes[j++]) ) {
3895                                                 // Remove *all* instances
3896                                                 while ( cur.indexOf( " " + clazz + " " ) >= 0 ) {
3897                                                         cur = cur.replace( " " + clazz + " ", " " );
3898                                                 }
3899                                         }
3900                                         elem.className = value ? jQuery.trim( cur ) : "";
3901                                 }
3902                         }
3903                 }
3904
3905                 return this;
3906         },
3907
3908         toggleClass: function( value, stateVal ) {
3909                 var type = typeof value;
3910
3911                 if ( typeof stateVal === "boolean" && type === "string" ) {
3912                         return stateVal ? this.addClass( value ) : this.removeClass( value );
3913                 }
3914
3915                 if ( jQuery.isFunction( value ) ) {
3916                         return this.each(function( i ) {
3917                                 jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
3918                         });
3919                 }
3920
3921                 return this.each(function() {
3922                         if ( type === "string" ) {
3923                                 // toggle individual class names
3924                                 var className,
3925                                         i = 0,
3926                                         self = jQuery( this ),
3927                                         classNames = value.match( core_rnotwhite ) || [];
3928
3929                                 while ( (className = classNames[ i++ ]) ) {
3930                                         // check each className given, space separated list
3931                                         if ( self.hasClass( className ) ) {
3932                                                 self.removeClass( className );
3933                                         } else {
3934                                                 self.addClass( className );
3935                                         }
3936                                 }
3937
3938                         // Toggle whole class name
3939                         } else if ( type === core_strundefined || type === "boolean" ) {
3940                                 if ( this.className ) {
3941                                         // store className if set
3942                                         data_priv.set( this, "__className__", this.className );
3943                                 }
3944
3945                                 // If the element has a class name or if we're passed "false",
3946                                 // then remove the whole classname (if there was one, the above saved it).
3947                                 // Otherwise bring back whatever was previously saved (if anything),
3948                                 // falling back to the empty string if nothing was stored.
3949                                 this.className = this.className || value === false ? "" : data_priv.get( this, "__className__" ) || "";
3950                         }
3951                 });
3952         },
3953
3954         hasClass: function( selector ) {
3955                 var className = " " + selector + " ",
3956                         i = 0,
3957                         l = this.length;
3958                 for ( ; i < l; i++ ) {
3959                         if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
3960                                 return true;
3961                         }
3962                 }
3963
3964                 return false;
3965         },
3966
3967         val: function( value ) {
3968                 var hooks, ret, isFunction,
3969                         elem = this[0];
3970
3971                 if ( !arguments.length ) {
3972                         if ( elem ) {
3973                                 hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
3974
3975                                 if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
3976                                         return ret;
3977                                 }
3978
3979                                 ret = elem.value;
3980
3981                                 return typeof ret === "string" ?
3982                                         // handle most common string cases
3983                                         ret.replace(rreturn, "") :
3984                                         // handle cases where value is null/undef or number
3985                                         ret == null ? "" : ret;
3986                         }
3987
3988                         return;
3989                 }
3990
3991                 isFunction = jQuery.isFunction( value );
3992
3993                 return this.each(function( i ) {
3994                         var val;
3995
3996                         if ( this.nodeType !== 1 ) {
3997                                 return;
3998                         }
3999
4000                         if ( isFunction ) {
4001                                 val = value.call( this, i, jQuery( this ).val() );
4002                         } else {
4003                                 val = value;
4004                         }
4005
4006                         // Treat null/undefined as ""; convert numbers to string
4007                         if ( val == null ) {
4008                                 val = "";
4009                         } else if ( typeof val === "number" ) {
4010                                 val += "";
4011                         } else if ( jQuery.isArray( val ) ) {
4012                                 val = jQuery.map(val, function ( value ) {
4013                                         return value == null ? "" : value + "";
4014                                 });
4015                         }
4016
4017                         hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
4018
4019                         // If set returns undefined, fall back to normal setting
4020                         if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
4021                                 this.value = val;
4022                         }
4023                 });
4024         }
4025 });
4026
4027 jQuery.extend({
4028         valHooks: {
4029                 option: {
4030                         get: function( elem ) {
4031                                 // attributes.value is undefined in Blackberry 4.7 but
4032                                 // uses .value. See #6932
4033                                 var val = elem.attributes.value;
4034                                 return !val || val.specified ? elem.value : elem.text;
4035                         }
4036                 },
4037                 select: {
4038                         get: function( elem ) {
4039                                 var value, option,
4040                                         options = elem.options,
4041                                         index = elem.selectedIndex,
4042                                         one = elem.type === "select-one" || index < 0,
4043                                         values = one ? null : [],
4044                                         max = one ? index + 1 : options.length,
4045                                         i = index < 0 ?
4046                                                 max :
4047                                                 one ? index : 0;
4048
4049                                 // Loop through all the selected options
4050                                 for ( ; i < max; i++ ) {
4051                                         option = options[ i ];
4052
4053                                         // IE6-9 doesn't update selected after form reset (#2551)
4054                                         if ( ( option.selected || i === index ) &&
4055                                                         // Don't return options that are disabled or in a disabled optgroup
4056                                                         ( jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) &&
4057                                                         ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {
4058
4059                                                 // Get the specific value for the option
4060                                                 value = jQuery( option ).val();
4061
4062                                                 // We don't need an array for one selects
4063                                                 if ( one ) {
4064                                                         return value;
4065                                                 }
4066
4067                                                 // Multi-Selects return an array
4068                                                 values.push( value );
4069                                         }
4070                                 }
4071
4072                                 return values;
4073                         },
4074
4075                         set: function( elem, value ) {
4076                                 var optionSet, option,
4077                                         options = elem.options,
4078                                         values = jQuery.makeArray( value ),
4079                                         i = options.length;
4080
4081                                 while ( i-- ) {
4082                                         option = options[ i ];
4083                                         if ( (option.selected = jQuery.inArray( jQuery(option).val(), values ) >= 0) ) {
4084                                                 optionSet = true;
4085                                         }
4086                                 }
4087
4088                                 // force browsers to behave consistently when non-matching value is set
4089                                 if ( !optionSet ) {
4090                                         elem.selectedIndex = -1;
4091                                 }
4092                                 return values;
4093                         }
4094                 }
4095         },
4096
4097         attr: function( elem, name, value ) {
4098                 var hooks, ret,
4099                         nType = elem.nodeType;
4100
4101                 // don't get/set attributes on text, comment and attribute nodes
4102                 if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
4103                         return;
4104                 }
4105
4106                 // Fallback to prop when attributes are not supported
4107                 if ( typeof elem.getAttribute === core_strundefined ) {
4108                         return jQuery.prop( elem, name, value );
4109                 }
4110
4111                 // All attributes are lowercase
4112                 // Grab necessary hook if one is defined
4113                 if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
4114                         name = name.toLowerCase();
4115                         hooks = jQuery.attrHooks[ name ] ||
4116                                 ( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook );
4117                 }
4118
4119                 if ( value !== undefined ) {
4120
4121                         if ( value === null ) {
4122                                 jQuery.removeAttr( elem, name );
4123
4124                         } else if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
4125                                 return ret;
4126
4127                         } else {
4128                                 elem.setAttribute( name, value + "" );
4129                                 return value;
4130                         }
4131
4132                 } else if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
4133                         return ret;
4134
4135                 } else {
4136                         ret = jQuery.find.attr( elem, name );
4137
4138                         // Non-existent attributes return null, we normalize to undefined
4139                         return ret == null ?
4140                                 undefined :
4141                                 ret;
4142                 }
4143         },
4144
4145         removeAttr: function( elem, value ) {
4146                 var name, propName,
4147                         i = 0,
4148                         attrNames = value && value.match( core_rnotwhite );
4149
4150                 if ( attrNames && elem.nodeType === 1 ) {
4151                         while ( (name = attrNames[i++]) ) {
4152                                 propName = jQuery.propFix[ name ] || name;
4153
4154                                 // Boolean attributes get special treatment (#10870)
4155                                 if ( jQuery.expr.match.bool.test( name ) ) {
4156                                         // Set corresponding property to false
4157                                         elem[ propName ] = false;
4158                                 }
4159
4160                                 elem.removeAttribute( name );
4161                         }
4162                 }
4163         },
4164
4165         attrHooks: {
4166                 type: {
4167                         set: function( elem, value ) {
4168                                 if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
4169                                         // Setting the type on a radio button after the value resets the value in IE6-9
4170                                         // Reset value to default in case type is set after value during creation
4171                                         var val = elem.value;
4172                                         elem.setAttribute( "type", value );
4173                                         if ( val ) {
4174                                                 elem.value = val;
4175                                         }
4176                                         return value;
4177                                 }
4178                         }
4179                 }
4180         },
4181
4182         propFix: {
4183                 "for": "htmlFor",
4184                 "class": "className"
4185         },
4186
4187         prop: function( elem, name, value ) {
4188                 var ret, hooks, notxml,
4189                         nType = elem.nodeType;
4190
4191                 // don't get/set properties on text, comment and attribute nodes
4192                 if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
4193                         return;
4194                 }
4195
4196                 notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
4197
4198                 if ( notxml ) {
4199                         // Fix name and attach hooks
4200                         name = jQuery.propFix[ name ] || name;
4201                         hooks = jQuery.propHooks[ name ];
4202                 }
4203
4204                 if ( value !== undefined ) {
4205                         return hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ?
4206                                 ret :
4207                                 ( elem[ name ] = value );
4208
4209                 } else {
4210                         return hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ?
4211                                 ret :
4212                                 elem[ name ];
4213                 }
4214         },
4215
4216         propHooks: {
4217                 tabIndex: {
4218                         get: function( elem ) {
4219                                 return elem.hasAttribute( "tabindex" ) || rfocusable.test( elem.nodeName ) || elem.href ?
4220                                         elem.tabIndex :
4221                                         -1;
4222                         }
4223                 }
4224         }
4225 });
4226
4227 // Hooks for boolean attributes
4228 boolHook = {
4229         set: function( elem, value, name ) {
4230                 if ( value === false ) {
4231                         // Remove boolean attributes when set to false
4232                         jQuery.removeAttr( elem, name );
4233                 } else {
4234                         elem.setAttribute( name, name );
4235                 }
4236                 return name;
4237         }
4238 };
4239 jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) {
4240         var getter = jQuery.expr.attrHandle[ name ] || jQuery.find.attr;
4241
4242         jQuery.expr.attrHandle[ name ] = function( elem, name, isXML ) {
4243                 var fn = jQuery.expr.attrHandle[ name ],
4244                         ret = isXML ?
4245                                 undefined :
4246                                 /* jshint eqeqeq: false */
4247                                 // Temporarily disable this handler to check existence
4248                                 (jQuery.expr.attrHandle[ name ] = undefined) !=
4249                                         getter( elem, name, isXML ) ?
4250
4251                                         name.toLowerCase() :
4252                                         null;
4253
4254                 // Restore handler
4255                 jQuery.expr.attrHandle[ name ] = fn;
4256
4257                 return ret;
4258         };
4259 });
4260
4261 // Support: IE9+
4262 // Selectedness for an option in an optgroup can be inaccurate
4263 if ( !jQuery.support.optSelected ) {
4264         jQuery.propHooks.selected = {
4265                 get: function( elem ) {
4266                         var parent = elem.parentNode;
4267                         if ( parent && parent.parentNode ) {
4268                                 parent.parentNode.selectedIndex;
4269                         }
4270                         return null;
4271                 }
4272         };
4273 }
4274
4275 jQuery.each([
4276         "tabIndex",
4277         "readOnly",
4278         "maxLength",
4279         "cellSpacing",
4280         "cellPadding",
4281         "rowSpan",
4282         "colSpan",
4283         "useMap",
4284         "frameBorder",
4285         "contentEditable"
4286 ], function() {
4287         jQuery.propFix[ this.toLowerCase() ] = this;
4288 });
4289
4290 // Radios and checkboxes getter/setter
4291 jQuery.each([ "radio", "checkbox" ], function() {
4292         jQuery.valHooks[ this ] = {
4293                 set: function( elem, value ) {
4294                         if ( jQuery.isArray( value ) ) {
4295                                 return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
4296                         }
4297                 }
4298         };
4299         if ( !jQuery.support.checkOn ) {
4300                 jQuery.valHooks[ this ].get = function( elem ) {
4301                         // Support: Webkit
4302                         // "" is returned instead of "on" if a value isn't specified
4303                         return elem.getAttribute("value") === null ? "on" : elem.value;
4304                 };
4305         }
4306 });
4307 var rkeyEvent = /^key/,
4308         rmouseEvent = /^(?:mouse|contextmenu)|click/,
4309         rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
4310         rtypenamespace = /^([^.]*)(?:\.(.+)|)$/;
4311
4312 function returnTrue() {
4313         return true;
4314 }
4315
4316 function returnFalse() {
4317         return false;
4318 }
4319
4320 function safeActiveElement() {
4321         try {
4322                 return document.activeElement;
4323         } catch ( err ) { }
4324 }
4325
4326 /*
4327  * Helper functions for managing events -- not part of the public interface.
4328  * Props to Dean Edwards' addEvent library for many of the ideas.
4329  */
4330 jQuery.event = {
4331
4332         global: {},
4333
4334         add: function( elem, types, handler, data, selector ) {
4335
4336                 var handleObjIn, eventHandle, tmp,
4337                         events, t, handleObj,
4338                         special, handlers, type, namespaces, origType,
4339                         elemData = data_priv.get( elem );
4340
4341                 // Don't attach events to noData or text/comment nodes (but allow plain objects)
4342                 if ( !elemData ) {
4343                         return;
4344                 }
4345
4346                 // Caller can pass in an object of custom data in lieu of the handler
4347                 if ( handler.handler ) {
4348                         handleObjIn = handler;
4349                         handler = handleObjIn.handler;
4350                         selector = handleObjIn.selector;
4351                 }
4352
4353                 // Make sure that the handler has a unique ID, used to find/remove it later
4354                 if ( !handler.guid ) {
4355                         handler.guid = jQuery.guid++;
4356                 }
4357
4358                 // Init the element's event structure and main handler, if this is the first
4359                 if ( !(events = elemData.events) ) {
4360                         events = elemData.events = {};
4361                 }
4362                 if ( !(eventHandle = elemData.handle) ) {
4363                         eventHandle = elemData.handle = function( e ) {
4364                                 // Discard the second event of a jQuery.event.trigger() and
4365                                 // when an event is called after a page has unloaded
4366                                 return typeof jQuery !== core_strundefined && (!e || jQuery.event.triggered !== e.type) ?
4367                                         jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
4368                                         undefined;
4369                         };
4370                         // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
4371                         eventHandle.elem = elem;
4372                 }
4373
4374                 // Handle multiple events separated by a space
4375                 types = ( types || "" ).match( core_rnotwhite ) || [""];
4376                 t = types.length;
4377                 while ( t-- ) {
4378                         tmp = rtypenamespace.exec( types[t] ) || [];
4379                         type = origType = tmp[1];
4380                         namespaces = ( tmp[2] || "" ).split( "." ).sort();
4381
4382                         // There *must* be a type, no attaching namespace-only handlers
4383                         if ( !type ) {
4384                                 continue;
4385                         }
4386
4387                         // If event changes its type, use the special event handlers for the changed type
4388                         special = jQuery.event.special[ type ] || {};
4389
4390                         // If selector defined, determine special event api type, otherwise given type
4391                         type = ( selector ? special.delegateType : special.bindType ) || type;
4392
4393                         // Update special based on newly reset type
4394                         special = jQuery.event.special[ type ] || {};
4395
4396                         // handleObj is passed to all event handlers
4397                         handleObj = jQuery.extend({
4398                                 type: type,
4399                                 origType: origType,
4400                                 data: data,
4401                                 handler: handler,
4402                                 guid: handler.guid,
4403                                 selector: selector,
4404                                 needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
4405                                 namespace: namespaces.join(".")
4406                         }, handleObjIn );
4407
4408                         // Init the event handler queue if we're the first
4409                         if ( !(handlers = events[ type ]) ) {
4410                                 handlers = events[ type ] = [];
4411                                 handlers.delegateCount = 0;
4412
4413                                 // Only use addEventListener if the special events handler returns false
4414                                 if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
4415                                         if ( elem.addEventListener ) {
4416                                                 elem.addEventListener( type, eventHandle, false );
4417                                         }
4418                                 }
4419                         }
4420
4421                         if ( special.add ) {
4422                                 special.add.call( elem, handleObj );
4423
4424                                 if ( !handleObj.handler.guid ) {
4425                                         handleObj.handler.guid = handler.guid;
4426                                 }
4427                         }
4428
4429                         // Add to the element's handler list, delegates in front
4430                         if ( selector ) {
4431                                 handlers.splice( handlers.delegateCount++, 0, handleObj );
4432                         } else {
4433                                 handlers.push( handleObj );
4434                         }
4435
4436                         // Keep track of which events have ever been used, for event optimization
4437                         jQuery.event.global[ type ] = true;
4438                 }
4439
4440                 // Nullify elem to prevent memory leaks in IE
4441                 elem = null;
4442         },
4443
4444         // Detach an event or set of events from an element
4445         remove: function( elem, types, handler, selector, mappedTypes ) {
4446
4447                 var j, origCount, tmp,
4448                         events, t, handleObj,
4449                         special, handlers, type, namespaces, origType,
4450                         elemData = data_priv.hasData( elem ) && data_priv.get( elem );
4451
4452                 if ( !elemData || !(events = elemData.events) ) {
4453                         return;
4454                 }
4455
4456                 // Once for each type.namespace in types; type may be omitted
4457                 types = ( types || "" ).match( core_rnotwhite ) || [""];
4458                 t = types.length;
4459                 while ( t-- ) {
4460                         tmp = rtypenamespace.exec( types[t] ) || [];
4461                         type = origType = tmp[1];
4462                         namespaces = ( tmp[2] || "" ).split( "." ).sort();
4463
4464                         // Unbind all events (on this namespace, if provided) for the element
4465                         if ( !type ) {
4466                                 for ( type in events ) {
4467                                         jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
4468                                 }
4469                                 continue;
4470                         }
4471
4472                         special = jQuery.event.special[ type ] || {};
4473                         type = ( selector ? special.delegateType : special.bindType ) || type;
4474                         handlers = events[ type ] || [];
4475                         tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" );
4476
4477                         // Remove matching events
4478                         origCount = j = handlers.length;
4479                         while ( j-- ) {
4480                                 handleObj = handlers[ j ];
4481
4482                                 if ( ( mappedTypes || origType === handleObj.origType ) &&
4483                                         ( !handler || handler.guid === handleObj.guid ) &&
4484                                         ( !tmp || tmp.test( handleObj.namespace ) ) &&
4485                                         ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
4486                                         handlers.splice( j, 1 );
4487
4488                                         if ( handleObj.selector ) {
4489                                                 handlers.delegateCount--;
4490                                         }
4491                                         if ( special.remove ) {
4492                                                 special.remove.call( elem, handleObj );
4493                                         }
4494                                 }
4495                         }
4496
4497                         // Remove generic event handler if we removed something and no more handlers exist
4498                         // (avoids potential for endless recursion during removal of special event handlers)
4499                         if ( origCount && !handlers.length ) {
4500                                 if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
4501                                         jQuery.removeEvent( elem, type, elemData.handle );
4502                                 }
4503
4504                                 delete events[ type ];
4505                         }
4506                 }
4507
4508                 // Remove the expando if it's no longer used
4509                 if ( jQuery.isEmptyObject( events ) ) {
4510                         delete elemData.handle;
4511                         data_priv.remove( elem, "events" );
4512                 }
4513         },
4514
4515         trigger: function( event, data, elem, onlyHandlers ) {
4516
4517                 var i, cur, tmp, bubbleType, ontype, handle, special,
4518                         eventPath = [ elem || document ],
4519                         type = core_hasOwn.call( event, "type" ) ? event.type : event,
4520                         namespaces = core_hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : [];
4521
4522                 cur = tmp = elem = elem || document;
4523
4524                 // Don't do events on text and comment nodes
4525                 if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
4526                         return;
4527                 }
4528
4529                 // focus/blur morphs to focusin/out; ensure we're not firing them right now
4530                 if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
4531                         return;
4532                 }
4533
4534                 if ( type.indexOf(".") >= 0 ) {
4535                         // Namespaced trigger; create a regexp to match event type in handle()
4536                         namespaces = type.split(".");
4537                         type = namespaces.shift();
4538                         namespaces.sort();
4539                 }
4540                 ontype = type.indexOf(":") < 0 && "on" + type;
4541
4542                 // Caller can pass in a jQuery.Event object, Object, or just an event type string
4543                 event = event[ jQuery.expando ] ?
4544                         event :
4545                         new jQuery.Event( type, typeof event === "object" && event );
4546
4547                 // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
4548                 event.isTrigger = onlyHandlers ? 2 : 3;
4549                 event.namespace = namespaces.join(".");
4550                 event.namespace_re = event.namespace ?
4551                         new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) :
4552                         null;
4553
4554                 // Clean up the event in case it is being reused
4555                 event.result = undefined;
4556                 if ( !event.target ) {
4557                         event.target = elem;
4558                 }
4559
4560                 // Clone any incoming data and prepend the event, creating the handler arg list
4561                 data = data == null ?
4562                         [ event ] :
4563                         jQuery.makeArray( data, [ event ] );
4564
4565                 // Allow special events to draw outside the lines
4566                 special = jQuery.event.special[ type ] || {};
4567                 if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
4568                         return;
4569                 }
4570
4571                 // Determine event propagation path in advance, per W3C events spec (#9951)
4572                 // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
4573                 if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
4574
4575                         bubbleType = special.delegateType || type;
4576                         if ( !rfocusMorph.test( bubbleType + type ) ) {
4577                                 cur = cur.parentNode;
4578                         }
4579                         for ( ; cur; cur = cur.parentNode ) {
4580                                 eventPath.push( cur );
4581                                 tmp = cur;
4582                         }
4583
4584                         // Only add window if we got to document (e.g., not plain obj or detached DOM)
4585                         if ( tmp === (elem.ownerDocument || document) ) {
4586                                 eventPath.push( tmp.defaultView || tmp.parentWindow || window );
4587                         }
4588                 }
4589
4590                 // Fire handlers on the event path
4591                 i = 0;
4592                 while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) {
4593
4594                         event.type = i > 1 ?
4595                                 bubbleType :
4596                                 special.bindType || type;
4597
4598                         // jQuery handler
4599                         handle = ( data_priv.get( cur, "events" ) || {} )[ event.type ] && data_priv.get( cur, "handle" );
4600                         if ( handle ) {
4601                                 handle.apply( cur, data );
4602                         }
4603
4604                         // Native handler
4605                         handle = ontype && cur[ ontype ];
4606                         if ( handle && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) {
4607                                 event.preventDefault();
4608                         }
4609                 }
4610                 event.type = type;
4611
4612                 // If nobody prevented the default action, do it now
4613                 if ( !onlyHandlers && !event.isDefaultPrevented() ) {
4614
4615                         if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) &&
4616                                 jQuery.acceptData( elem ) ) {
4617
4618                                 // Call a native DOM method on the target with the same name name as the event.
4619                                 // Don't do default actions on window, that's where global variables be (#6170)
4620                                 if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) {
4621
4622                                         // Don't re-trigger an onFOO event when we call its FOO() method
4623                                         tmp = elem[ ontype ];
4624
4625                                         if ( tmp ) {
4626                                                 elem[ ontype ] = null;
4627                                         }
4628
4629                                         // Prevent re-triggering of the same event, since we already bubbled it above
4630                                         jQuery.event.triggered = type;
4631                                         elem[ type ]();
4632                                         jQuery.event.triggered = undefined;
4633
4634                                         if ( tmp ) {
4635                                                 elem[ ontype ] = tmp;
4636                                         }
4637                                 }
4638                         }
4639                 }
4640
4641                 return event.result;
4642         },
4643
4644         dispatch: function( event ) {
4645
4646                 // Make a writable jQuery.Event from the native event object
4647                 event = jQuery.event.fix( event );
4648
4649                 var i, j, ret, matched, handleObj,
4650                         handlerQueue = [],
4651                         args = core_slice.call( arguments ),
4652                         handlers = ( data_priv.get( this, "events" ) || {} )[ event.type ] || [],
4653                         special = jQuery.event.special[ event.type ] || {};
4654
4655                 // Use the fix-ed jQuery.Event rather than the (read-only) native event
4656                 args[0] = event;
4657                 event.delegateTarget = this;
4658
4659                 // Call the preDispatch hook for the mapped type, and let it bail if desired
4660                 if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
4661                         return;
4662                 }
4663
4664                 // Determine handlers
4665                 handlerQueue = jQuery.event.handlers.call( this, event, handlers );
4666
4667                 // Run delegates first; they may want to stop propagation beneath us
4668                 i = 0;
4669                 while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) {
4670                         event.currentTarget = matched.elem;
4671
4672                         j = 0;
4673                         while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) {
4674
4675                                 // Triggered event must either 1) have no namespace, or
4676                                 // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
4677                                 if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) {
4678
4679                                         event.handleObj = handleObj;
4680                                         event.data = handleObj.data;
4681
4682                                         ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
4683                                                         .apply( matched.elem, args );
4684
4685                                         if ( ret !== undefined ) {
4686                                                 if ( (event.result = ret) === false ) {
4687                                                         event.preventDefault();
4688                                                         event.stopPropagation();
4689                                                 }
4690                                         }
4691                                 }
4692                         }
4693                 }
4694
4695                 // Call the postDispatch hook for the mapped type
4696                 if ( special.postDispatch ) {
4697                         special.postDispatch.call( this, event );
4698                 }
4699
4700                 return event.result;
4701         },
4702
4703         handlers: function( event, handlers ) {
4704                 var i, matches, sel, handleObj,
4705                         handlerQueue = [],
4706                         delegateCount = handlers.delegateCount,
4707                         cur = event.target;
4708
4709                 // Find delegate handlers
4710                 // Black-hole SVG <use> instance trees (#13180)
4711                 // Avoid non-left-click bubbling in Firefox (#3861)
4712                 if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) {
4713
4714                         for ( ; cur !== this; cur = cur.parentNode || this ) {
4715
4716                                 // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
4717                                 if ( cur.disabled !== true || event.type !== "click" ) {
4718                                         matches = [];
4719                                         for ( i = 0; i < delegateCount; i++ ) {
4720                                                 handleObj = handlers[ i ];
4721
4722                                                 // Don't conflict with Object.prototype properties (#13203)
4723                                                 sel = handleObj.selector + " ";
4724
4725                                                 if ( matches[ sel ] === undefined ) {
4726                                                         matches[ sel ] = handleObj.needsContext ?
4727                                                                 jQuery( sel, this ).index( cur ) >= 0 :
4728                                                                 jQuery.find( sel, this, null, [ cur ] ).length;
4729                                                 }
4730                                                 if ( matches[ sel ] ) {
4731                                                         matches.push( handleObj );
4732                                                 }
4733                                         }
4734                                         if ( matches.length ) {
4735                                                 handlerQueue.push({ elem: cur, handlers: matches });
4736                                         }
4737                                 }
4738                         }
4739                 }
4740
4741                 // Add the remaining (directly-bound) handlers
4742                 if ( delegateCount < handlers.length ) {
4743                         handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) });
4744                 }
4745
4746                 return handlerQueue;
4747         },
4748
4749         // Includes some event props shared by KeyEvent and MouseEvent
4750         props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
4751
4752         fixHooks: {},
4753
4754         keyHooks: {
4755                 props: "char charCode key keyCode".split(" "),
4756                 filter: function( event, original ) {
4757
4758                         // Add which for key events
4759                         if ( event.which == null ) {
4760                                 event.which = original.charCode != null ? original.charCode : original.keyCode;
4761                         }
4762
4763                         return event;
4764                 }
4765         },
4766
4767         mouseHooks: {
4768                 props: "button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
4769                 filter: function( event, original ) {
4770                         var eventDoc, doc, body,
4771                                 button = original.button;
4772
4773                         // Calculate pageX/Y if missing and clientX/Y available
4774                         if ( event.pageX == null && original.clientX != null ) {
4775                                 eventDoc = event.target.ownerDocument || document;
4776                                 doc = eventDoc.documentElement;
4777                                 body = eventDoc.body;
4778
4779                                 event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
4780                                 event.pageY = original.clientY + ( doc && doc.scrollTop  || body && body.scrollTop  || 0 ) - ( doc && doc.clientTop  || body && body.clientTop  || 0 );
4781                         }
4782
4783                         // Add which for click: 1 === left; 2 === middle; 3 === right
4784                         // Note: button is not normalized, so don't use it
4785                         if ( !event.which && button !== undefined ) {
4786                                 event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
4787                         }
4788
4789                         return event;
4790                 }
4791         },
4792
4793         fix: function( event ) {
4794                 if ( event[ jQuery.expando ] ) {
4795                         return event;
4796                 }
4797
4798                 // Create a writable copy of the event object and normalize some properties
4799                 var i, prop, copy,
4800                         type = event.type,
4801                         originalEvent = event,
4802                         fixHook = this.fixHooks[ type ];
4803
4804                 if ( !fixHook ) {
4805                         this.fixHooks[ type ] = fixHook =
4806                                 rmouseEvent.test( type ) ? this.mouseHooks :
4807                                 rkeyEvent.test( type ) ? this.keyHooks :
4808                                 {};
4809                 }
4810                 copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
4811
4812                 event = new jQuery.Event( originalEvent );
4813
4814                 i = copy.length;
4815                 while ( i-- ) {
4816                         prop = copy[ i ];
4817                         event[ prop ] = originalEvent[ prop ];
4818                 }
4819
4820                 // Support: Cordova 2.5 (WebKit) (#13255)
4821                 // All events should have a target; Cordova deviceready doesn't
4822                 if ( !event.target ) {
4823                         event.target = document;
4824                 }
4825
4826                 // Support: Safari 6.0+, Chrome < 28
4827                 // Target should not be a text node (#504, #13143)
4828                 if ( event.target.nodeType === 3 ) {
4829                         event.target = event.target.parentNode;
4830                 }
4831
4832                 return fixHook.filter? fixHook.filter( event, originalEvent ) : event;
4833         },
4834
4835         special: {
4836                 load: {
4837                         // Prevent triggered image.load events from bubbling to window.load
4838                         noBubble: true
4839                 },
4840                 focus: {
4841                         // Fire native event if possible so blur/focus sequence is correct
4842                         trigger: function() {
4843                                 if ( this !== safeActiveElement() && this.focus ) {
4844                                         this.focus();
4845                                         return false;
4846                                 }
4847                         },
4848                         delegateType: "focusin"
4849                 },
4850                 blur: {
4851                         trigger: function() {
4852                                 if ( this === safeActiveElement() && this.blur ) {
4853                                         this.blur();
4854                                         return false;
4855                                 }
4856                         },
4857                         delegateType: "focusout"
4858                 },
4859                 click: {
4860                         // For checkbox, fire native event so checked state will be right
4861                         trigger: function() {
4862                                 if ( this.type === "checkbox" && this.click && jQuery.nodeName( this, "input" ) ) {
4863                                         this.click();
4864                                         return false;
4865                                 }
4866                         },
4867
4868                         // For cross-browser consistency, don't fire native .click() on links
4869                         _default: function( event ) {
4870                                 return jQuery.nodeName( event.target, "a" );
4871                         }
4872                 },
4873
4874                 beforeunload: {
4875                         postDispatch: function( event ) {
4876
4877                                 // Support: Firefox 20+
4878                                 // Firefox doesn't alert if the returnValue field is not set.
4879                                 if ( event.result !== undefined ) {
4880                                         event.originalEvent.returnValue = event.result;
4881                                 }
4882                         }
4883                 }
4884         },
4885
4886         simulate: function( type, elem, event, bubble ) {
4887                 // Piggyback on a donor event to simulate a different one.
4888                 // Fake originalEvent to avoid donor's stopPropagation, but if the
4889                 // simulated event prevents default then we do the same on the donor.
4890                 var e = jQuery.extend(
4891                         new jQuery.Event(),
4892                         event,
4893                         {
4894                                 type: type,
4895                                 isSimulated: true,
4896                                 originalEvent: {}
4897                         }
4898                 );
4899                 if ( bubble ) {
4900                         jQuery.event.trigger( e, null, elem );
4901                 } else {
4902                         jQuery.event.dispatch.call( elem, e );
4903                 }
4904                 if ( e.isDefaultPrevented() ) {
4905                         event.preventDefault();
4906                 }
4907         }
4908 };
4909
4910 jQuery.removeEvent = function( elem, type, handle ) {
4911         if ( elem.removeEventListener ) {
4912                 elem.removeEventListener( type, handle, false );
4913         }
4914 };
4915
4916 jQuery.Event = function( src, props ) {
4917         // Allow instantiation without the 'new' keyword
4918         if ( !(this instanceof jQuery.Event) ) {
4919                 return new jQuery.Event( src, props );
4920         }
4921
4922         // Event object
4923         if ( src && src.type ) {
4924                 this.originalEvent = src;
4925                 this.type = src.type;
4926
4927                 // Events bubbling up the document may have been marked as prevented
4928                 // by a handler lower down the tree; reflect the correct value.
4929                 this.isDefaultPrevented = ( src.defaultPrevented ||
4930                         src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse;
4931
4932         // Event type
4933         } else {
4934                 this.type = src;
4935         }
4936
4937         // Put explicitly provided properties onto the event object
4938         if ( props ) {
4939                 jQuery.extend( this, props );
4940         }
4941
4942         // Create a timestamp if incoming event doesn't have one
4943         this.timeStamp = src && src.timeStamp || jQuery.now();
4944
4945         // Mark it as fixed
4946         this[ jQuery.expando ] = true;
4947 };
4948
4949 // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
4950 // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
4951 jQuery.Event.prototype = {
4952         isDefaultPrevented: returnFalse,
4953         isPropagationStopped: returnFalse,
4954         isImmediatePropagationStopped: returnFalse,
4955
4956         preventDefault: function() {
4957                 var e = this.originalEvent;
4958
4959                 this.isDefaultPrevented = returnTrue;
4960
4961                 if ( e && e.preventDefault ) {
4962                         e.preventDefault();
4963                 }
4964         },
4965         stopPropagation: function() {
4966                 var e = this.originalEvent;
4967
4968                 this.isPropagationStopped = returnTrue;
4969
4970                 if ( e && e.stopPropagation ) {
4971                         e.stopPropagation();
4972                 }
4973         },
4974         stopImmediatePropagation: function() {
4975                 this.isImmediatePropagationStopped = returnTrue;
4976                 this.stopPropagation();
4977         }
4978 };
4979
4980 // Create mouseenter/leave events using mouseover/out and event-time checks
4981 // Support: Chrome 15+
4982 jQuery.each({
4983         mouseenter: "mouseover",
4984         mouseleave: "mouseout"
4985 }, function( orig, fix ) {
4986         jQuery.event.special[ orig ] = {
4987                 delegateType: fix,
4988                 bindType: fix,
4989
4990                 handle: function( event ) {
4991                         var ret,
4992                                 target = this,
4993                                 related = event.relatedTarget,
4994                                 handleObj = event.handleObj;
4995
4996                         // For mousenter/leave call the handler if related is outside the target.
4997                         // NB: No relatedTarget if the mouse left/entered the browser window
4998                         if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
4999                                 event.type = handleObj.origType;
5000                                 ret = handleObj.handler.apply( this, arguments );
5001                                 event.type = fix;
5002                         }
5003                         return ret;
5004                 }
5005         };
5006 });
5007
5008 // Create "bubbling" focus and blur events
5009 // Support: Firefox, Chrome, Safari
5010 if ( !jQuery.support.focusinBubbles ) {
5011         jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
5012
5013                 // Attach a single capturing handler while someone wants focusin/focusout
5014                 var attaches = 0,
5015                         handler = function( event ) {
5016                                 jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
5017                         };
5018
5019                 jQuery.event.special[ fix ] = {
5020                         setup: function() {
5021                                 if ( attaches++ === 0 ) {
5022                                         document.addEventListener( orig, handler, true );
5023                                 }
5024                         },
5025                         teardown: function() {
5026                                 if ( --attaches === 0 ) {
5027                                         document.removeEventListener( orig, handler, true );
5028                                 }
5029                         }
5030                 };
5031         });
5032 }
5033
5034 jQuery.fn.extend({
5035
5036         on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
5037                 var origFn, type;
5038
5039                 // Types can be a map of types/handlers
5040                 if ( typeof types === "object" ) {
5041                         // ( types-Object, selector, data )
5042                         if ( typeof selector !== "string" ) {
5043                                 // ( types-Object, data )
5044                                 data = data || selector;
5045                                 selector = undefined;
5046                         }
5047                         for ( type in types ) {
5048                                 this.on( type, selector, data, types[ type ], one );
5049                         }
5050                         return this;
5051                 }
5052
5053                 if ( data == null && fn == null ) {
5054                         // ( types, fn )
5055                         fn = selector;
5056                         data = selector = undefined;
5057                 } else if ( fn == null ) {
5058                         if ( typeof selector === "string" ) {
5059                                 // ( types, selector, fn )
5060                                 fn = data;
5061                                 data = undefined;
5062                         } else {
5063                                 // ( types, data, fn )
5064                                 fn = data;
5065                                 data = selector;
5066                                 selector = undefined;
5067                         }
5068                 }
5069                 if ( fn === false ) {
5070                         fn = returnFalse;
5071                 } else if ( !fn ) {
5072                         return this;
5073                 }
5074
5075                 if ( one === 1 ) {
5076                         origFn = fn;
5077                         fn = function( event ) {
5078                                 // Can use an empty set, since event contains the info
5079                                 jQuery().off( event );
5080                                 return origFn.apply( this, arguments );
5081                         };
5082                         // Use same guid so caller can remove using origFn
5083                         fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
5084                 }
5085                 return this.each( function() {
5086                         jQuery.event.add( this, types, fn, data, selector );
5087                 });
5088         },
5089         one: function( types, selector, data, fn ) {
5090                 return this.on( types, selector, data, fn, 1 );
5091         },
5092         off: function( types, selector, fn ) {
5093                 var handleObj, type;
5094                 if ( types && types.preventDefault && types.handleObj ) {
5095                         // ( event )  dispatched jQuery.Event
5096                         handleObj = types.handleObj;
5097                         jQuery( types.delegateTarget ).off(
5098                                 handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
5099                                 handleObj.selector,
5100                                 handleObj.handler
5101                         );
5102                         return this;
5103                 }
5104                 if ( typeof types === "object" ) {
5105                         // ( types-object [, selector] )
5106                         for ( type in types ) {
5107                                 this.off( type, selector, types[ type ] );
5108                         }
5109                         return this;
5110                 }
5111                 if ( selector === false || typeof selector === "function" ) {
5112                         // ( types [, fn] )
5113                         fn = selector;
5114                         selector = undefined;
5115                 }
5116                 if ( fn === false ) {
5117                         fn = returnFalse;
5118                 }
5119                 return this.each(function() {
5120                         jQuery.event.remove( this, types, fn, selector );
5121                 });
5122         },
5123
5124         trigger: function( type, data ) {
5125                 return this.each(function() {
5126                         jQuery.event.trigger( type, data, this );
5127                 });
5128         },
5129         triggerHandler: function( type, data ) {
5130                 var elem = this[0];
5131                 if ( elem ) {
5132                         return jQuery.event.trigger( type, data, elem, true );
5133                 }
5134         }
5135 });
5136 var isSimple = /^.[^:#\[\.,]*$/,
5137         rparentsprev = /^(?:parents|prev(?:Until|All))/,
5138         rneedsContext = jQuery.expr.match.needsContext,
5139         // methods guaranteed to produce a unique set when starting from a unique set
5140         guaranteedUnique = {
5141                 children: true,
5142                 contents: true,
5143                 next: true,
5144                 prev: true
5145         };
5146
5147 jQuery.fn.extend({
5148         find: function( selector ) {
5149                 var i,
5150                         ret = [],
5151                         self = this,
5152                         len = self.length;
5153
5154                 if ( typeof selector !== "string" ) {
5155                         return this.pushStack( jQuery( selector ).filter(function() {
5156                                 for ( i = 0; i < len; i++ ) {
5157                                         if ( jQuery.contains( self[ i ], this ) ) {
5158                                                 return true;
5159                                         }
5160                                 }
5161                         }) );
5162                 }
5163
5164                 for ( i = 0; i < len; i++ ) {
5165                         jQuery.find( selector, self[ i ], ret );
5166                 }
5167
5168                 // Needed because $( selector, context ) becomes $( context ).find( selector )
5169                 ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );
5170                 ret.selector = this.selector ? this.selector + " " + selector : selector;
5171                 return ret;
5172         },
5173
5174         has: function( target ) {
5175                 var targets = jQuery( target, this ),
5176                         l = targets.length;
5177
5178                 return this.filter(function() {
5179                         var i = 0;
5180                         for ( ; i < l; i++ ) {
5181                                 if ( jQuery.contains( this, targets[i] ) ) {
5182                                         return true;
5183                                 }
5184                         }
5185                 });
5186         },
5187
5188         not: function( selector ) {
5189                 return this.pushStack( winnow(this, selector || [], true) );
5190         },
5191
5192         filter: function( selector ) {
5193                 return this.pushStack( winnow(this, selector || [], false) );
5194         },
5195
5196         is: function( selector ) {
5197                 return !!winnow(
5198                         this,
5199
5200                         // If this is a positional/relative selector, check membership in the returned set
5201                         // so $("p:first").is("p:last") won't return true for a doc with two "p".
5202                         typeof selector === "string" && rneedsContext.test( selector ) ?
5203                                 jQuery( selector ) :
5204                                 selector || [],
5205                         false
5206                 ).length;
5207         },
5208
5209         closest: function( selectors, context ) {
5210                 var cur,
5211                         i = 0,
5212                         l = this.length,
5213                         matched = [],
5214                         pos = ( rneedsContext.test( selectors ) || typeof selectors !== "string" ) ?
5215                                 jQuery( selectors, context || this.context ) :
5216                                 0;
5217
5218                 for ( ; i < l; i++ ) {
5219                         for ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) {
5220                                 // Always skip document fragments
5221                                 if ( cur.nodeType < 11 && (pos ?
5222                                         pos.index(cur) > -1 :
5223
5224                                         // Don't pass non-elements to Sizzle
5225                                         cur.nodeType === 1 &&
5226                                                 jQuery.find.matchesSelector(cur, selectors)) ) {
5227
5228                                         cur = matched.push( cur );
5229                                         break;
5230                                 }
5231                         }
5232                 }
5233
5234                 return this.pushStack( matched.length > 1 ? jQuery.unique( matched ) : matched );
5235         },
5236
5237         // Determine the position of an element within
5238         // the matched set of elements
5239         index: function( elem ) {
5240
5241                 // No argument, return index in parent
5242                 if ( !elem ) {
5243                         return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;
5244                 }
5245
5246                 // index in selector
5247                 if ( typeof elem === "string" ) {
5248                         return core_indexOf.call( jQuery( elem ), this[ 0 ] );
5249                 }
5250
5251                 // Locate the position of the desired element
5252                 return core_indexOf.call( this,
5253
5254                         // If it receives a jQuery object, the first element is used
5255                         elem.jquery ? elem[ 0 ] : elem
5256                 );
5257         },
5258
5259         add: function( selector, context ) {
5260                 var set = typeof selector === "string" ?
5261                                 jQuery( selector, context ) :
5262                                 jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
5263                         all = jQuery.merge( this.get(), set );
5264
5265                 return this.pushStack( jQuery.unique(all) );
5266         },
5267
5268         addBack: function( selector ) {
5269                 return this.add( selector == null ?
5270                         this.prevObject : this.prevObject.filter(selector)
5271                 );
5272         }
5273 });
5274
5275 function sibling( cur, dir ) {
5276         while ( (cur = cur[dir]) && cur.nodeType !== 1 ) {}
5277
5278         return cur;
5279 }
5280
5281 jQuery.each({
5282         parent: function( elem ) {
5283                 var parent = elem.parentNode;
5284                 return parent && parent.nodeType !== 11 ? parent : null;
5285         },
5286         parents: function( elem ) {
5287                 return jQuery.dir( elem, "parentNode" );
5288         },
5289         parentsUntil: function( elem, i, until ) {
5290                 return jQuery.dir( elem, "parentNode", until );
5291         },
5292         next: function( elem ) {
5293                 return sibling( elem, "nextSibling" );
5294         },
5295         prev: function( elem ) {
5296                 return sibling( elem, "previousSibling" );
5297         },
5298         nextAll: function( elem ) {
5299                 return jQuery.dir( elem, "nextSibling" );
5300         },
5301         prevAll: function( elem ) {
5302                 return jQuery.dir( elem, "previousSibling" );
5303         },
5304         nextUntil: function( elem, i, until ) {
5305                 return jQuery.dir( elem, "nextSibling", until );
5306         },
5307         prevUntil: function( elem, i, until ) {
5308                 return jQuery.dir( elem, "previousSibling", until );
5309         },
5310         siblings: function( elem ) {
5311                 return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
5312         },
5313         children: function( elem ) {
5314                 return jQuery.sibling( elem.firstChild );
5315         },
5316         contents: function( elem ) {
5317                 return elem.contentDocument || jQuery.merge( [], elem.childNodes );
5318         }
5319 }, function( name, fn ) {
5320         jQuery.fn[ name ] = function( until, selector ) {
5321                 var matched = jQuery.map( this, fn, until );
5322
5323                 if ( name.slice( -5 ) !== "Until" ) {
5324                         selector = until;
5325                 }
5326
5327                 if ( selector && typeof selector === "string" ) {
5328                         matched = jQuery.filter( selector, matched );
5329                 }
5330
5331                 if ( this.length > 1 ) {
5332                         // Remove duplicates
5333                         if ( !guaranteedUnique[ name ] ) {
5334                                 jQuery.unique( matched );
5335                         }
5336
5337                         // Reverse order for parents* and prev-derivatives
5338                         if ( rparentsprev.test( name ) ) {
5339                                 matched.reverse();
5340                         }
5341                 }
5342
5343                 return this.pushStack( matched );
5344         };
5345 });
5346
5347 jQuery.extend({
5348         filter: function( expr, elems, not ) {
5349                 var elem = elems[ 0 ];
5350
5351                 if ( not ) {
5352                         expr = ":not(" + expr + ")";
5353                 }
5354
5355                 return elems.length === 1 && elem.nodeType === 1 ?
5356                         jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] :
5357                         jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
5358                                 return elem.nodeType === 1;
5359                         }));
5360         },
5361
5362         dir: function( elem, dir, until ) {
5363                 var matched = [],
5364                         truncate = until !== undefined;
5365
5366                 while ( (elem = elem[ dir ]) && elem.nodeType !== 9 ) {
5367                         if ( elem.nodeType === 1 ) {
5368                                 if ( truncate && jQuery( elem ).is( until ) ) {
5369                                         break;
5370                                 }
5371                                 matched.push( elem );
5372                         }
5373                 }
5374                 return matched;
5375         },
5376
5377         sibling: function( n, elem ) {
5378                 var matched = [];
5379
5380                 for ( ; n; n = n.nextSibling ) {
5381                         if ( n.nodeType === 1 && n !== elem ) {
5382                                 matched.push( n );
5383                         }
5384                 }
5385
5386                 return matched;
5387         }
5388 });
5389
5390 // Implement the identical functionality for filter and not
5391 function winnow( elements, qualifier, not ) {
5392         if ( jQuery.isFunction( qualifier ) ) {
5393                 return jQuery.grep( elements, function( elem, i ) {
5394                         /* jshint -W018 */
5395                         return !!qualifier.call( elem, i, elem ) !== not;
5396                 });
5397
5398         }
5399
5400         if ( qualifier.nodeType ) {
5401                 return jQuery.grep( elements, function( elem ) {
5402                         return ( elem === qualifier ) !== not;
5403                 });
5404
5405         }
5406
5407         if ( typeof qualifier === "string" ) {
5408                 if ( isSimple.test( qualifier ) ) {
5409                         return jQuery.filter( qualifier, elements, not );
5410                 }
5411
5412                 qualifier = jQuery.filter( qualifier, elements );
5413         }
5414
5415         return jQuery.grep( elements, function( elem ) {
5416                 return ( core_indexOf.call( qualifier, elem ) >= 0 ) !== not;
5417         });
5418 }
5419 var rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
5420         rtagName = /<([\w:]+)/,
5421         rhtml = /<|&#?\w+;/,
5422         rnoInnerhtml = /<(?:script|style|link)/i,
5423         manipulation_rcheckableType = /^(?:checkbox|radio)$/i,
5424         // checked="checked" or checked
5425         rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
5426         rscriptType = /^$|\/(?:java|ecma)script/i,
5427         rscriptTypeMasked = /^true\/(.*)/,
5428         rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,
5429
5430         // We have to close these tags to support XHTML (#13200)
5431         wrapMap = {
5432
5433                 // Support: IE 9
5434                 option: [ 1, "<select multiple='multiple'>", "</select>" ],
5435
5436                 thead: [ 1, "<table>", "</table>" ],
5437                 col: [ 2, "<table><colgroup>", "</colgroup></table>" ],
5438                 tr: [ 2, "<table><tbody>", "</tbody></table>" ],
5439                 td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
5440
5441                 _default: [ 0, "", "" ]
5442         };
5443
5444 // Support: IE 9
5445 wrapMap.optgroup = wrapMap.option;
5446
5447 wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
5448 wrapMap.th = wrapMap.td;
5449
5450 jQuery.fn.extend({
5451         text: function( value ) {
5452                 return jQuery.access( this, function( value ) {
5453                         return value === undefined ?
5454                                 jQuery.text( this ) :
5455                                 this.empty().append( ( this[ 0 ] && this[ 0 ].ownerDocument || document ).createTextNode( value ) );
5456                 }, null, value, arguments.length );
5457         },
5458
5459         append: function() {
5460                 return this.domManip( arguments, function( elem ) {
5461                         if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
5462                                 var target = manipulationTarget( this, elem );
5463                                 target.appendChild( elem );
5464                         }
5465                 });
5466         },
5467
5468         prepend: function() {
5469                 return this.domManip( arguments, function( elem ) {
5470                         if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
5471                                 var target = manipulationTarget( this, elem );
5472                                 target.insertBefore( elem, target.firstChild );
5473                         }
5474                 });
5475         },
5476
5477         before: function() {
5478                 return this.domManip( arguments, function( elem ) {
5479                         if ( this.parentNode ) {
5480                                 this.parentNode.insertBefore( elem, this );
5481                         }
5482                 });
5483         },
5484
5485         after: function() {
5486                 return this.domManip( arguments, function( elem ) {
5487                         if ( this.parentNode ) {
5488                                 this.parentNode.insertBefore( elem, this.nextSibling );
5489                         }
5490                 });
5491         },
5492
5493         // keepData is for internal use only--do not document
5494         remove: function( selector, keepData ) {
5495                 var elem,
5496                         elems = selector ? jQuery.filter( selector, this ) : this,
5497                         i = 0;
5498
5499                 for ( ; (elem = elems[i]) != null; i++ ) {
5500                         if ( !keepData && elem.nodeType === 1 ) {
5501                                 jQuery.cleanData( getAll( elem ) );
5502                         }
5503
5504                         if ( elem.parentNode ) {
5505                                 if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) {
5506                                         setGlobalEval( getAll( elem, "script" ) );
5507                                 }
5508                                 elem.parentNode.removeChild( elem );
5509                         }
5510                 }
5511
5512                 return this;
5513         },
5514
5515         empty: function() {
5516                 var elem,
5517                         i = 0;
5518
5519                 for ( ; (elem = this[i]) != null; i++ ) {
5520                         if ( elem.nodeType === 1 ) {
5521
5522                                 // Prevent memory leaks
5523                                 jQuery.cleanData( getAll( elem, false ) );
5524
5525                                 // Remove any remaining nodes
5526                                 elem.textContent = "";
5527                         }
5528                 }
5529
5530                 return this;
5531         },
5532
5533         clone: function( dataAndEvents, deepDataAndEvents ) {
5534                 dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
5535                 deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
5536
5537                 return this.map( function () {
5538                         return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
5539                 });
5540         },
5541
5542         html: function( value ) {
5543                 return jQuery.access( this, function( value ) {
5544                         var elem = this[ 0 ] || {},
5545                                 i = 0,
5546                                 l = this.length;
5547
5548                         if ( value === undefined && elem.nodeType === 1 ) {
5549                                 return elem.innerHTML;
5550                         }
5551
5552                         // See if we can take a shortcut and just use innerHTML
5553                         if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
5554                                 !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) {
5555
5556                                 value = value.replace( rxhtmlTag, "<$1></$2>" );
5557
5558                                 try {
5559                                         for ( ; i < l; i++ ) {
5560                                                 elem = this[ i ] || {};
5561
5562                                                 // Remove element nodes and prevent memory leaks
5563                                                 if ( elem.nodeType === 1 ) {
5564                                                         jQuery.cleanData( getAll( elem, false ) );
5565                                                         elem.innerHTML = value;
5566                                                 }
5567                                         }
5568
5569                                         elem = 0;
5570
5571                                 // If using innerHTML throws an exception, use the fallback method
5572                                 } catch( e ) {}
5573                         }
5574
5575                         if ( elem ) {
5576                                 this.empty().append( value );
5577                         }
5578                 }, null, value, arguments.length );
5579         },
5580
5581         replaceWith: function() {
5582                 var
5583                         // Snapshot the DOM in case .domManip sweeps something relevant into its fragment
5584                         args = jQuery.map( this, function( elem ) {
5585                                 return [ elem.nextSibling, elem.parentNode ];
5586                         }),
5587                         i = 0;
5588
5589                 // Make the changes, replacing each context element with the new content
5590                 this.domManip( arguments, function( elem ) {
5591                         var next = args[ i++ ],
5592                                 parent = args[ i++ ];
5593
5594                         if ( parent ) {
5595                                 // Don't use the snapshot next if it has moved (#13810)
5596                                 if ( next && next.parentNode !== parent ) {
5597                                         next = this.nextSibling;
5598                                 }
5599                                 jQuery( this ).remove();
5600                                 parent.insertBefore( elem, next );
5601                         }
5602                 // Allow new content to include elements from the context set
5603                 }, true );
5604
5605                 // Force removal if there was no new content (e.g., from empty arguments)
5606                 return i ? this : this.remove();
5607         },
5608
5609         detach: function( selector ) {
5610                 return this.remove( selector, true );
5611         },
5612
5613         domManip: function( args, callback, allowIntersection ) {
5614
5615                 // Flatten any nested arrays
5616                 args = core_concat.apply( [], args );
5617
5618                 var fragment, first, scripts, hasScripts, node, doc,
5619                         i = 0,
5620                         l = this.length,
5621                         set = this,
5622                         iNoClone = l - 1,
5623                         value = args[ 0 ],
5624                         isFunction = jQuery.isFunction( value );
5625
5626                 // We can't cloneNode fragments that contain checked, in WebKit
5627                 if ( isFunction || !( l <= 1 || typeof value !== "string" || jQuery.support.checkClone || !rchecked.test( value ) ) ) {
5628                         return this.each(function( index ) {
5629                                 var self = set.eq( index );
5630                                 if ( isFunction ) {
5631                                         args[ 0 ] = value.call( this, index, self.html() );
5632                                 }
5633                                 self.domManip( args, callback, allowIntersection );
5634                         });
5635                 }
5636
5637                 if ( l ) {
5638                         fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, !allowIntersection && this );
5639                         first = fragment.firstChild;
5640
5641                         if ( fragment.childNodes.length === 1 ) {
5642                                 fragment = first;
5643                         }
5644
5645                         if ( first ) {
5646                                 scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
5647                                 hasScripts = scripts.length;
5648
5649                                 // Use the original fragment for the last item instead of the first because it can end up
5650                                 // being emptied incorrectly in certain situations (#8070).
5651                                 for ( ; i < l; i++ ) {
5652                                         node = fragment;
5653
5654                                         if ( i !== iNoClone ) {
5655                                                 node = jQuery.clone( node, true, true );
5656
5657                                                 // Keep references to cloned scripts for later restoration
5658                                                 if ( hasScripts ) {
5659                                                         // Support: QtWebKit
5660                                                         // jQuery.merge because core_push.apply(_, arraylike) throws
5661                                                         jQuery.merge( scripts, getAll( node, "script" ) );
5662                                                 }
5663                                         }
5664
5665                                         callback.call( this[ i ], node, i );
5666                                 }
5667
5668                                 if ( hasScripts ) {
5669                                         doc = scripts[ scripts.length - 1 ].ownerDocument;
5670
5671                                         // Reenable scripts
5672                                         jQuery.map( scripts, restoreScript );
5673
5674                                         // Evaluate executable scripts on first document insertion
5675                                         for ( i = 0; i < hasScripts; i++ ) {
5676                                                 node = scripts[ i ];
5677                                                 if ( rscriptType.test( node.type || "" ) &&
5678                                                         !data_priv.access( node, "globalEval" ) && jQuery.contains( doc, node ) ) {
5679
5680                                                         if ( node.src ) {
5681                                                                 // Hope ajax is available...
5682                                                                 jQuery._evalUrl( node.src );
5683                                                         } else {
5684                                                                 jQuery.globalEval( node.textContent.replace( rcleanScript, "" ) );
5685                                                         }
5686                                                 }
5687                                         }
5688                                 }
5689                         }
5690                 }
5691
5692                 return this;
5693         }
5694 });
5695
5696 jQuery.each({
5697         appendTo: "append",
5698         prependTo: "prepend",
5699         insertBefore: "before",
5700         insertAfter: "after",
5701         replaceAll: "replaceWith"
5702 }, function( name, original ) {
5703         jQuery.fn[ name ] = function( selector ) {
5704                 var elems,
5705                         ret = [],
5706                         insert = jQuery( selector ),
5707                         last = insert.length - 1,
5708                         i = 0;
5709
5710                 for ( ; i <= last; i++ ) {
5711                         elems = i === last ? this : this.clone( true );
5712                         jQuery( insert[ i ] )[ original ]( elems );
5713
5714                         // Support: QtWebKit
5715                         // .get() because core_push.apply(_, arraylike) throws
5716                         core_push.apply( ret, elems.get() );
5717                 }
5718
5719                 return this.pushStack( ret );
5720         };
5721 });
5722
5723 jQuery.extend({
5724         clone: function( elem, dataAndEvents, deepDataAndEvents ) {
5725                 var i, l, srcElements, destElements,
5726                         clone = elem.cloneNode( true ),
5727                         inPage = jQuery.contains( elem.ownerDocument, elem );
5728
5729                 // Support: IE >= 9
5730                 // Fix Cloning issues
5731                 if ( !jQuery.support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && !jQuery.isXMLDoc( elem ) ) {
5732
5733                         // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2
5734                         destElements = getAll( clone );
5735                         srcElements = getAll( elem );
5736
5737                         for ( i = 0, l = srcElements.length; i < l; i++ ) {
5738                                 fixInput( srcElements[ i ], destElements[ i ] );
5739                         }
5740                 }
5741
5742                 // Copy the events from the original to the clone
5743                 if ( dataAndEvents ) {
5744                         if ( deepDataAndEvents ) {
5745                                 srcElements = srcElements || getAll( elem );
5746                                 destElements = destElements || getAll( clone );
5747
5748                                 for ( i = 0, l = srcElements.length; i < l; i++ ) {
5749                                         cloneCopyEvent( srcElements[ i ], destElements[ i ] );
5750                                 }
5751                         } else {
5752                                 cloneCopyEvent( elem, clone );
5753                         }
5754                 }
5755
5756                 // Preserve script evaluation history
5757                 destElements = getAll( clone, "script" );
5758                 if ( destElements.length > 0 ) {
5759                         setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
5760                 }
5761
5762                 // Return the cloned set
5763                 return clone;
5764         },
5765
5766         buildFragment: function( elems, context, scripts, selection ) {
5767                 var elem, tmp, tag, wrap, contains, j,
5768                         i = 0,
5769                         l = elems.length,
5770                         fragment = context.createDocumentFragment(),
5771                         nodes = [];
5772
5773                 for ( ; i < l; i++ ) {
5774                         elem = elems[ i ];
5775
5776                         if ( elem || elem === 0 ) {
5777
5778                                 // Add nodes directly
5779                                 if ( jQuery.type( elem ) === "object" ) {
5780                                         // Support: QtWebKit
5781                                         // jQuery.merge because core_push.apply(_, arraylike) throws
5782                                         jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
5783
5784                                 // Convert non-html into a text node
5785                                 } else if ( !rhtml.test( elem ) ) {
5786                                         nodes.push( context.createTextNode( elem ) );
5787
5788                                 // Convert html into DOM nodes
5789                                 } else {
5790                                         tmp = tmp || fragment.appendChild( context.createElement("div") );
5791
5792                                         // Deserialize a standard representation
5793                                         tag = ( rtagName.exec( elem ) || ["", ""] )[ 1 ].toLowerCase();
5794                                         wrap = wrapMap[ tag ] || wrapMap._default;
5795                                         tmp.innerHTML = wrap[ 1 ] + elem.replace( rxhtmlTag, "<$1></$2>" ) + wrap[ 2 ];
5796
5797                                         // Descend through wrappers to the right content
5798                                         j = wrap[ 0 ];
5799                                         while ( j-- ) {
5800                                                 tmp = tmp.lastChild;
5801                                         }
5802
5803                                         // Support: QtWebKit
5804                                         // jQuery.merge because core_push.apply(_, arraylike) throws
5805                                         jQuery.merge( nodes, tmp.childNodes );
5806
5807                                         // Remember the top-level container
5808                                         tmp = fragment.firstChild;
5809
5810                                         // Fixes #12346
5811                                         // Support: Webkit, IE
5812                                         tmp.textContent = "";
5813                                 }
5814                         }
5815                 }
5816
5817                 // Remove wrapper from fragment
5818                 fragment.textContent = "";
5819
5820                 i = 0;
5821                 while ( (elem = nodes[ i++ ]) ) {
5822
5823                         // #4087 - If origin and destination elements are the same, and this is
5824                         // that element, do not do anything
5825                         if ( selection && jQuery.inArray( elem, selection ) !== -1 ) {
5826                                 continue;
5827                         }
5828
5829                         contains = jQuery.contains( elem.ownerDocument, elem );
5830
5831                         // Append to fragment
5832                         tmp = getAll( fragment.appendChild( elem ), "script" );
5833
5834                         // Preserve script evaluation history
5835                         if ( contains ) {
5836                                 setGlobalEval( tmp );
5837                         }
5838
5839                         // Capture executables
5840                         if ( scripts ) {
5841                                 j = 0;
5842                                 while ( (elem = tmp[ j++ ]) ) {
5843                                         if ( rscriptType.test( elem.type || "" ) ) {
5844                                                 scripts.push( elem );
5845                                         }
5846                                 }
5847                         }
5848                 }
5849
5850                 return fragment;
5851         },
5852
5853         cleanData: function( elems ) {
5854                 var data, elem, events, type, key, j,
5855                         special = jQuery.event.special,
5856                         i = 0;
5857
5858                 for ( ; (elem = elems[ i ]) !== undefined; i++ ) {
5859                         if ( Data.accepts( elem ) ) {
5860                                 key = elem[ data_priv.expando ];
5861
5862                                 if ( key && (data = data_priv.cache[ key ]) ) {
5863                                         events = Object.keys( data.events || {} );
5864                                         if ( events.length ) {
5865                                                 for ( j = 0; (type = events[j]) !== undefined; j++ ) {
5866                                                         if ( special[ type ] ) {
5867                                                                 jQuery.event.remove( elem, type );
5868
5869                                                         // This is a shortcut to avoid jQuery.event.remove's overhead
5870                                                         } else {
5871                                                                 jQuery.removeEvent( elem, type, data.handle );
5872                                                         }
5873                                                 }
5874                                         }
5875                                         if ( data_priv.cache[ key ] ) {
5876                                                 // Discard any remaining `private` data
5877                                                 delete data_priv.cache[ key ];
5878                                         }
5879                                 }
5880                         }
5881                         // Discard any remaining `user` data
5882                         delete data_user.cache[ elem[ data_user.expando ] ];
5883                 }
5884         },
5885
5886         _evalUrl: function( url ) {
5887                 return jQuery.ajax({
5888                         url: url,
5889                         type: "GET",
5890                         dataType: "script",
5891                         async: false,
5892                         global: false,
5893                         "throws": true
5894                 });
5895         }
5896 });
5897
5898 // Support: 1.x compatibility
5899 // Manipulating tables requires a tbody
5900 function manipulationTarget( elem, content ) {
5901         return jQuery.nodeName( elem, "table" ) &&
5902                 jQuery.nodeName( content.nodeType === 1 ? content : content.firstChild, "tr" ) ?
5903
5904                 elem.getElementsByTagName("tbody")[0] ||
5905                         elem.appendChild( elem.ownerDocument.createElement("tbody") ) :
5906                 elem;
5907 }
5908
5909 // Replace/restore the type attribute of script elements for safe DOM manipulation
5910 function disableScript( elem ) {
5911         elem.type = (elem.getAttribute("type") !== null) + "/" + elem.type;
5912         return elem;
5913 }
5914 function restoreScript( elem ) {
5915         var match = rscriptTypeMasked.exec( elem.type );
5916
5917         if ( match ) {
5918                 elem.type = match[ 1 ];
5919         } else {
5920                 elem.removeAttribute("type");
5921         }
5922
5923         return elem;
5924 }
5925
5926 // Mark scripts as having already been evaluated
5927 function setGlobalEval( elems, refElements ) {
5928         var l = elems.length,
5929                 i = 0;
5930
5931         for ( ; i < l; i++ ) {
5932                 data_priv.set(
5933                         elems[ i ], "globalEval", !refElements || data_priv.get( refElements[ i ], "globalEval" )
5934                 );
5935         }
5936 }
5937
5938 function cloneCopyEvent( src, dest ) {
5939         var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events;
5940
5941         if ( dest.nodeType !== 1 ) {
5942                 return;
5943         }
5944
5945         // 1. Copy private data: events, handlers, etc.
5946         if ( data_priv.hasData( src ) ) {
5947                 pdataOld = data_priv.access( src );
5948                 pdataCur = data_priv.set( dest, pdataOld );
5949                 events = pdataOld.events;
5950
5951                 if ( events ) {
5952                         delete pdataCur.handle;
5953                         pdataCur.events = {};
5954
5955                         for ( type in events ) {
5956                                 for ( i = 0, l = events[ type ].length; i < l; i++ ) {
5957                                         jQuery.event.add( dest, type, events[ type ][ i ] );
5958                                 }
5959                         }
5960                 }
5961         }
5962
5963         // 2. Copy user data
5964         if ( data_user.hasData( src ) ) {
5965                 udataOld = data_user.access( src );
5966                 udataCur = jQuery.extend( {}, udataOld );
5967
5968                 data_user.set( dest, udataCur );
5969         }
5970 }
5971
5972
5973 function getAll( context, tag ) {
5974         var ret = context.getElementsByTagName ? context.getElementsByTagName( tag || "*" ) :
5975                         context.querySelectorAll ? context.querySelectorAll( tag || "*" ) :
5976                         [];
5977
5978         return tag === undefined || tag && jQuery.nodeName( context, tag ) ?
5979                 jQuery.merge( [ context ], ret ) :
5980                 ret;
5981 }
5982
5983 // Support: IE >= 9
5984 function fixInput( src, dest ) {
5985         var nodeName = dest.nodeName.toLowerCase();
5986
5987         // Fails to persist the checked state of a cloned checkbox or radio button.
5988         if ( nodeName === "input" && manipulation_rcheckableType.test( src.type ) ) {
5989                 dest.checked = src.checked;
5990
5991         // Fails to return the selected option to the default selected state when cloning options
5992         } else if ( nodeName === "input" || nodeName === "textarea" ) {
5993                 dest.defaultValue = src.defaultValue;
5994         }
5995 }
5996 jQuery.fn.extend({
5997         wrapAll: function( html ) {
5998                 var wrap;
5999
6000                 if ( jQuery.isFunction( html ) ) {
6001                         return this.each(function( i ) {
6002                                 jQuery( this ).wrapAll( html.call(this, i) );
6003                         });
6004                 }
6005
6006                 if ( this[ 0 ] ) {
6007
6008                         // The elements to wrap the target around
6009                         wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true );
6010
6011                         if ( this[ 0 ].parentNode ) {
6012                                 wrap.insertBefore( this[ 0 ] );
6013                         }
6014
6015                         wrap.map(function() {
6016                                 var elem = this;
6017
6018                                 while ( elem.firstElementChild ) {
6019                                         elem = elem.firstElementChild;
6020                                 }
6021
6022                                 return elem;
6023                         }).append( this );
6024                 }
6025
6026                 return this;
6027         },
6028
6029         wrapInner: function( html ) {
6030                 if ( jQuery.isFunction( html ) ) {
6031                         return this.each(function( i ) {
6032                                 jQuery( this ).wrapInner( html.call(this, i) );
6033                         });
6034                 }
6035
6036                 return this.each(function() {
6037                         var self = jQuery( this ),
6038                                 contents = self.contents();
6039
6040                         if ( contents.length ) {
6041                                 contents.wrapAll( html );
6042
6043                         } else {
6044                                 self.append( html );
6045                         }
6046                 });
6047         },
6048
6049         wrap: function( html ) {
6050                 var isFunction = jQuery.isFunction( html );
6051
6052                 return this.each(function( i ) {
6053                         jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
6054                 });
6055         },
6056
6057         unwrap: function() {
6058                 return this.parent().each(function() {
6059                         if ( !jQuery.nodeName( this, "body" ) ) {
6060                                 jQuery( this ).replaceWith( this.childNodes );
6061                         }
6062                 }).end();
6063         }
6064 });
6065 var curCSS, iframe,
6066         // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
6067         // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
6068         rdisplayswap = /^(none|table(?!-c[ea]).+)/,
6069         rmargin = /^margin/,
6070         rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ),
6071         rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ),
6072         rrelNum = new RegExp( "^([+-])=(" + core_pnum + ")", "i" ),
6073         elemdisplay = { BODY: "block" },
6074
6075         cssShow = { position: "absolute", visibility: "hidden", display: "block" },
6076         cssNormalTransform = {
6077                 letterSpacing: 0,
6078                 fontWeight: 400
6079         },
6080
6081         cssExpand = [ "Top", "Right", "Bottom", "Left" ],
6082         cssPrefixes = [ "Webkit", "O", "Moz", "ms" ];
6083
6084 // return a css property mapped to a potentially vendor prefixed property
6085 function vendorPropName( style, name ) {
6086
6087         // shortcut for names that are not vendor prefixed
6088         if ( name in style ) {
6089                 return name;
6090         }
6091
6092         // check for vendor prefixed names
6093         var capName = name.charAt(0).toUpperCase() + name.slice(1),
6094                 origName = name,
6095                 i = cssPrefixes.length;
6096
6097         while ( i-- ) {
6098                 name = cssPrefixes[ i ] + capName;
6099                 if ( name in style ) {
6100                         return name;
6101                 }
6102         }
6103
6104         return origName;
6105 }
6106
6107 function isHidden( elem, el ) {
6108         // isHidden might be called from jQuery#filter function;
6109         // in that case, element will be second argument
6110         elem = el || elem;
6111         return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem );
6112 }
6113
6114 // NOTE: we've included the "window" in window.getComputedStyle
6115 // because jsdom on node.js will break without it.
6116 function getStyles( elem ) {
6117         return window.getComputedStyle( elem, null );
6118 }
6119
6120 function showHide( elements, show ) {
6121         var display, elem, hidden,
6122                 values = [],
6123                 index = 0,
6124                 length = elements.length;
6125
6126         for ( ; index < length; index++ ) {
6127                 elem = elements[ index ];
6128                 if ( !elem.style ) {
6129                         continue;
6130                 }
6131
6132                 values[ index ] = data_priv.get( elem, "olddisplay" );
6133                 display = elem.style.display;
6134                 if ( show ) {
6135                         // Reset the inline display of this element to learn if it is
6136                         // being hidden by cascaded rules or not
6137                         if ( !values[ index ] && display === "none" ) {
6138                                 elem.style.display = "";
6139                         }
6140
6141                         // Set elements which have been overridden with display: none
6142                         // in a stylesheet to whatever the default browser style is
6143                         // for such an element
6144                         if ( elem.style.display === "" && isHidden( elem ) ) {
6145                                 values[ index ] = data_priv.access( elem, "olddisplay", css_defaultDisplay(elem.nodeName) );
6146                         }
6147                 } else {
6148
6149                         if ( !values[ index ] ) {
6150                                 hidden = isHidden( elem );
6151
6152                                 if ( display && display !== "none" || !hidden ) {
6153                                         data_priv.set( elem, "olddisplay", hidden ? display : jQuery.css(elem, "display") );
6154                                 }
6155                         }
6156                 }
6157         }
6158
6159         // Set the display of most of the elements in a second loop
6160         // to avoid the constant reflow
6161         for ( index = 0; index < length; index++ ) {
6162                 elem = elements[ index ];
6163                 if ( !elem.style ) {
6164                         continue;
6165                 }
6166                 if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
6167                         elem.style.display = show ? values[ index ] || "" : "none";
6168                 }
6169         }
6170
6171         return elements;
6172 }
6173
6174 jQuery.fn.extend({
6175         css: function( name, value ) {
6176                 return jQuery.access( this, function( elem, name, value ) {
6177                         var styles, len,
6178                                 map = {},
6179                                 i = 0;
6180
6181                         if ( jQuery.isArray( name ) ) {
6182                                 styles = getStyles( elem );
6183                                 len = name.length;
6184
6185                                 for ( ; i < len; i++ ) {
6186                                         map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
6187                                 }
6188
6189                                 return map;
6190                         }
6191
6192                         return value !== undefined ?
6193                                 jQuery.style( elem, name, value ) :
6194                                 jQuery.css( elem, name );
6195                 }, name, value, arguments.length > 1 );
6196         },
6197         show: function() {
6198                 return showHide( this, true );
6199         },
6200         hide: function() {
6201                 return showHide( this );
6202         },
6203         toggle: function( state ) {
6204                 if ( typeof state === "boolean" ) {
6205                         return state ? this.show() : this.hide();
6206                 }
6207
6208                 return this.each(function() {
6209                         if ( isHidden( this ) ) {
6210                                 jQuery( this ).show();
6211                         } else {
6212                                 jQuery( this ).hide();
6213                         }
6214                 });
6215         }
6216 });
6217
6218 jQuery.extend({
6219         // Add in style property hooks for overriding the default
6220         // behavior of getting and setting a style property
6221         cssHooks: {
6222                 opacity: {
6223                         get: function( elem, computed ) {
6224                                 if ( computed ) {
6225                                         // We should always get a number back from opacity
6226                                         var ret = curCSS( elem, "opacity" );
6227                                         return ret === "" ? "1" : ret;
6228                                 }
6229                         }
6230                 }
6231         },
6232
6233         // Don't automatically add "px" to these possibly-unitless properties
6234         cssNumber: {
6235                 "columnCount": true,
6236                 "fillOpacity": true,
6237                 "fontWeight": true,
6238                 "lineHeight": true,
6239                 "opacity": true,
6240                 "order": true,
6241                 "orphans": true,
6242                 "widows": true,
6243                 "zIndex": true,
6244                 "zoom": true
6245         },
6246
6247         // Add in properties whose names you wish to fix before
6248         // setting or getting the value
6249         cssProps: {
6250                 // normalize float css property
6251                 "float": "cssFloat"
6252         },
6253
6254         // Get and set the style property on a DOM Node
6255         style: function( elem, name, value, extra ) {
6256                 // Don't set styles on text and comment nodes
6257                 if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
6258                         return;
6259                 }
6260
6261                 // Make sure that we're working with the right name
6262                 var ret, type, hooks,
6263                         origName = jQuery.camelCase( name ),
6264                         style = elem.style;
6265
6266                 name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );
6267
6268                 // gets hook for the prefixed version
6269                 // followed by the unprefixed version
6270                 hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
6271
6272                 // Check if we're setting a value
6273                 if ( value !== undefined ) {
6274                         type = typeof value;
6275
6276                         // convert relative number strings (+= or -=) to relative numbers. #7345
6277                         if ( type === "string" && (ret = rrelNum.exec( value )) ) {
6278                                 value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );
6279                                 // Fixes bug #9237
6280                                 type = "number";
6281                         }
6282
6283                         // Make sure that NaN and null values aren't set. See: #7116
6284                         if ( value == null || type === "number" && isNaN( value ) ) {
6285                                 return;
6286                         }
6287
6288                         // If a number was passed in, add 'px' to the (except for certain CSS properties)
6289                         if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
6290                                 value += "px";
6291                         }
6292
6293                         // Fixes #8908, it can be done more correctly by specifying setters in cssHooks,
6294                         // but it would mean to define eight (for every problematic property) identical functions
6295                         if ( !jQuery.support.clearCloneStyle && value === "" && name.indexOf("background") === 0 ) {
6296                                 style[ name ] = "inherit";
6297                         }
6298
6299                         // If a hook was provided, use that value, otherwise just set the specified value
6300                         if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {
6301                                 style[ name ] = value;
6302                         }
6303
6304                 } else {
6305                         // If a hook was provided get the non-computed value from there
6306                         if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
6307                                 return ret;
6308                         }
6309
6310                         // Otherwise just get the value from the style object
6311                         return style[ name ];
6312                 }
6313         },
6314
6315         css: function( elem, name, extra, styles ) {
6316                 var val, num, hooks,
6317                         origName = jQuery.camelCase( name );
6318
6319                 // Make sure that we're working with the right name
6320                 name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );
6321
6322                 // gets hook for the prefixed version
6323                 // followed by the unprefixed version
6324                 hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
6325
6326                 // If a hook was provided get the computed value from there
6327                 if ( hooks && "get" in hooks ) {
6328                         val = hooks.get( elem, true, extra );
6329                 }
6330
6331                 // Otherwise, if a way to get the computed value exists, use that
6332                 if ( val === undefined ) {
6333                         val = curCSS( elem, name, styles );
6334                 }
6335
6336                 //convert "normal" to computed value
6337                 if ( val === "normal" && name in cssNormalTransform ) {
6338                         val = cssNormalTransform[ name ];
6339                 }
6340
6341                 // Return, converting to number if forced or a qualifier was provided and val looks numeric
6342                 if ( extra === "" || extra ) {
6343                         num = parseFloat( val );
6344                         return extra === true || jQuery.isNumeric( num ) ? num || 0 : val;
6345                 }
6346                 return val;
6347         }
6348 });
6349
6350 curCSS = function( elem, name, _computed ) {
6351         var width, minWidth, maxWidth,
6352                 computed = _computed || getStyles( elem ),
6353
6354                 // Support: IE9
6355                 // getPropertyValue is only needed for .css('filter') in IE9, see #12537
6356                 ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined,
6357                 style = elem.style;
6358
6359         if ( computed ) {
6360
6361                 if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
6362                         ret = jQuery.style( elem, name );
6363                 }
6364
6365                 // Support: Safari 5.1
6366                 // A tribute to the "awesome hack by Dean Edwards"
6367                 // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels
6368                 // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
6369                 if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {
6370
6371                         // Remember the original values
6372                         width = style.width;
6373                         minWidth = style.minWidth;
6374                         maxWidth = style.maxWidth;
6375
6376                         // Put in the new values to get a computed value out
6377                         style.minWidth = style.maxWidth = style.width = ret;
6378                         ret = computed.width;
6379
6380                         // Revert the changed values
6381                         style.width = width;
6382                         style.minWidth = minWidth;
6383                         style.maxWidth = maxWidth;
6384                 }
6385         }
6386
6387         return ret;
6388 };
6389
6390
6391 function setPositiveNumber( elem, value, subtract ) {
6392         var matches = rnumsplit.exec( value );
6393         return matches ?
6394                 // Guard against undefined "subtract", e.g., when used as in cssHooks
6395                 Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) :
6396                 value;
6397 }
6398
6399 function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
6400         var i = extra === ( isBorderBox ? "border" : "content" ) ?
6401                 // If we already have the right measurement, avoid augmentation
6402                 4 :
6403                 // Otherwise initialize for horizontal or vertical properties
6404                 name === "width" ? 1 : 0,
6405
6406                 val = 0;
6407
6408         for ( ; i < 4; i += 2 ) {
6409                 // both box models exclude margin, so add it if we want it
6410                 if ( extra === "margin" ) {
6411                         val += jQuery.css( elem, extra + cssExpand[ i ], true, styles );
6412                 }
6413
6414                 if ( isBorderBox ) {
6415                         // border-box includes padding, so remove it if we want content
6416                         if ( extra === "content" ) {
6417                                 val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
6418                         }
6419
6420                         // at this point, extra isn't border nor margin, so remove border
6421                         if ( extra !== "margin" ) {
6422                                 val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
6423                         }
6424                 } else {
6425                         // at this point, extra isn't content, so add padding
6426                         val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
6427
6428                         // at this point, extra isn't content nor padding, so add border
6429                         if ( extra !== "padding" ) {
6430                                 val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
6431                         }
6432                 }
6433         }
6434
6435         return val;
6436 }
6437
6438 function getWidthOrHeight( elem, name, extra ) {
6439
6440         // Start with offset property, which is equivalent to the border-box value
6441         var valueIsBorderBox = true,
6442                 val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
6443                 styles = getStyles( elem ),
6444                 isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
6445
6446         // some non-html elements return undefined for offsetWidth, so check for null/undefined
6447         // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
6448         // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
6449         if ( val <= 0 || val == null ) {
6450                 // Fall back to computed then uncomputed css if necessary
6451                 val = curCSS( elem, name, styles );
6452                 if ( val < 0 || val == null ) {
6453                         val = elem.style[ name ];
6454                 }
6455
6456                 // Computed unit is not pixels. Stop here and return.
6457                 if ( rnumnonpx.test(val) ) {
6458                         return val;
6459                 }
6460
6461                 // we need the check for style in case a browser which returns unreliable values
6462                 // for getComputedStyle silently falls back to the reliable elem.style
6463                 valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] );
6464
6465                 // Normalize "", auto, and prepare for extra
6466                 val = parseFloat( val ) || 0;
6467         }
6468
6469         // use the active box-sizing model to add/subtract irrelevant styles
6470         return ( val +
6471                 augmentWidthOrHeight(
6472                         elem,
6473                         name,
6474                         extra || ( isBorderBox ? "border" : "content" ),
6475                         valueIsBorderBox,
6476                         styles
6477                 )
6478         ) + "px";
6479 }
6480
6481 // Try to determine the default display value of an element
6482 function css_defaultDisplay( nodeName ) {
6483         var doc = document,
6484                 display = elemdisplay[ nodeName ];
6485
6486         if ( !display ) {
6487                 display = actualDisplay( nodeName, doc );
6488
6489                 // If the simple way fails, read from inside an iframe
6490                 if ( display === "none" || !display ) {
6491                         // Use the already-created iframe if possible
6492                         iframe = ( iframe ||
6493                                 jQuery("<iframe frameborder='0' width='0' height='0'/>")
6494                                 .css( "cssText", "display:block !important" )
6495                         ).appendTo( doc.documentElement );
6496
6497                         // Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse
6498                         doc = ( iframe[0].contentWindow || iframe[0].contentDocument ).document;
6499                         doc.write("<!doctype html><html><body>");
6500                         doc.close();
6501
6502                         display = actualDisplay( nodeName, doc );
6503                         iframe.detach();
6504                 }
6505
6506                 // Store the correct default display
6507                 elemdisplay[ nodeName ] = display;
6508         }
6509
6510         return display;
6511 }
6512
6513 // Called ONLY from within css_defaultDisplay
6514 function actualDisplay( name, doc ) {
6515         var elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),
6516                 display = jQuery.css( elem[0], "display" );
6517         elem.remove();
6518         return display;
6519 }
6520
6521 jQuery.each([ "height", "width" ], function( i, name ) {
6522         jQuery.cssHooks[ name ] = {
6523                 get: function( elem, computed, extra ) {
6524                         if ( computed ) {
6525                                 // certain elements can have dimension info if we invisibly show them
6526                                 // however, it must have a current display style that would benefit from this
6527                                 return elem.offsetWidth === 0 && rdisplayswap.test( jQuery.css( elem, "display" ) ) ?
6528                                         jQuery.swap( elem, cssShow, function() {
6529                                                 return getWidthOrHeight( elem, name, extra );
6530                                         }) :
6531                                         getWidthOrHeight( elem, name, extra );
6532                         }
6533                 },
6534
6535                 set: function( elem, value, extra ) {
6536                         var styles = extra && getStyles( elem );
6537                         return setPositiveNumber( elem, value, extra ?
6538                                 augmentWidthOrHeight(
6539                                         elem,
6540                                         name,
6541                                         extra,
6542                                         jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
6543                                         styles
6544                                 ) : 0
6545                         );
6546                 }
6547         };
6548 });
6549
6550 // These hooks cannot be added until DOM ready because the support test
6551 // for it is not run until after DOM ready
6552 jQuery(function() {
6553         // Support: Android 2.3
6554         if ( !jQuery.support.reliableMarginRight ) {
6555                 jQuery.cssHooks.marginRight = {
6556                         get: function( elem, computed ) {
6557                                 if ( computed ) {
6558                                         // Support: Android 2.3
6559                                         // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
6560                                         // Work around by temporarily setting element display to inline-block
6561                                         return jQuery.swap( elem, { "display": "inline-block" },
6562                                                 curCSS, [ elem, "marginRight" ] );
6563                                 }
6564                         }
6565                 };
6566         }
6567
6568         // Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
6569         // getComputedStyle returns percent when specified for top/left/bottom/right
6570         // rather than make the css module depend on the offset module, we just check for it here
6571         if ( !jQuery.support.pixelPosition && jQuery.fn.position ) {
6572                 jQuery.each( [ "top", "left" ], function( i, prop ) {
6573                         jQuery.cssHooks[ prop ] = {
6574                                 get: function( elem, computed ) {
6575                                         if ( computed ) {
6576                                                 computed = curCSS( elem, prop );
6577                                                 // if curCSS returns percentage, fallback to offset
6578                                                 return rnumnonpx.test( computed ) ?
6579                                                         jQuery( elem ).position()[ prop ] + "px" :
6580                                                         computed;
6581                                         }
6582                                 }
6583                         };
6584                 });
6585         }
6586
6587 });
6588
6589 if ( jQuery.expr && jQuery.expr.filters ) {
6590         jQuery.expr.filters.hidden = function( elem ) {
6591                 // Support: Opera <= 12.12
6592                 // Opera reports offsetWidths and offsetHeights less than zero on some elements
6593                 return elem.offsetWidth <= 0 && elem.offsetHeight <= 0;
6594         };
6595
6596         jQuery.expr.filters.visible = function( elem ) {
6597                 return !jQuery.expr.filters.hidden( elem );
6598         };
6599 }
6600
6601 // These hooks are used by animate to expand properties
6602 jQuery.each({
6603         margin: "",
6604         padding: "",
6605         border: "Width"
6606 }, function( prefix, suffix ) {
6607         jQuery.cssHooks[ prefix + suffix ] = {
6608                 expand: function( value ) {
6609                         var i = 0,
6610                                 expanded = {},
6611
6612                                 // assumes a single number if not a string
6613                                 parts = typeof value === "string" ? value.split(" ") : [ value ];
6614
6615                         for ( ; i < 4; i++ ) {
6616                                 expanded[ prefix + cssExpand[ i ] + suffix ] =
6617                                         parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
6618                         }
6619
6620                         return expanded;
6621                 }
6622         };
6623
6624         if ( !rmargin.test( prefix ) ) {
6625                 jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
6626         }
6627 });
6628 var r20 = /%20/g,
6629         rbracket = /\[\]$/,
6630         rCRLF = /\r?\n/g,
6631         rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
6632         rsubmittable = /^(?:input|select|textarea|keygen)/i;
6633
6634 jQuery.fn.extend({
6635         serialize: function() {
6636                 return jQuery.param( this.serializeArray() );
6637         },
6638         serializeArray: function() {
6639                 return this.map(function(){
6640                         // Can add propHook for "elements" to filter or add form elements
6641                         var elements = jQuery.prop( this, "elements" );
6642                         return elements ? jQuery.makeArray( elements ) : this;
6643                 })
6644                 .filter(function(){
6645                         var type = this.type;
6646                         // Use .is(":disabled") so that fieldset[disabled] works
6647                         return this.name && !jQuery( this ).is( ":disabled" ) &&
6648                                 rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
6649                                 ( this.checked || !manipulation_rcheckableType.test( type ) );
6650                 })
6651                 .map(function( i, elem ){
6652                         var val = jQuery( this ).val();
6653
6654                         return val == null ?
6655                                 null :
6656                                 jQuery.isArray( val ) ?
6657                                         jQuery.map( val, function( val ){
6658                                                 return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
6659                                         }) :
6660                                         { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
6661                 }).get();
6662         }
6663 });
6664
6665 //Serialize an array of form elements or a set of
6666 //key/values into a query string
6667 jQuery.param = function( a, traditional ) {
6668         var prefix,
6669                 s = [],
6670                 add = function( key, value ) {
6671                         // If value is a function, invoke it and return its value
6672                         value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
6673                         s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
6674                 };
6675
6676         // Set traditional to true for jQuery <= 1.3.2 behavior.
6677         if ( traditional === undefined ) {
6678                 traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;
6679         }
6680
6681         // If an array was passed in, assume that it is an array of form elements.
6682         if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
6683                 // Serialize the form elements
6684                 jQuery.each( a, function() {
6685                         add( this.name, this.value );
6686                 });
6687
6688         } else {
6689                 // If traditional, encode the "old" way (the way 1.3.2 or older
6690                 // did it), otherwise encode params recursively.
6691                 for ( prefix in a ) {
6692                         buildParams( prefix, a[ prefix ], traditional, add );
6693                 }
6694         }
6695
6696         // Return the resulting serialization
6697         return s.join( "&" ).replace( r20, "+" );
6698 };
6699
6700 function buildParams( prefix, obj, traditional, add ) {
6701         var name;
6702
6703         if ( jQuery.isArray( obj ) ) {
6704                 // Serialize array item.
6705                 jQuery.each( obj, function( i, v ) {
6706                         if ( traditional || rbracket.test( prefix ) ) {
6707                                 // Treat each array item as a scalar.
6708                                 add( prefix, v );
6709
6710                         } else {
6711                                 // Item is non-scalar (array or object), encode its numeric index.
6712                                 buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
6713                         }
6714                 });
6715
6716         } else if ( !traditional && jQuery.type( obj ) === "object" ) {
6717                 // Serialize object item.
6718                 for ( name in obj ) {
6719                         buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
6720                 }
6721
6722         } else {
6723                 // Serialize scalar item.
6724                 add( prefix, obj );
6725         }
6726 }
6727 jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
6728         "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
6729         "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
6730
6731         // Handle event binding
6732         jQuery.fn[ name ] = function( data, fn ) {
6733                 return arguments.length > 0 ?
6734                         this.on( name, null, data, fn ) :
6735                         this.trigger( name );
6736         };
6737 });
6738
6739 jQuery.fn.extend({
6740         hover: function( fnOver, fnOut ) {
6741                 return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
6742         },
6743
6744         bind: function( types, data, fn ) {
6745                 return this.on( types, null, data, fn );
6746         },
6747         unbind: function( types, fn ) {
6748                 return this.off( types, null, fn );
6749         },
6750
6751         delegate: function( selector, types, data, fn ) {
6752                 return this.on( types, selector, data, fn );
6753         },
6754         undelegate: function( selector, types, fn ) {
6755                 // ( namespace ) or ( selector, types [, fn] )
6756                 return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn );
6757         }
6758 });
6759 var
6760         // Document location
6761         ajaxLocParts,
6762         ajaxLocation,
6763
6764         ajax_nonce = jQuery.now(),
6765
6766         ajax_rquery = /\?/,
6767         rhash = /#.*$/,
6768         rts = /([?&])_=[^&]*/,
6769         rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg,
6770         // #7653, #8125, #8152: local protocol detection
6771         rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
6772         rnoContent = /^(?:GET|HEAD)$/,
6773         rprotocol = /^\/\//,
6774         rurl = /^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,
6775
6776         // Keep a copy of the old load method
6777         _load = jQuery.fn.load,
6778
6779         /* Prefilters
6780          * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
6781          * 2) These are called:
6782          *    - BEFORE asking for a transport
6783          *    - AFTER param serialization (s.data is a string if s.processData is true)
6784          * 3) key is the dataType
6785          * 4) the catchall symbol "*" can be used
6786          * 5) execution will start with transport dataType and THEN continue down to "*" if needed
6787          */
6788         prefilters = {},
6789
6790         /* Transports bindings
6791          * 1) key is the dataType
6792          * 2) the catchall symbol "*" can be used
6793          * 3) selection will start with transport dataType and THEN go to "*" if needed
6794          */
6795         transports = {},
6796
6797         // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
6798         allTypes = "*/".concat("*");
6799
6800 // #8138, IE may throw an exception when accessing
6801 // a field from window.location if document.domain has been set
6802 try {
6803         ajaxLocation = location.href;
6804 } catch( e ) {
6805         // Use the href attribute of an A element
6806         // since IE will modify it given document.location
6807         ajaxLocation = document.createElement( "a" );
6808         ajaxLocation.href = "";
6809         ajaxLocation = ajaxLocation.href;
6810 }
6811
6812 // Segment location into parts
6813 ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
6814
6815 // Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
6816 function addToPrefiltersOrTransports( structure ) {
6817
6818         // dataTypeExpression is optional and defaults to "*"
6819         return function( dataTypeExpression, func ) {
6820
6821                 if ( typeof dataTypeExpression !== "string" ) {
6822                         func = dataTypeExpression;
6823                         dataTypeExpression = "*";
6824                 }
6825
6826                 var dataType,
6827                         i = 0,
6828                         dataTypes = dataTypeExpression.toLowerCase().match( core_rnotwhite ) || [];
6829
6830                 if ( jQuery.isFunction( func ) ) {
6831                         // For each dataType in the dataTypeExpression
6832                         while ( (dataType = dataTypes[i++]) ) {
6833                                 // Prepend if requested
6834                                 if ( dataType[0] === "+" ) {
6835                                         dataType = dataType.slice( 1 ) || "*";
6836                                         (structure[ dataType ] = structure[ dataType ] || []).unshift( func );
6837
6838                                 // Otherwise append
6839                                 } else {
6840                                         (structure[ dataType ] = structure[ dataType ] || []).push( func );
6841                                 }
6842                         }
6843                 }
6844         };
6845 }
6846
6847 // Base inspection function for prefilters and transports
6848 function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
6849
6850         var inspected = {},
6851                 seekingTransport = ( structure === transports );
6852
6853         function inspect( dataType ) {
6854                 var selected;
6855                 inspected[ dataType ] = true;
6856                 jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
6857                         var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
6858                         if( typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) {
6859                                 options.dataTypes.unshift( dataTypeOrTransport );
6860                                 inspect( dataTypeOrTransport );
6861                                 return false;
6862                         } else if ( seekingTransport ) {
6863                                 return !( selected = dataTypeOrTransport );
6864                         }
6865                 });
6866                 return selected;
6867         }
6868
6869         return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
6870 }
6871
6872 // A special extend for ajax options
6873 // that takes "flat" options (not to be deep extended)
6874 // Fixes #9887
6875 function ajaxExtend( target, src ) {
6876         var key, deep,
6877                 flatOptions = jQuery.ajaxSettings.flatOptions || {};
6878
6879         for ( key in src ) {
6880                 if ( src[ key ] !== undefined ) {
6881                         ( flatOptions[ key ] ? target : ( deep || (deep = {}) ) )[ key ] = src[ key ];
6882                 }
6883         }
6884         if ( deep ) {
6885                 jQuery.extend( true, target, deep );
6886         }
6887
6888         return target;
6889 }
6890
6891 jQuery.fn.load = function( url, params, callback ) {
6892         if ( typeof url !== "string" && _load ) {
6893                 return _load.apply( this, arguments );
6894         }
6895
6896         var selector, type, response,
6897                 self = this,
6898                 off = url.indexOf(" ");
6899
6900         if ( off >= 0 ) {
6901                 selector = url.slice( off );
6902                 url = url.slice( 0, off );
6903         }
6904
6905         // If it's a function
6906         if ( jQuery.isFunction( params ) ) {
6907
6908                 // We assume that it's the callback
6909                 callback = params;
6910                 params = undefined;
6911
6912         // Otherwise, build a param string
6913         } else if ( params && typeof params === "object" ) {
6914                 type = "POST";
6915         }
6916
6917         // If we have elements to modify, make the request
6918         if ( self.length > 0 ) {
6919                 jQuery.ajax({
6920                         url: url,
6921
6922                         // if "type" variable is undefined, then "GET" method will be used
6923                         type: type,
6924                         dataType: "html",
6925                         data: params
6926                 }).done(function( responseText ) {
6927
6928                         // Save response for use in complete callback
6929                         response = arguments;
6930
6931                         self.html( selector ?
6932
6933                                 // If a selector was specified, locate the right elements in a dummy div
6934                                 // Exclude scripts to avoid IE 'Permission Denied' errors
6935                                 jQuery("<div>").append( jQuery.parseHTML( responseText ) ).find( selector ) :
6936
6937                                 // Otherwise use the full result
6938                                 responseText );
6939
6940                 }).complete( callback && function( jqXHR, status ) {
6941                         self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );
6942                 });
6943         }
6944
6945         return this;
6946 };
6947
6948 // Attach a bunch of functions for handling common AJAX events
6949 jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ){
6950         jQuery.fn[ type ] = function( fn ){
6951                 return this.on( type, fn );
6952         };
6953 });
6954
6955 jQuery.extend({
6956
6957         // Counter for holding the number of active queries
6958         active: 0,
6959
6960         // Last-Modified header cache for next request
6961         lastModified: {},
6962         etag: {},
6963
6964         ajaxSettings: {
6965                 url: ajaxLocation,
6966                 type: "GET",
6967                 isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
6968                 global: true,
6969                 processData: true,
6970                 async: true,
6971                 contentType: "application/x-www-form-urlencoded; charset=UTF-8",
6972                 /*
6973                 timeout: 0,
6974                 data: null,
6975                 dataType: null,
6976                 username: null,
6977                 password: null,
6978                 cache: null,
6979                 throws: false,
6980                 traditional: false,
6981                 headers: {},
6982                 */
6983
6984                 accepts: {
6985                         "*": allTypes,
6986                         text: "text/plain",
6987                         html: "text/html",
6988                         xml: "application/xml, text/xml",
6989                         json: "application/json, text/javascript"
6990                 },
6991
6992                 contents: {
6993                         xml: /xml/,
6994                         html: /html/,
6995                         json: /json/
6996                 },
6997
6998                 responseFields: {
6999                         xml: "responseXML",
7000                         text: "responseText",
7001                         json: "responseJSON"
7002                 },
7003
7004                 // Data converters
7005                 // Keys separate source (or catchall "*") and destination types with a single space
7006                 converters: {
7007
7008                         // Convert anything to text
7009                         "* text": String,
7010
7011                         // Text to html (true = no transformation)
7012                         "text html": true,
7013
7014                         // Evaluate text as a json expression
7015                         "text json": jQuery.parseJSON,
7016
7017                         // Parse text as xml
7018                         "text xml": jQuery.parseXML
7019                 },
7020
7021                 // For options that shouldn't be deep extended:
7022                 // you can add your own custom options here if
7023                 // and when you create one that shouldn't be
7024                 // deep extended (see ajaxExtend)
7025                 flatOptions: {
7026                         url: true,
7027                         context: true
7028                 }
7029         },
7030
7031         // Creates a full fledged settings object into target
7032         // with both ajaxSettings and settings fields.
7033         // If target is omitted, writes into ajaxSettings.
7034         ajaxSetup: function( target, settings ) {
7035                 return settings ?
7036
7037                         // Building a settings object
7038                         ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :
7039
7040                         // Extending ajaxSettings
7041                         ajaxExtend( jQuery.ajaxSettings, target );
7042         },
7043
7044         ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
7045         ajaxTransport: addToPrefiltersOrTransports( transports ),
7046
7047         // Main method
7048         ajax: function( url, options ) {
7049
7050                 // If url is an object, simulate pre-1.5 signature
7051                 if ( typeof url === "object" ) {
7052                         options = url;
7053                         url = undefined;
7054                 }
7055
7056                 // Force options to be an object
7057                 options = options || {};
7058
7059                 var transport,
7060                         // URL without anti-cache param
7061                         cacheURL,
7062                         // Response headers
7063                         responseHeadersString,
7064                         responseHeaders,
7065                         // timeout handle
7066                         timeoutTimer,
7067                         // Cross-domain detection vars
7068                         parts,
7069                         // To know if global events are to be dispatched
7070                         fireGlobals,
7071                         // Loop variable
7072                         i,
7073                         // Create the final options object
7074                         s = jQuery.ajaxSetup( {}, options ),
7075                         // Callbacks context
7076                         callbackContext = s.context || s,
7077                         // Context for global events is callbackContext if it is a DOM node or jQuery collection
7078                         globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ?
7079                                 jQuery( callbackContext ) :
7080                                 jQuery.event,
7081                         // Deferreds
7082                         deferred = jQuery.Deferred(),
7083                         completeDeferred = jQuery.Callbacks("once memory"),
7084                         // Status-dependent callbacks
7085                         statusCode = s.statusCode || {},
7086                         // Headers (they are sent all at once)
7087                         requestHeaders = {},
7088                         requestHeadersNames = {},
7089                         // The jqXHR state
7090                         state = 0,
7091                         // Default abort message
7092                         strAbort = "canceled",
7093                         // Fake xhr
7094                         jqXHR = {
7095                                 readyState: 0,
7096
7097                                 // Builds headers hashtable if needed
7098                                 getResponseHeader: function( key ) {
7099                                         var match;
7100                                         if ( state === 2 ) {
7101                                                 if ( !responseHeaders ) {
7102                                                         responseHeaders = {};
7103                                                         while ( (match = rheaders.exec( responseHeadersString )) ) {
7104                                                                 responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
7105                                                         }
7106                                                 }
7107                                                 match = responseHeaders[ key.toLowerCase() ];
7108                                         }
7109                                         return match == null ? null : match;
7110                                 },
7111
7112                                 // Raw string
7113                                 getAllResponseHeaders: function() {
7114                                         return state === 2 ? responseHeadersString : null;
7115                                 },
7116
7117                                 // Caches the header
7118                                 setRequestHeader: function( name, value ) {
7119                                         var lname = name.toLowerCase();
7120                                         if ( !state ) {
7121                                                 name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
7122                                                 requestHeaders[ name ] = value;
7123                                         }
7124                                         return this;
7125                                 },
7126
7127                                 // Overrides response content-type header
7128                                 overrideMimeType: function( type ) {
7129                                         if ( !state ) {
7130                                                 s.mimeType = type;
7131                                         }
7132                                         return this;
7133                                 },
7134
7135                                 // Status-dependent callbacks
7136                                 statusCode: function( map ) {
7137                                         var code;
7138                                         if ( map ) {
7139                                                 if ( state < 2 ) {
7140                                                         for ( code in map ) {
7141                                                                 // Lazy-add the new callback in a way that preserves old ones
7142                                                                 statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
7143                                                         }
7144                                                 } else {
7145                                                         // Execute the appropriate callbacks
7146                                                         jqXHR.always( map[ jqXHR.status ] );
7147                                                 }
7148                                         }
7149                                         return this;
7150                                 },
7151
7152                                 // Cancel the request
7153                                 abort: function( statusText ) {
7154                                         var finalText = statusText || strAbort;
7155                                         if ( transport ) {
7156                                                 transport.abort( finalText );
7157                                         }
7158                                         done( 0, finalText );
7159                                         return this;
7160                                 }
7161                         };
7162
7163                 // Attach deferreds
7164                 deferred.promise( jqXHR ).complete = completeDeferred.add;
7165                 jqXHR.success = jqXHR.done;
7166                 jqXHR.error = jqXHR.fail;
7167
7168                 // Remove hash character (#7531: and string promotion)
7169                 // Add protocol if not provided (prefilters might expect it)
7170                 // Handle falsy url in the settings object (#10093: consistency with old signature)
7171                 // We also use the url parameter if available
7172                 s.url = ( ( url || s.url || ajaxLocation ) + "" ).replace( rhash, "" )
7173                         .replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
7174
7175                 // Alias method option to type as per ticket #12004
7176                 s.type = options.method || options.type || s.method || s.type;
7177
7178                 // Extract dataTypes list
7179                 s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( core_rnotwhite ) || [""];
7180
7181                 // A cross-domain request is in order when we have a protocol:host:port mismatch
7182                 if ( s.crossDomain == null ) {
7183                         parts = rurl.exec( s.url.toLowerCase() );
7184                         s.crossDomain = !!( parts &&
7185                                 ( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||
7186                                         ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? "80" : "443" ) ) !==
7187                                                 ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? "80" : "443" ) ) )
7188                         );
7189                 }
7190
7191                 // Convert data if not already a string
7192                 if ( s.data && s.processData && typeof s.data !== "string" ) {
7193                         s.data = jQuery.param( s.data, s.traditional );
7194                 }
7195
7196                 // Apply prefilters
7197                 inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
7198
7199                 // If request was aborted inside a prefilter, stop there
7200                 if ( state === 2 ) {
7201                         return jqXHR;
7202                 }
7203
7204                 // We can fire global events as of now if asked to
7205                 fireGlobals = s.global;
7206
7207                 // Watch for a new set of requests
7208                 if ( fireGlobals && jQuery.active++ === 0 ) {
7209                         jQuery.event.trigger("ajaxStart");
7210                 }
7211
7212                 // Uppercase the type
7213                 s.type = s.type.toUpperCase();
7214
7215                 // Determine if request has content
7216                 s.hasContent = !rnoContent.test( s.type );
7217
7218                 // Save the URL in case we're toying with the If-Modified-Since
7219                 // and/or If-None-Match header later on
7220                 cacheURL = s.url;
7221
7222                 // More options handling for requests with no content
7223                 if ( !s.hasContent ) {
7224
7225                         // If data is available, append data to url
7226                         if ( s.data ) {
7227                                 cacheURL = ( s.url += ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + s.data );
7228                                 // #9682: remove data so that it's not used in an eventual retry
7229                                 delete s.data;
7230                         }
7231
7232                         // Add anti-cache in url if needed
7233                         if ( s.cache === false ) {
7234                                 s.url = rts.test( cacheURL ) ?
7235
7236                                         // If there is already a '_' parameter, set its value
7237                                         cacheURL.replace( rts, "$1_=" + ajax_nonce++ ) :
7238
7239                                         // Otherwise add one to the end
7240                                         cacheURL + ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ajax_nonce++;
7241                         }
7242                 }
7243
7244                 // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
7245                 if ( s.ifModified ) {
7246                         if ( jQuery.lastModified[ cacheURL ] ) {
7247                                 jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
7248                         }
7249                         if ( jQuery.etag[ cacheURL ] ) {
7250                                 jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
7251                         }
7252                 }
7253
7254                 // Set the correct header, if data is being sent
7255                 if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
7256                         jqXHR.setRequestHeader( "Content-Type", s.contentType );
7257                 }
7258
7259                 // Set the Accepts header for the server, depending on the dataType
7260                 jqXHR.setRequestHeader(
7261                         "Accept",
7262                         s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
7263                                 s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
7264                                 s.accepts[ "*" ]
7265                 );
7266
7267                 // Check for headers option
7268                 for ( i in s.headers ) {
7269                         jqXHR.setRequestHeader( i, s.headers[ i ] );
7270                 }
7271
7272                 // Allow custom headers/mimetypes and early abort
7273                 if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
7274                         // Abort if not done already and return
7275                         return jqXHR.abort();
7276                 }
7277
7278                 // aborting is no longer a cancellation
7279                 strAbort = "abort";
7280
7281                 // Install callbacks on deferreds
7282                 for ( i in { success: 1, error: 1, complete: 1 } ) {
7283                         jqXHR[ i ]( s[ i ] );
7284                 }
7285
7286                 // Get transport
7287                 transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
7288
7289                 // If no transport, we auto-abort
7290                 if ( !transport ) {
7291                         done( -1, "No Transport" );
7292                 } else {
7293                         jqXHR.readyState = 1;
7294
7295                         // Send global event
7296                         if ( fireGlobals ) {
7297                                 globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
7298                         }
7299                         // Timeout
7300                         if ( s.async && s.timeout > 0 ) {
7301                                 timeoutTimer = setTimeout(function() {
7302                                         jqXHR.abort("timeout");
7303                                 }, s.timeout );
7304                         }
7305
7306                         try {
7307                                 state = 1;
7308                                 transport.send( requestHeaders, done );
7309                         } catch ( e ) {
7310                                 // Propagate exception as error if not done
7311                                 if ( state < 2 ) {
7312                                         done( -1, e );
7313                                 // Simply rethrow otherwise
7314                                 } else {
7315                                         throw e;
7316                                 }
7317                         }
7318                 }
7319
7320                 // Callback for when everything is done
7321                 function done( status, nativeStatusText, responses, headers ) {
7322                         var isSuccess, success, error, response, modified,
7323                                 statusText = nativeStatusText;
7324
7325                         // Called once
7326                         if ( state === 2 ) {
7327                                 return;
7328                         }
7329
7330                         // State is "done" now
7331                         state = 2;
7332
7333                         // Clear timeout if it exists
7334                         if ( timeoutTimer ) {
7335                                 clearTimeout( timeoutTimer );
7336                         }
7337
7338                         // Dereference transport for early garbage collection
7339                         // (no matter how long the jqXHR object will be used)
7340                         transport = undefined;
7341
7342                         // Cache response headers
7343                         responseHeadersString = headers || "";
7344
7345                         // Set readyState
7346                         jqXHR.readyState = status > 0 ? 4 : 0;
7347
7348                         // Determine if successful
7349                         isSuccess = status >= 200 && status < 300 || status === 304;
7350
7351                         // Get response data
7352                         if ( responses ) {
7353                                 response = ajaxHandleResponses( s, jqXHR, responses );
7354                         }
7355
7356                         // Convert no matter what (that way responseXXX fields are always set)
7357                         response = ajaxConvert( s, response, jqXHR, isSuccess );
7358
7359                         // If successful, handle type chaining
7360                         if ( isSuccess ) {
7361
7362                                 // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
7363                                 if ( s.ifModified ) {
7364                                         modified = jqXHR.getResponseHeader("Last-Modified");
7365                                         if ( modified ) {
7366                                                 jQuery.lastModified[ cacheURL ] = modified;
7367                                         }
7368                                         modified = jqXHR.getResponseHeader("etag");
7369                                         if ( modified ) {
7370                                                 jQuery.etag[ cacheURL ] = modified;
7371                                         }
7372                                 }
7373
7374                                 // if no content
7375                                 if ( status === 204 || s.type === "HEAD" ) {
7376                                         statusText = "nocontent";
7377
7378                                 // if not modified
7379                                 } else if ( status === 304 ) {
7380                                         statusText = "notmodified";
7381
7382                                 // If we have data, let's convert it
7383                                 } else {
7384                                         statusText = response.state;
7385                                         success = response.data;
7386                                         error = response.error;
7387                                         isSuccess = !error;
7388                                 }
7389                         } else {
7390                                 // We extract error from statusText
7391                                 // then normalize statusText and status for non-aborts
7392                                 error = statusText;
7393                                 if ( status || !statusText ) {
7394                                         statusText = "error";
7395                                         if ( status < 0 ) {
7396                                                 status = 0;
7397                                         }
7398                                 }
7399                         }
7400
7401                         // Set data for the fake xhr object
7402                         jqXHR.status = status;
7403                         jqXHR.statusText = ( nativeStatusText || statusText ) + "";
7404
7405                         // Success/Error
7406                         if ( isSuccess ) {
7407                                 deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
7408                         } else {
7409                                 deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
7410                         }
7411
7412                         // Status-dependent callbacks
7413                         jqXHR.statusCode( statusCode );
7414                         statusCode = undefined;
7415
7416                         if ( fireGlobals ) {
7417                                 globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
7418                                         [ jqXHR, s, isSuccess ? success : error ] );
7419                         }
7420
7421                         // Complete
7422                         completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
7423
7424                         if ( fireGlobals ) {
7425                                 globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
7426                                 // Handle the global AJAX counter
7427                                 if ( !( --jQuery.active ) ) {
7428                                         jQuery.event.trigger("ajaxStop");
7429                                 }
7430                         }
7431                 }
7432
7433                 return jqXHR;
7434         },
7435
7436         getJSON: function( url, data, callback ) {
7437                 return jQuery.get( url, data, callback, "json" );
7438         },
7439
7440         getScript: function( url, callback ) {
7441                 return jQuery.get( url, undefined, callback, "script" );
7442         }
7443 });
7444
7445 jQuery.each( [ "get", "post" ], function( i, method ) {
7446         jQuery[ method ] = function( url, data, callback, type ) {
7447                 // shift arguments if data argument was omitted
7448                 if ( jQuery.isFunction( data ) ) {
7449                         type = type || callback;
7450                         callback = data;
7451                         data = undefined;
7452                 }
7453
7454                 return jQuery.ajax({
7455                         url: url,
7456                         type: method,
7457                         dataType: type,
7458                         data: data,
7459                         success: callback
7460                 });
7461         };
7462 });
7463
7464 /* Handles responses to an ajax request:
7465  * - finds the right dataType (mediates between content-type and expected dataType)
7466  * - returns the corresponding response
7467  */
7468 function ajaxHandleResponses( s, jqXHR, responses ) {
7469
7470         var ct, type, finalDataType, firstDataType,
7471                 contents = s.contents,
7472                 dataTypes = s.dataTypes;
7473
7474         // Remove auto dataType and get content-type in the process
7475         while( dataTypes[ 0 ] === "*" ) {
7476                 dataTypes.shift();
7477                 if ( ct === undefined ) {
7478                         ct = s.mimeType || jqXHR.getResponseHeader("Content-Type");
7479                 }
7480         }
7481
7482         // Check if we're dealing with a known content-type
7483         if ( ct ) {
7484                 for ( type in contents ) {
7485                         if ( contents[ type ] && contents[ type ].test( ct ) ) {
7486                                 dataTypes.unshift( type );
7487                                 break;
7488                         }
7489                 }
7490         }
7491
7492         // Check to see if we have a response for the expected dataType
7493         if ( dataTypes[ 0 ] in responses ) {
7494                 finalDataType = dataTypes[ 0 ];
7495         } else {
7496                 // Try convertible dataTypes
7497                 for ( type in responses ) {
7498                         if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
7499                                 finalDataType = type;
7500                                 break;
7501                         }
7502                         if ( !firstDataType ) {
7503                                 firstDataType = type;
7504                         }
7505                 }
7506                 // Or just use first one
7507                 finalDataType = finalDataType || firstDataType;
7508         }
7509
7510         // If we found a dataType
7511         // We add the dataType to the list if needed
7512         // and return the corresponding response
7513         if ( finalDataType ) {
7514                 if ( finalDataType !== dataTypes[ 0 ] ) {
7515                         dataTypes.unshift( finalDataType );
7516                 }
7517                 return responses[ finalDataType ];
7518         }
7519 }
7520
7521 /* Chain conversions given the request and the original response
7522  * Also sets the responseXXX fields on the jqXHR instance
7523  */
7524 function ajaxConvert( s, response, jqXHR, isSuccess ) {
7525         var conv2, current, conv, tmp, prev,
7526                 converters = {},
7527                 // Work with a copy of dataTypes in case we need to modify it for conversion
7528                 dataTypes = s.dataTypes.slice();
7529
7530         // Create converters map with lowercased keys
7531         if ( dataTypes[ 1 ] ) {
7532                 for ( conv in s.converters ) {
7533                         converters[ conv.toLowerCase() ] = s.converters[ conv ];
7534                 }
7535         }
7536
7537         current = dataTypes.shift();
7538
7539         // Convert to each sequential dataType
7540         while ( current ) {
7541
7542                 if ( s.responseFields[ current ] ) {
7543                         jqXHR[ s.responseFields[ current ] ] = response;
7544                 }
7545
7546                 // Apply the dataFilter if provided
7547                 if ( !prev && isSuccess && s.dataFilter ) {
7548                         response = s.dataFilter( response, s.dataType );
7549                 }
7550
7551                 prev = current;
7552                 current = dataTypes.shift();
7553
7554                 if ( current ) {
7555
7556                 // There's only work to do if current dataType is non-auto
7557                         if ( current === "*" ) {
7558
7559                                 current = prev;
7560
7561                         // Convert response if prev dataType is non-auto and differs from current
7562                         } else if ( prev !== "*" && prev !== current ) {
7563
7564                                 // Seek a direct converter
7565                                 conv = converters[ prev + " " + current ] || converters[ "* " + current ];
7566
7567                                 // If none found, seek a pair
7568                                 if ( !conv ) {
7569                                         for ( conv2 in converters ) {
7570
7571                                                 // If conv2 outputs current
7572                                                 tmp = conv2.split( " " );
7573                                                 if ( tmp[ 1 ] === current ) {
7574
7575                                                         // If prev can be converted to accepted input
7576                                                         conv = converters[ prev + " " + tmp[ 0 ] ] ||
7577                                                                 converters[ "* " + tmp[ 0 ] ];
7578                                                         if ( conv ) {
7579                                                                 // Condense equivalence converters
7580                                                                 if ( conv === true ) {
7581                                                                         conv = converters[ conv2 ];
7582
7583                                                                 // Otherwise, insert the intermediate dataType
7584                                                                 } else if ( converters[ conv2 ] !== true ) {
7585                                                                         current = tmp[ 0 ];
7586                                                                         dataTypes.unshift( tmp[ 1 ] );
7587                                                                 }
7588                                                                 break;
7589                                                         }
7590                                                 }
7591                                         }
7592                                 }
7593
7594                                 // Apply converter (if not an equivalence)
7595                                 if ( conv !== true ) {
7596
7597                                         // Unless errors are allowed to bubble, catch and return them
7598                                         if ( conv && s[ "throws" ] ) {
7599                                                 response = conv( response );
7600                                         } else {
7601                                                 try {
7602                                                         response = conv( response );
7603                                                 } catch ( e ) {
7604                                                         return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current };
7605                                                 }
7606                                         }
7607                                 }
7608                         }
7609                 }
7610         }
7611
7612         return { state: "success", data: response };
7613 }
7614 // Install script dataType
7615 jQuery.ajaxSetup({
7616         accepts: {
7617                 script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
7618         },
7619         contents: {
7620                 script: /(?:java|ecma)script/
7621         },
7622         converters: {
7623                 "text script": function( text ) {
7624                         jQuery.globalEval( text );
7625                         return text;
7626                 }
7627         }
7628 });
7629
7630 // Handle cache's special case and crossDomain
7631 jQuery.ajaxPrefilter( "script", function( s ) {
7632         if ( s.cache === undefined ) {
7633                 s.cache = false;
7634         }
7635         if ( s.crossDomain ) {
7636                 s.type = "GET";
7637         }
7638 });
7639
7640 // Bind script tag hack transport
7641 jQuery.ajaxTransport( "script", function( s ) {
7642         // This transport only deals with cross domain requests
7643         if ( s.crossDomain ) {
7644                 var script, callback;
7645                 return {
7646                         send: function( _, complete ) {
7647                                 script = jQuery("<script>").prop({
7648                                         async: true,
7649                                         charset: s.scriptCharset,
7650                                         src: s.url
7651                                 }).on(
7652                                         "load error",
7653                                         callback = function( evt ) {
7654                                                 script.remove();
7655                                                 callback = null;
7656                                                 if ( evt ) {
7657                                                         complete( evt.type === "error" ? 404 : 200, evt.type );
7658                                                 }
7659                                         }
7660                                 );
7661                                 document.head.appendChild( script[ 0 ] );
7662                         },
7663                         abort: function() {
7664                                 if ( callback ) {
7665                                         callback();
7666                                 }
7667                         }
7668                 };
7669         }
7670 });
7671 var oldCallbacks = [],
7672         rjsonp = /(=)\?(?=&|$)|\?\?/;
7673
7674 // Default jsonp settings
7675 jQuery.ajaxSetup({
7676         jsonp: "callback",
7677         jsonpCallback: function() {
7678                 var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( ajax_nonce++ ) );
7679                 this[ callback ] = true;
7680                 return callback;
7681         }
7682 });
7683
7684 // Detect, normalize options and install callbacks for jsonp requests
7685 jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
7686
7687         var callbackName, overwritten, responseContainer,
7688                 jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
7689                         "url" :
7690                         typeof s.data === "string" && !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && rjsonp.test( s.data ) && "data"
7691                 );
7692
7693         // Handle iff the expected data type is "jsonp" or we have a parameter to set
7694         if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {
7695
7696                 // Get callback name, remembering preexisting value associated with it
7697                 callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?
7698                         s.jsonpCallback() :
7699                         s.jsonpCallback;
7700
7701                 // Insert callback into url or form data
7702                 if ( jsonProp ) {
7703                         s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
7704                 } else if ( s.jsonp !== false ) {
7705                         s.url += ( ajax_rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
7706                 }
7707
7708                 // Use data converter to retrieve json after script execution
7709                 s.converters["script json"] = function() {
7710                         if ( !responseContainer ) {
7711                                 jQuery.error( callbackName + " was not called" );
7712                         }
7713                         return responseContainer[ 0 ];
7714                 };
7715
7716                 // force json dataType
7717                 s.dataTypes[ 0 ] = "json";
7718
7719                 // Install callback
7720                 overwritten = window[ callbackName ];
7721                 window[ callbackName ] = function() {
7722                         responseContainer = arguments;
7723                 };
7724
7725                 // Clean-up function (fires after converters)
7726                 jqXHR.always(function() {
7727                         // Restore preexisting value
7728                         window[ callbackName ] = overwritten;
7729
7730                         // Save back as free
7731                         if ( s[ callbackName ] ) {
7732                                 // make sure that re-using the options doesn't screw things around
7733                                 s.jsonpCallback = originalSettings.jsonpCallback;
7734
7735                                 // save the callback name for future use
7736                                 oldCallbacks.push( callbackName );
7737                         }
7738
7739                         // Call if it was a function and we have a response
7740                         if ( responseContainer && jQuery.isFunction( overwritten ) ) {
7741                                 overwritten( responseContainer[ 0 ] );
7742                         }
7743
7744                         responseContainer = overwritten = undefined;
7745                 });
7746
7747                 // Delegate to script
7748                 return "script";
7749         }
7750 });
7751 jQuery.ajaxSettings.xhr = function() {
7752         try {
7753                 return new XMLHttpRequest();
7754         } catch( e ) {}
7755 };
7756
7757 var xhrSupported = jQuery.ajaxSettings.xhr(),
7758         xhrSuccessStatus = {
7759                 // file protocol always yields status code 0, assume 200
7760                 0: 200,
7761                 // Support: IE9
7762                 // #1450: sometimes IE returns 1223 when it should be 204
7763                 1223: 204
7764         },
7765         // Support: IE9
7766         // We need to keep track of outbound xhr and abort them manually
7767         // because IE is not smart enough to do it all by itself
7768         xhrId = 0,
7769         xhrCallbacks = {};
7770
7771 if ( window.ActiveXObject ) {
7772         jQuery( window ).on( "unload", function() {
7773                 for( var key in xhrCallbacks ) {
7774                         xhrCallbacks[ key ]();
7775                 }
7776                 xhrCallbacks = undefined;
7777         });
7778 }
7779
7780 jQuery.support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
7781 jQuery.support.ajax = xhrSupported = !!xhrSupported;
7782
7783 jQuery.ajaxTransport(function( options ) {
7784         var callback;
7785         // Cross domain only allowed if supported through XMLHttpRequest
7786         if ( jQuery.support.cors || xhrSupported && !options.crossDomain ) {
7787                 return {
7788                         send: function( headers, complete ) {
7789                                 var i, id,
7790                                         xhr = options.xhr();
7791                                 xhr.open( options.type, options.url, options.async, options.username, options.password );
7792                                 // Apply custom fields if provided
7793                                 if ( options.xhrFields ) {
7794                                         for ( i in options.xhrFields ) {
7795                                                 xhr[ i ] = options.xhrFields[ i ];
7796                                         }
7797                                 }
7798                                 // Override mime type if needed
7799                                 if ( options.mimeType && xhr.overrideMimeType ) {
7800                                         xhr.overrideMimeType( options.mimeType );
7801                                 }
7802                                 // X-Requested-With header
7803                                 // For cross-domain requests, seeing as conditions for a preflight are
7804                                 // akin to a jigsaw puzzle, we simply never set it to be sure.
7805                                 // (it can always be set on a per-request basis or even using ajaxSetup)
7806                                 // For same-domain requests, won't change header if already provided.
7807                                 if ( !options.crossDomain && !headers["X-Requested-With"] ) {
7808                                         headers["X-Requested-With"] = "XMLHttpRequest";
7809                                 }
7810                                 // Set headers
7811                                 for ( i in headers ) {
7812                                         xhr.setRequestHeader( i, headers[ i ] );
7813                                 }
7814                                 // Callback
7815                                 callback = function( type ) {
7816                                         return function() {
7817                                                 if ( callback ) {
7818                                                         delete xhrCallbacks[ id ];
7819                                                         callback = xhr.onload = xhr.onerror = null;
7820                                                         if ( type === "abort" ) {
7821                                                                 xhr.abort();
7822                                                         } else if ( type === "error" ) {
7823                                                                 complete(
7824                                                                         // file protocol always yields status 0, assume 404
7825                                                                         xhr.status || 404,
7826                                                                         xhr.statusText
7827                                                                 );
7828                                                         } else {
7829                                                                 complete(
7830                                                                         xhrSuccessStatus[ xhr.status ] || xhr.status,
7831                                                                         xhr.statusText,
7832                                                                         // Support: IE9
7833                                                                         // #11426: When requesting binary data, IE9 will throw an exception
7834                                                                         // on any attempt to access responseText
7835                                                                         typeof xhr.responseText === "string" ? {
7836                                                                                 text: xhr.responseText
7837                                                                         } : undefined,
7838                                                                         xhr.getAllResponseHeaders()
7839                                                                 );
7840                                                         }
7841                                                 }
7842                                         };
7843                                 };
7844                                 // Listen to events
7845                                 xhr.onload = callback();
7846                                 xhr.onerror = callback("error");
7847                                 // Create the abort callback
7848                                 callback = xhrCallbacks[( id = xhrId++ )] = callback("abort");
7849                                 // Do send the request
7850                                 // This may raise an exception which is actually
7851                                 // handled in jQuery.ajax (so no try/catch here)
7852                                 xhr.send( options.hasContent && options.data || null );
7853                         },
7854                         abort: function() {
7855                                 if ( callback ) {
7856                                         callback();
7857                                 }
7858                         }
7859                 };
7860         }
7861 });
7862 var fxNow, timerId,
7863         rfxtypes = /^(?:toggle|show|hide)$/,
7864         rfxnum = new RegExp( "^(?:([+-])=|)(" + core_pnum + ")([a-z%]*)$", "i" ),
7865         rrun = /queueHooks$/,
7866         animationPrefilters = [ defaultPrefilter ],
7867         tweeners = {
7868                 "*": [function( prop, value ) {
7869                         var tween = this.createTween( prop, value ),
7870                                 target = tween.cur(),
7871                                 parts = rfxnum.exec( value ),
7872                                 unit = parts && parts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
7873
7874                                 // Starting value computation is required for potential unit mismatches
7875                                 start = ( jQuery.cssNumber[ prop ] || unit !== "px" && +target ) &&
7876                                         rfxnum.exec( jQuery.css( tween.elem, prop ) ),
7877                                 scale = 1,
7878                                 maxIterations = 20;
7879
7880                         if ( start && start[ 3 ] !== unit ) {
7881                                 // Trust units reported by jQuery.css
7882                                 unit = unit || start[ 3 ];
7883
7884                                 // Make sure we update the tween properties later on
7885                                 parts = parts || [];
7886
7887                                 // Iteratively approximate from a nonzero starting point
7888                                 start = +target || 1;
7889
7890                                 do {
7891                                         // If previous iteration zeroed out, double until we get *something*
7892                                         // Use a string for doubling factor so we don't accidentally see scale as unchanged below
7893                                         scale = scale || ".5";
7894
7895                                         // Adjust and apply
7896                                         start = start / scale;
7897                                         jQuery.style( tween.elem, prop, start + unit );
7898
7899                                 // Update scale, tolerating zero or NaN from tween.cur()
7900                                 // And breaking the loop if scale is unchanged or perfect, or if we've just had enough
7901                                 } while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );
7902                         }
7903
7904                         // Update tween properties
7905                         if ( parts ) {
7906                                 start = tween.start = +start || +target || 0;
7907                                 tween.unit = unit;
7908                                 // If a +=/-= token was provided, we're doing a relative animation
7909                                 tween.end = parts[ 1 ] ?
7910                                         start + ( parts[ 1 ] + 1 ) * parts[ 2 ] :
7911                                         +parts[ 2 ];
7912                         }
7913
7914                         return tween;
7915                 }]
7916         };
7917
7918 // Animations created synchronously will run synchronously
7919 function createFxNow() {
7920         setTimeout(function() {
7921                 fxNow = undefined;
7922         });
7923         return ( fxNow = jQuery.now() );
7924 }
7925
7926 function createTween( value, prop, animation ) {
7927         var tween,
7928                 collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ),
7929                 index = 0,
7930                 length = collection.length;
7931         for ( ; index < length; index++ ) {
7932                 if ( (tween = collection[ index ].call( animation, prop, value )) ) {
7933
7934                         // we're done with this property
7935                         return tween;
7936                 }
7937         }
7938 }
7939
7940 function Animation( elem, properties, options ) {
7941         var result,
7942                 stopped,
7943                 index = 0,
7944                 length = animationPrefilters.length,
7945                 deferred = jQuery.Deferred().always( function() {
7946                         // don't match elem in the :animated selector
7947                         delete tick.elem;
7948                 }),
7949                 tick = function() {
7950                         if ( stopped ) {
7951                                 return false;
7952                         }
7953                         var currentTime = fxNow || createFxNow(),
7954                                 remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
7955                                 // archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497)
7956                                 temp = remaining / animation.duration || 0,
7957                                 percent = 1 - temp,
7958                                 index = 0,
7959                                 length = animation.tweens.length;
7960
7961                         for ( ; index < length ; index++ ) {
7962                                 animation.tweens[ index ].run( percent );
7963                         }
7964
7965                         deferred.notifyWith( elem, [ animation, percent, remaining ]);
7966
7967                         if ( percent < 1 && length ) {
7968                                 return remaining;
7969                         } else {
7970                                 deferred.resolveWith( elem, [ animation ] );
7971                                 return false;
7972                         }
7973                 },
7974                 animation = deferred.promise({
7975                         elem: elem,
7976                         props: jQuery.extend( {}, properties ),
7977                         opts: jQuery.extend( true, { specialEasing: {} }, options ),
7978                         originalProperties: properties,
7979                         originalOptions: options,
7980                         startTime: fxNow || createFxNow(),
7981                         duration: options.duration,
7982                         tweens: [],
7983                         createTween: function( prop, end ) {
7984                                 var tween = jQuery.Tween( elem, animation.opts, prop, end,
7985                                                 animation.opts.specialEasing[ prop ] || animation.opts.easing );
7986                                 animation.tweens.push( tween );
7987                                 return tween;
7988                         },
7989                         stop: function( gotoEnd ) {
7990                                 var index = 0,
7991                                         // if we are going to the end, we want to run all the tweens
7992                                         // otherwise we skip this part
7993                                         length = gotoEnd ? animation.tweens.length : 0;
7994                                 if ( stopped ) {
7995                                         return this;
7996                                 }
7997                                 stopped = true;
7998                                 for ( ; index < length ; index++ ) {
7999                                         animation.tweens[ index ].run( 1 );
8000                                 }
8001
8002                                 // resolve when we played the last frame
8003                                 // otherwise, reject
8004                                 if ( gotoEnd ) {
8005                                         deferred.resolveWith( elem, [ animation, gotoEnd ] );
8006                                 } else {
8007                                         deferred.rejectWith( elem, [ animation, gotoEnd ] );
8008                                 }
8009                                 return this;
8010                         }
8011                 }),
8012                 props = animation.props;
8013
8014         propFilter( props, animation.opts.specialEasing );
8015
8016         for ( ; index < length ; index++ ) {
8017                 result = animationPrefilters[ index ].call( animation, elem, props, animation.opts );
8018                 if ( result ) {
8019                         return result;
8020                 }
8021         }
8022
8023         jQuery.map( props, createTween, animation );
8024
8025         if ( jQuery.isFunction( animation.opts.start ) ) {
8026                 animation.opts.start.call( elem, animation );
8027         }
8028
8029         jQuery.fx.timer(
8030                 jQuery.extend( tick, {
8031                         elem: elem,
8032                         anim: animation,
8033                         queue: animation.opts.queue
8034                 })
8035         );
8036
8037         // attach callbacks from options
8038         return animation.progress( animation.opts.progress )
8039                 .done( animation.opts.done, animation.opts.complete )
8040                 .fail( animation.opts.fail )
8041                 .always( animation.opts.always );
8042 }
8043
8044 function propFilter( props, specialEasing ) {
8045         var index, name, easing, value, hooks;
8046
8047         // camelCase, specialEasing and expand cssHook pass
8048         for ( index in props ) {
8049                 name = jQuery.camelCase( index );
8050                 easing = specialEasing[ name ];
8051                 value = props[ index ];
8052                 if ( jQuery.isArray( value ) ) {
8053                         easing = value[ 1 ];
8054                         value = props[ index ] = value[ 0 ];
8055                 }
8056
8057                 if ( index !== name ) {
8058                         props[ name ] = value;
8059                         delete props[ index ];
8060                 }
8061
8062                 hooks = jQuery.cssHooks[ name ];
8063                 if ( hooks && "expand" in hooks ) {
8064                         value = hooks.expand( value );
8065                         delete props[ name ];
8066
8067                         // not quite $.extend, this wont overwrite keys already present.
8068                         // also - reusing 'index' from above because we have the correct "name"
8069                         for ( index in value ) {
8070                                 if ( !( index in props ) ) {
8071                                         props[ index ] = value[ index ];
8072                                         specialEasing[ index ] = easing;
8073                                 }
8074                         }
8075                 } else {
8076                         specialEasing[ name ] = easing;
8077                 }
8078         }
8079 }
8080
8081 jQuery.Animation = jQuery.extend( Animation, {
8082
8083         tweener: function( props, callback ) {
8084                 if ( jQuery.isFunction( props ) ) {
8085                         callback = props;
8086                         props = [ "*" ];
8087                 } else {
8088                         props = props.split(" ");
8089                 }
8090
8091                 var prop,
8092                         index = 0,
8093                         length = props.length;
8094
8095                 for ( ; index < length ; index++ ) {
8096                         prop = props[ index ];
8097                         tweeners[ prop ] = tweeners[ prop ] || [];
8098                         tweeners[ prop ].unshift( callback );
8099                 }
8100         },
8101
8102         prefilter: function( callback, prepend ) {
8103                 if ( prepend ) {
8104                         animationPrefilters.unshift( callback );
8105                 } else {
8106                         animationPrefilters.push( callback );
8107                 }
8108         }
8109 });
8110
8111 function defaultPrefilter( elem, props, opts ) {
8112         /* jshint validthis: true */
8113         var prop, value, toggle, tween, hooks, oldfire,
8114                 anim = this,
8115                 orig = {},
8116                 style = elem.style,
8117                 hidden = elem.nodeType && isHidden( elem ),
8118                 dataShow = data_priv.get( elem, "fxshow" );
8119
8120         // handle queue: false promises
8121         if ( !opts.queue ) {
8122                 hooks = jQuery._queueHooks( elem, "fx" );
8123                 if ( hooks.unqueued == null ) {
8124                         hooks.unqueued = 0;
8125                         oldfire = hooks.empty.fire;
8126                         hooks.empty.fire = function() {
8127                                 if ( !hooks.unqueued ) {
8128                                         oldfire();
8129                                 }
8130                         };
8131                 }
8132                 hooks.unqueued++;
8133
8134                 anim.always(function() {
8135                         // doing this makes sure that the complete handler will be called
8136                         // before this completes
8137                         anim.always(function() {
8138                                 hooks.unqueued--;
8139                                 if ( !jQuery.queue( elem, "fx" ).length ) {
8140                                         hooks.empty.fire();
8141                                 }
8142                         });
8143                 });
8144         }
8145
8146         // height/width overflow pass
8147         if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {
8148                 // Make sure that nothing sneaks out
8149                 // Record all 3 overflow attributes because IE9-10 do not
8150                 // change the overflow attribute when overflowX and
8151                 // overflowY are set to the same value
8152                 opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
8153
8154                 // Set display property to inline-block for height/width
8155                 // animations on inline elements that are having width/height animated
8156                 if ( jQuery.css( elem, "display" ) === "inline" &&
8157                                 jQuery.css( elem, "float" ) === "none" ) {
8158
8159                         style.display = "inline-block";
8160                 }
8161         }
8162
8163         if ( opts.overflow ) {
8164                 style.overflow = "hidden";
8165                 anim.always(function() {
8166                         style.overflow = opts.overflow[ 0 ];
8167                         style.overflowX = opts.overflow[ 1 ];
8168                         style.overflowY = opts.overflow[ 2 ];
8169                 });
8170         }
8171
8172
8173         // show/hide pass
8174         for ( prop in props ) {
8175                 value = props[ prop ];
8176                 if ( rfxtypes.exec( value ) ) {
8177                         delete props[ prop ];
8178                         toggle = toggle || value === "toggle";
8179                         if ( value === ( hidden ? "hide" : "show" ) ) {
8180
8181                                 // If there is dataShow left over from a stopped hide or show and we are going to proceed with show, we should pretend to be hidden
8182                                 if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) {
8183                                         hidden = true;
8184                                 } else {
8185                                         continue;
8186                                 }
8187                         }
8188                         orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
8189                 }
8190         }
8191
8192         if ( !jQuery.isEmptyObject( orig ) ) {
8193                 if ( dataShow ) {
8194                         if ( "hidden" in dataShow ) {
8195                                 hidden = dataShow.hidden;
8196                         }
8197                 } else {
8198                         dataShow = data_priv.access( elem, "fxshow", {} );
8199                 }
8200
8201                 // store state if its toggle - enables .stop().toggle() to "reverse"
8202                 if ( toggle ) {
8203                         dataShow.hidden = !hidden;
8204                 }
8205                 if ( hidden ) {
8206                         jQuery( elem ).show();
8207                 } else {
8208                         anim.done(function() {
8209                                 jQuery( elem ).hide();
8210                         });
8211                 }
8212                 anim.done(function() {
8213                         var prop;
8214
8215                         data_priv.remove( elem, "fxshow" );
8216                         for ( prop in orig ) {
8217                                 jQuery.style( elem, prop, orig[ prop ] );
8218                         }
8219                 });
8220                 for ( prop in orig ) {
8221                         tween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
8222
8223                         if ( !( prop in dataShow ) ) {
8224                                 dataShow[ prop ] = tween.start;
8225                                 if ( hidden ) {
8226                                         tween.end = tween.start;
8227                                         tween.start = prop === "width" || prop === "height" ? 1 : 0;
8228                                 }
8229                         }
8230                 }
8231         }
8232 }
8233
8234 function Tween( elem, options, prop, end, easing ) {
8235         return new Tween.prototype.init( elem, options, prop, end, easing );
8236 }
8237 jQuery.Tween = Tween;
8238
8239 Tween.prototype = {
8240         constructor: Tween,
8241         init: function( elem, options, prop, end, easing, unit ) {
8242                 this.elem = elem;
8243                 this.prop = prop;
8244                 this.easing = easing || "swing";
8245                 this.options = options;
8246                 this.start = this.now = this.cur();
8247                 this.end = end;
8248                 this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
8249         },
8250         cur: function() {
8251                 var hooks = Tween.propHooks[ this.prop ];
8252
8253                 return hooks && hooks.get ?
8254                         hooks.get( this ) :
8255                         Tween.propHooks._default.get( this );
8256         },
8257         run: function( percent ) {
8258                 var eased,
8259                         hooks = Tween.propHooks[ this.prop ];
8260
8261                 if ( this.options.duration ) {
8262                         this.pos = eased = jQuery.easing[ this.easing ](
8263                                 percent, this.options.duration * percent, 0, 1, this.options.duration
8264                         );
8265                 } else {
8266                         this.pos = eased = percent;
8267                 }
8268                 this.now = ( this.end - this.start ) * eased + this.start;
8269
8270                 if ( this.options.step ) {
8271                         this.options.step.call( this.elem, this.now, this );
8272                 }
8273
8274                 if ( hooks && hooks.set ) {
8275                         hooks.set( this );
8276                 } else {
8277                         Tween.propHooks._default.set( this );
8278                 }
8279                 return this;
8280         }
8281 };
8282
8283 Tween.prototype.init.prototype = Tween.prototype;
8284
8285 Tween.propHooks = {
8286         _default: {
8287                 get: function( tween ) {
8288                         var result;
8289
8290                         if ( tween.elem[ tween.prop ] != null &&
8291                                 (!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) {
8292                                 return tween.elem[ tween.prop ];
8293                         }
8294
8295                         // passing an empty string as a 3rd parameter to .css will automatically
8296                         // attempt a parseFloat and fallback to a string if the parse fails
8297                         // so, simple values such as "10px" are parsed to Float.
8298                         // complex values such as "rotate(1rad)" are returned as is.
8299                         result = jQuery.css( tween.elem, tween.prop, "" );
8300                         // Empty strings, null, undefined and "auto" are converted to 0.
8301                         return !result || result === "auto" ? 0 : result;
8302                 },
8303                 set: function( tween ) {
8304                         // use step hook for back compat - use cssHook if its there - use .style if its
8305                         // available and use plain properties where available
8306                         if ( jQuery.fx.step[ tween.prop ] ) {
8307                                 jQuery.fx.step[ tween.prop ]( tween );
8308                         } else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {
8309                                 jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
8310                         } else {
8311                                 tween.elem[ tween.prop ] = tween.now;
8312                         }
8313                 }
8314         }
8315 };
8316
8317 // Support: IE9
8318 // Panic based approach to setting things on disconnected nodes
8319
8320 Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
8321         set: function( tween ) {
8322                 if ( tween.elem.nodeType && tween.elem.parentNode ) {
8323                         tween.elem[ tween.prop ] = tween.now;
8324                 }
8325         }
8326 };
8327
8328 jQuery.each([ "toggle", "show", "hide" ], function( i, name ) {
8329         var cssFn = jQuery.fn[ name ];
8330         jQuery.fn[ name ] = function( speed, easing, callback ) {
8331                 return speed == null || typeof speed === "boolean" ?
8332                         cssFn.apply( this, arguments ) :
8333                         this.animate( genFx( name, true ), speed, easing, callback );
8334         };
8335 });
8336
8337 jQuery.fn.extend({
8338         fadeTo: function( speed, to, easing, callback ) {
8339
8340                 // show any hidden elements after setting opacity to 0
8341                 return this.filter( isHidden ).css( "opacity", 0 ).show()
8342
8343                         // animate to the value specified
8344                         .end().animate({ opacity: to }, speed, easing, callback );
8345         },
8346         animate: function( prop, speed, easing, callback ) {
8347                 var empty = jQuery.isEmptyObject( prop ),
8348                         optall = jQuery.speed( speed, easing, callback ),
8349                         doAnimation = function() {
8350                                 // Operate on a copy of prop so per-property easing won't be lost
8351                                 var anim = Animation( this, jQuery.extend( {}, prop ), optall );
8352
8353                                 // Empty animations, or finishing resolves immediately
8354                                 if ( empty || data_priv.get( this, "finish" ) ) {
8355                                         anim.stop( true );
8356                                 }
8357                         };
8358                         doAnimation.finish = doAnimation;
8359
8360                 return empty || optall.queue === false ?
8361                         this.each( doAnimation ) :
8362                         this.queue( optall.queue, doAnimation );
8363         },
8364         stop: function( type, clearQueue, gotoEnd ) {
8365                 var stopQueue = function( hooks ) {
8366                         var stop = hooks.stop;
8367                         delete hooks.stop;
8368                         stop( gotoEnd );
8369                 };
8370
8371                 if ( typeof type !== "string" ) {
8372                         gotoEnd = clearQueue;
8373                         clearQueue = type;
8374                         type = undefined;
8375                 }
8376                 if ( clearQueue && type !== false ) {
8377                         this.queue( type || "fx", [] );
8378                 }
8379
8380                 return this.each(function() {
8381                         var dequeue = true,
8382                                 index = type != null && type + "queueHooks",
8383                                 timers = jQuery.timers,
8384                                 data = data_priv.get( this );
8385
8386                         if ( index ) {
8387                                 if ( data[ index ] && data[ index ].stop ) {
8388                                         stopQueue( data[ index ] );
8389                                 }
8390                         } else {
8391                                 for ( index in data ) {
8392                                         if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
8393                                                 stopQueue( data[ index ] );
8394                                         }
8395                                 }
8396                         }
8397
8398                         for ( index = timers.length; index--; ) {
8399                                 if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
8400                                         timers[ index ].anim.stop( gotoEnd );
8401                                         dequeue = false;
8402                                         timers.splice( index, 1 );
8403                                 }
8404                         }
8405
8406                         // start the next in the queue if the last step wasn't forced
8407                         // timers currently will call their complete callbacks, which will dequeue
8408                         // but only if they were gotoEnd
8409                         if ( dequeue || !gotoEnd ) {
8410                                 jQuery.dequeue( this, type );
8411                         }
8412                 });
8413         },
8414         finish: function( type ) {
8415                 if ( type !== false ) {
8416                         type = type || "fx";
8417                 }
8418                 return this.each(function() {
8419                         var index,
8420                                 data = data_priv.get( this ),
8421                                 queue = data[ type + "queue" ],
8422                                 hooks = data[ type + "queueHooks" ],
8423                                 timers = jQuery.timers,
8424                                 length = queue ? queue.length : 0;
8425
8426                         // enable finishing flag on private data
8427                         data.finish = true;
8428
8429                         // empty the queue first
8430                         jQuery.queue( this, type, [] );
8431
8432                         if ( hooks && hooks.stop ) {
8433                                 hooks.stop.call( this, true );
8434                         }
8435
8436                         // look for any active animations, and finish them
8437                         for ( index = timers.length; index--; ) {
8438                                 if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
8439                                         timers[ index ].anim.stop( true );
8440                                         timers.splice( index, 1 );
8441                                 }
8442                         }
8443
8444                         // look for any animations in the old queue and finish them
8445                         for ( index = 0; index < length; index++ ) {
8446                                 if ( queue[ index ] && queue[ index ].finish ) {
8447                                         queue[ index ].finish.call( this );
8448                                 }
8449                         }
8450
8451                         // turn off finishing flag
8452                         delete data.finish;
8453                 });
8454         }
8455 });
8456
8457 // Generate parameters to create a standard animation
8458 function genFx( type, includeWidth ) {
8459         var which,
8460                 attrs = { height: type },
8461                 i = 0;
8462
8463         // if we include width, step value is 1 to do all cssExpand values,
8464         // if we don't include width, step value is 2 to skip over Left and Right
8465         includeWidth = includeWidth? 1 : 0;
8466         for( ; i < 4 ; i += 2 - includeWidth ) {
8467                 which = cssExpand[ i ];
8468                 attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
8469         }
8470
8471         if ( includeWidth ) {
8472                 attrs.opacity = attrs.width = type;
8473         }
8474
8475         return attrs;
8476 }
8477
8478 // Generate shortcuts for custom animations
8479 jQuery.each({
8480         slideDown: genFx("show"),
8481         slideUp: genFx("hide"),
8482         slideToggle: genFx("toggle"),
8483         fadeIn: { opacity: "show" },
8484         fadeOut: { opacity: "hide" },
8485         fadeToggle: { opacity: "toggle" }
8486 }, function( name, props ) {
8487         jQuery.fn[ name ] = function( speed, easing, callback ) {
8488                 return this.animate( props, speed, easing, callback );
8489         };
8490 });
8491
8492 jQuery.speed = function( speed, easing, fn ) {
8493         var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
8494                 complete: fn || !fn && easing ||
8495                         jQuery.isFunction( speed ) && speed,
8496                 duration: speed,
8497                 easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
8498         };
8499
8500         opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
8501                 opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
8502
8503         // normalize opt.queue - true/undefined/null -> "fx"
8504         if ( opt.queue == null || opt.queue === true ) {
8505                 opt.queue = "fx";
8506         }
8507
8508         // Queueing
8509         opt.old = opt.complete;
8510
8511         opt.complete = function() {
8512                 if ( jQuery.isFunction( opt.old ) ) {
8513                         opt.old.call( this );
8514                 }
8515
8516                 if ( opt.queue ) {
8517                         jQuery.dequeue( this, opt.queue );
8518                 }
8519         };
8520
8521         return opt;
8522 };
8523
8524 jQuery.easing = {
8525         linear: function( p ) {
8526                 return p;
8527         },
8528         swing: function( p ) {
8529                 return 0.5 - Math.cos( p*Math.PI ) / 2;
8530         }
8531 };
8532
8533 jQuery.timers = [];
8534 jQuery.fx = Tween.prototype.init;
8535 jQuery.fx.tick = function() {
8536         var timer,
8537                 timers = jQuery.timers,
8538                 i = 0;
8539
8540         fxNow = jQuery.now();
8541
8542         for ( ; i < timers.length; i++ ) {
8543                 timer = timers[ i ];
8544                 // Checks the timer has not already been removed
8545                 if ( !timer() && timers[ i ] === timer ) {
8546                         timers.splice( i--, 1 );
8547                 }
8548         }
8549
8550         if ( !timers.length ) {
8551                 jQuery.fx.stop();
8552         }
8553         fxNow = undefined;
8554 };
8555
8556 jQuery.fx.timer = function( timer ) {
8557         if ( timer() && jQuery.timers.push( timer ) ) {
8558                 jQuery.fx.start();
8559         }
8560 };
8561
8562 jQuery.fx.interval = 13;
8563
8564 jQuery.fx.start = function() {
8565         if ( !timerId ) {
8566                 timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );
8567         }
8568 };
8569
8570 jQuery.fx.stop = function() {
8571         clearInterval( timerId );
8572         timerId = null;
8573 };
8574
8575 jQuery.fx.speeds = {
8576         slow: 600,
8577         fast: 200,
8578         // Default speed
8579         _default: 400
8580 };
8581
8582 // Back Compat <1.8 extension point
8583 jQuery.fx.step = {};
8584
8585 if ( jQuery.expr && jQuery.expr.filters ) {
8586         jQuery.expr.filters.animated = function( elem ) {
8587                 return jQuery.grep(jQuery.timers, function( fn ) {
8588                         return elem === fn.elem;
8589                 }).length;
8590         };
8591 }
8592 jQuery.fn.offset = function( options ) {
8593         if ( arguments.length ) {
8594                 return options === undefined ?
8595                         this :
8596                         this.each(function( i ) {
8597                                 jQuery.offset.setOffset( this, options, i );
8598                         });
8599         }
8600
8601         var docElem, win,
8602                 elem = this[ 0 ],
8603                 box = { top: 0, left: 0 },
8604                 doc = elem && elem.ownerDocument;
8605
8606         if ( !doc ) {
8607                 return;
8608         }
8609
8610         docElem = doc.documentElement;
8611
8612         // Make sure it's not a disconnected DOM node
8613         if ( !jQuery.contains( docElem, elem ) ) {
8614                 return box;
8615         }
8616
8617         // If we don't have gBCR, just use 0,0 rather than error
8618         // BlackBerry 5, iOS 3 (original iPhone)
8619         if ( typeof elem.getBoundingClientRect !== core_strundefined ) {
8620                 box = elem.getBoundingClientRect();
8621         }
8622         win = getWindow( doc );
8623         return {
8624                 top: box.top + win.pageYOffset - docElem.clientTop,
8625                 left: box.left + win.pageXOffset - docElem.clientLeft
8626         };
8627 };
8628
8629 jQuery.offset = {
8630
8631         setOffset: function( elem, options, i ) {
8632                 var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,
8633                         position = jQuery.css( elem, "position" ),
8634                         curElem = jQuery( elem ),
8635                         props = {};
8636
8637                 // Set position first, in-case top/left are set even on static elem
8638                 if ( position === "static" ) {
8639                         elem.style.position = "relative";
8640                 }
8641
8642                 curOffset = curElem.offset();
8643                 curCSSTop = jQuery.css( elem, "top" );
8644                 curCSSLeft = jQuery.css( elem, "left" );
8645                 calculatePosition = ( position === "absolute" || position === "fixed" ) && ( curCSSTop + curCSSLeft ).indexOf("auto") > -1;
8646
8647                 // Need to be able to calculate position if either top or left is auto and position is either absolute or fixed
8648                 if ( calculatePosition ) {
8649                         curPosition = curElem.position();
8650                         curTop = curPosition.top;
8651                         curLeft = curPosition.left;
8652
8653                 } else {
8654                         curTop = parseFloat( curCSSTop ) || 0;
8655                         curLeft = parseFloat( curCSSLeft ) || 0;
8656                 }
8657
8658                 if ( jQuery.isFunction( options ) ) {
8659                         options = options.call( elem, i, curOffset );
8660                 }
8661
8662                 if ( options.top != null ) {
8663                         props.top = ( options.top - curOffset.top ) + curTop;
8664                 }
8665                 if ( options.left != null ) {
8666                         props.left = ( options.left - curOffset.left ) + curLeft;
8667                 }
8668
8669                 if ( "using" in options ) {
8670                         options.using.call( elem, props );
8671
8672                 } else {
8673                         curElem.css( props );
8674                 }
8675         }
8676 };
8677
8678
8679 jQuery.fn.extend({
8680
8681         position: function() {
8682                 if ( !this[ 0 ] ) {
8683                         return;
8684                 }
8685
8686                 var offsetParent, offset,
8687                         elem = this[ 0 ],
8688                         parentOffset = { top: 0, left: 0 };
8689
8690                 // Fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is it's only offset parent
8691                 if ( jQuery.css( elem, "position" ) === "fixed" ) {
8692                         // We assume that getBoundingClientRect is available when computed position is fixed
8693                         offset = elem.getBoundingClientRect();
8694
8695                 } else {
8696                         // Get *real* offsetParent
8697                         offsetParent = this.offsetParent();
8698
8699                         // Get correct offsets
8700                         offset = this.offset();
8701                         if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) {
8702                                 parentOffset = offsetParent.offset();
8703                         }
8704
8705                         // Add offsetParent borders
8706                         parentOffset.top += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true );
8707                         parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true );
8708                 }
8709
8710                 // Subtract parent offsets and element margins
8711                 return {
8712                         top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ),
8713                         left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true )
8714                 };
8715         },
8716
8717         offsetParent: function() {
8718                 return this.map(function() {
8719                         var offsetParent = this.offsetParent || docElem;
8720
8721                         while ( offsetParent && ( !jQuery.nodeName( offsetParent, "html" ) && jQuery.css( offsetParent, "position") === "static" ) ) {
8722                                 offsetParent = offsetParent.offsetParent;
8723                         }
8724
8725                         return offsetParent || docElem;
8726                 });
8727         }
8728 });
8729
8730
8731 // Create scrollLeft and scrollTop methods
8732 jQuery.each( {scrollLeft: "pageXOffset", scrollTop: "pageYOffset"}, function( method, prop ) {
8733         var top = "pageYOffset" === prop;
8734
8735         jQuery.fn[ method ] = function( val ) {
8736                 return jQuery.access( this, function( elem, method, val ) {
8737                         var win = getWindow( elem );
8738
8739                         if ( val === undefined ) {
8740                                 return win ? win[ prop ] : elem[ method ];
8741                         }
8742
8743                         if ( win ) {
8744                                 win.scrollTo(
8745                                         !top ? val : window.pageXOffset,
8746                                         top ? val : window.pageYOffset
8747                                 );
8748
8749                         } else {
8750                                 elem[ method ] = val;
8751                         }
8752                 }, method, val, arguments.length, null );
8753         };
8754 });
8755
8756 function getWindow( elem ) {
8757         return jQuery.isWindow( elem ) ? elem : elem.nodeType === 9 && elem.defaultView;
8758 }
8759 // Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
8760 jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
8761         jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) {
8762                 // margin is only for outerHeight, outerWidth
8763                 jQuery.fn[ funcName ] = function( margin, value ) {
8764                         var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
8765                                 extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
8766
8767                         return jQuery.access( this, function( elem, type, value ) {
8768                                 var doc;
8769
8770                                 if ( jQuery.isWindow( elem ) ) {
8771                                         // As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there
8772                                         // isn't a whole lot we can do. See pull request at this URL for discussion:
8773                                         // https://github.com/jquery/jquery/pull/764
8774                                         return elem.document.documentElement[ "client" + name ];
8775                                 }
8776
8777                                 // Get document width or height
8778                                 if ( elem.nodeType === 9 ) {
8779                                         doc = elem.documentElement;
8780
8781                                         // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height],
8782                                         // whichever is greatest
8783                                         return Math.max(
8784                                                 elem.body[ "scroll" + name ], doc[ "scroll" + name ],
8785                                                 elem.body[ "offset" + name ], doc[ "offset" + name ],
8786                                                 doc[ "client" + name ]
8787                                         );
8788                                 }
8789
8790                                 return value === undefined ?
8791                                         // Get width or height on the element, requesting but not forcing parseFloat
8792                                         jQuery.css( elem, type, extra ) :
8793
8794                                         // Set width or height on the element
8795                                         jQuery.style( elem, type, value, extra );
8796                         }, type, chainable ? margin : undefined, chainable, null );
8797                 };
8798         });
8799 });
8800 // Limit scope pollution from any deprecated API
8801 // (function() {
8802
8803 // The number of elements contained in the matched element set
8804 jQuery.fn.size = function() {
8805         return this.length;
8806 };
8807
8808 jQuery.fn.andSelf = jQuery.fn.addBack;
8809
8810 // })();
8811 if ( typeof module === "object" && module && typeof module.exports === "object" ) {
8812         // Expose jQuery as module.exports in loaders that implement the Node
8813         // module pattern (including browserify). Do not create the global, since
8814         // the user will be storing it themselves locally, and globals are frowned
8815         // upon in the Node module world.
8816         module.exports = jQuery;
8817 } else {
8818         // Register as a named AMD module, since jQuery can be concatenated with other
8819         // files that may use define, but not via a proper concatenation script that
8820         // understands anonymous AMD modules. A named AMD is safest and most robust
8821         // way to register. Lowercase jquery is used because AMD module names are
8822         // derived from file names, and jQuery is normally delivered in a lowercase
8823         // file name. Do this after creating the global so that if an AMD module wants
8824         // to call noConflict to hide this version of jQuery, it will work.
8825         if ( typeof define === "function" && define.amd ) {
8826                 define( "jquery", [], function () { return jQuery; } );
8827         }
8828 }
8829
8830 // If there is a window object, that at least has a document property,
8831 // define jQuery and $ identifiers
8832 if ( typeof window === "object" && typeof window.document === "object" ) {
8833         window.jQuery = window.$ = jQuery;
8834 }
8835
8836 })( window );
8837
8838 /**
8839  * @license
8840  * Lo-Dash 2.2.1 (Custom Build) <http://lodash.com/>
8841  * Build: `lodash modern -o ./dist/lodash.js`
8842  * Copyright 2012-2013 The Dojo Foundation <http://dojofoundation.org/>
8843  * Based on Underscore.js 1.5.2 <http://underscorejs.org/LICENSE>
8844  * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
8845  * Available under MIT license <http://lodash.com/license>
8846  */
8847 ;(function() {
8848
8849   /** Used as a safe reference for `undefined` in pre ES5 environments */
8850   var undefined;
8851
8852   /** Used to pool arrays and objects used internally */
8853   var arrayPool = [],
8854       objectPool = [];
8855
8856   /** Used to generate unique IDs */
8857   var idCounter = 0;
8858
8859   /** Used to prefix keys to avoid issues with `__proto__` and properties on `Object.prototype` */
8860   var keyPrefix = +new Date + '';
8861
8862   /** Used as the size when optimizations are enabled for large arrays */
8863   var largeArraySize = 75;
8864
8865   /** Used as the max size of the `arrayPool` and `objectPool` */
8866   var maxPoolSize = 40;
8867
8868   /** Used to detect and test whitespace */
8869   var whitespace = (
8870     // whitespace
8871     ' \t\x0B\f\xA0\ufeff' +
8872
8873     // line terminators
8874     '\n\r\u2028\u2029' +
8875
8876     // unicode category "Zs" space separators
8877     '\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000'
8878   );
8879
8880   /** Used to match empty string literals in compiled template source */
8881   var reEmptyStringLeading = /\b__p \+= '';/g,
8882       reEmptyStringMiddle = /\b(__p \+=) '' \+/g,
8883       reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g;
8884
8885   /**
8886    * Used to match ES6 template delimiters
8887    * http://people.mozilla.org/~jorendorff/es6-draft.html#sec-7.8.6
8888    */
8889   var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g;
8890
8891   /** Used to match regexp flags from their coerced string values */
8892   var reFlags = /\w*$/;
8893
8894   /** Used to detected named functions */
8895   var reFuncName = /^function[ \n\r\t]+\w/;
8896
8897   /** Used to match "interpolate" template delimiters */
8898   var reInterpolate = /<%=([\s\S]+?)%>/g;
8899
8900   /** Used to match leading whitespace and zeros to be removed */
8901   var reLeadingSpacesAndZeros = RegExp('^[' + whitespace + ']*0+(?=.$)');
8902
8903   /** Used to ensure capturing order of template delimiters */
8904   var reNoMatch = /($^)/;
8905
8906   /** Used to detect functions containing a `this` reference */
8907   var reThis = /\bthis\b/;
8908
8909   /** Used to match unescaped characters in compiled string literals */
8910   var reUnescapedString = /['\n\r\t\u2028\u2029\\]/g;
8911
8912   /** Used to assign default `context` object properties */
8913   var contextProps = [
8914     'Array', 'Boolean', 'Date', 'Function', 'Math', 'Number', 'Object',
8915     'RegExp', 'String', '_', 'attachEvent', 'clearTimeout', 'isFinite', 'isNaN',
8916     'parseInt', 'setImmediate', 'setTimeout'
8917   ];
8918
8919   /** Used to make template sourceURLs easier to identify */
8920   var templateCounter = 0;
8921
8922   /** `Object#toString` result shortcuts */
8923   var argsClass = '[object Arguments]',
8924       arrayClass = '[object Array]',
8925       boolClass = '[object Boolean]',
8926       dateClass = '[object Date]',
8927       funcClass = '[object Function]',
8928       numberClass = '[object Number]',
8929       objectClass = '[object Object]',
8930       regexpClass = '[object RegExp]',
8931       stringClass = '[object String]';
8932
8933   /** Used to identify object classifications that `_.clone` supports */
8934   var cloneableClasses = {};
8935   cloneableClasses[funcClass] = false;
8936   cloneableClasses[argsClass] = cloneableClasses[arrayClass] =
8937   cloneableClasses[boolClass] = cloneableClasses[dateClass] =
8938   cloneableClasses[numberClass] = cloneableClasses[objectClass] =
8939   cloneableClasses[regexpClass] = cloneableClasses[stringClass] = true;
8940
8941   /** Used as an internal `_.debounce` options object */
8942   var debounceOptions = {
8943     'leading': false,
8944     'maxWait': 0,
8945     'trailing': false
8946   };
8947
8948   /** Used as the property descriptor for `__bindData__` */
8949   var descriptor = {
8950     'configurable': false,
8951     'enumerable': false,
8952     'value': null,
8953     'writable': false
8954   };
8955
8956   /** Used to determine if values are of the language type Object */
8957   var objectTypes = {
8958     'boolean': false,
8959     'function': true,
8960     'object': true,
8961     'number': false,
8962     'string': false,
8963     'undefined': false
8964   };
8965
8966   /** Used to escape characters for inclusion in compiled string literals */
8967   var stringEscapes = {
8968     '\\': '\\',
8969     "'": "'",
8970     '\n': 'n',
8971     '\r': 'r',
8972     '\t': 't',
8973     '\u2028': 'u2028',
8974     '\u2029': 'u2029'
8975   };
8976
8977   /** Used as a reference to the global object */
8978   var root = (objectTypes[typeof window] && window) || this;
8979
8980   /** Detect free variable `exports` */
8981   var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports;
8982
8983   /** Detect free variable `module` */
8984   var freeModule = objectTypes[typeof module] && module && !module.nodeType && module;
8985
8986   /** Detect the popular CommonJS extension `module.exports` */
8987   var moduleExports = freeModule && freeModule.exports === freeExports && freeExports;
8988
8989   /** Detect free variable `global` from Node.js or Browserified code and use it as `root` */
8990   var freeGlobal = objectTypes[typeof global] && global;
8991   if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal)) {
8992     root = freeGlobal;
8993   }
8994
8995   /*--------------------------------------------------------------------------*/
8996
8997   /**
8998    * The base implementation of `_.indexOf` without support for binary searches
8999    * or `fromIndex` constraints.
9000    *
9001    * @private
9002    * @param {Array} array The array to search.
9003    * @param {*} value The value to search for.
9004    * @param {number} [fromIndex=0] The index to search from.
9005    * @returns {number} Returns the index of the matched value or `-1`.
9006    */
9007   function baseIndexOf(array, value, fromIndex) {
9008     var index = (fromIndex || 0) - 1,
9009         length = array ? array.length : 0;
9010
9011     while (++index < length) {
9012       if (array[index] === value) {
9013         return index;
9014       }
9015     }
9016     return -1;
9017   }
9018
9019   /**
9020    * An implementation of `_.contains` for cache objects that mimics the return
9021    * signature of `_.indexOf` by returning `0` if the value is found, else `-1`.
9022    *
9023    * @private
9024    * @param {Object} cache The cache object to inspect.
9025    * @param {*} value The value to search for.
9026    * @returns {number} Returns `0` if `value` is found, else `-1`.
9027    */
9028   function cacheIndexOf(cache, value) {
9029     var type = typeof value;
9030     cache = cache.cache;
9031
9032     if (type == 'boolean' || value == null) {
9033       return cache[value] ? 0 : -1;
9034     }
9035     if (type != 'number' && type != 'string') {
9036       type = 'object';
9037     }
9038     var key = type == 'number' ? value : keyPrefix + value;
9039     cache = (cache = cache[type]) && cache[key];
9040
9041     return type == 'object'
9042       ? (cache && baseIndexOf(cache, value) > -1 ? 0 : -1)
9043       : (cache ? 0 : -1);
9044   }
9045
9046   /**
9047    * Adds a given value to the corresponding cache object.
9048    *
9049    * @private
9050    * @param {*} value The value to add to the cache.
9051    */
9052   function cachePush(value) {
9053     var cache = this.cache,
9054         type = typeof value;
9055
9056     if (type == 'boolean' || value == null) {
9057       cache[value] = true;
9058     } else {
9059       if (type != 'number' && type != 'string') {
9060         type = 'object';
9061       }
9062       var key = type == 'number' ? value : keyPrefix + value,
9063           typeCache = cache[type] || (cache[type] = {});
9064
9065       if (type == 'object') {
9066         (typeCache[key] || (typeCache[key] = [])).push(value);
9067       } else {
9068         typeCache[key] = true;
9069       }
9070     }
9071   }
9072
9073   /**
9074    * Used by `_.max` and `_.min` as the default callback when a given
9075    * collection is a string value.
9076    *
9077    * @private
9078    * @param {string} value The character to inspect.
9079    * @returns {number} Returns the code unit of given character.
9080    */
9081   function charAtCallback(value) {
9082     return value.charCodeAt(0);
9083   }
9084
9085   /**
9086    * Used by `sortBy` to compare transformed `collection` elements, stable sorting
9087    * them in ascending order.
9088    *
9089    * @private
9090    * @param {Object} a The object to compare to `b`.
9091    * @param {Object} b The object to compare to `a`.
9092    * @returns {number} Returns the sort order indicator of `1` or `-1`.
9093    */
9094   function compareAscending(a, b) {
9095     var ac = a.criteria,
9096         bc = b.criteria;
9097
9098     // ensure a stable sort in V8 and other engines
9099     // http://code.google.com/p/v8/issues/detail?id=90
9100     if (ac !== bc) {
9101       if (ac > bc || typeof ac == 'undefined') {
9102         return 1;
9103       }
9104       if (ac < bc || typeof bc == 'undefined') {
9105         return -1;
9106       }
9107     }
9108     // The JS engine embedded in Adobe applications like InDesign has a buggy
9109     // `Array#sort` implementation that causes it, under certain circumstances,
9110     // to return the same value for `a` and `b`.
9111     // See https://github.com/jashkenas/underscore/pull/1247
9112     return a.index - b.index;
9113   }
9114
9115   /**
9116    * Creates a cache object to optimize linear searches of large arrays.
9117    *
9118    * @private
9119    * @param {Array} [array=[]] The array to search.
9120    * @returns {null|Object} Returns the cache object or `null` if caching should not be used.
9121    */
9122   function createCache(array) {
9123     var index = -1,
9124         length = array.length,
9125         first = array[0],
9126         mid = array[(length / 2) | 0],
9127         last = array[length - 1];
9128
9129     if (first && typeof first == 'object' &&
9130         mid && typeof mid == 'object' && last && typeof last == 'object') {
9131       return false;
9132     }
9133     var cache = getObject();
9134     cache['false'] = cache['null'] = cache['true'] = cache['undefined'] = false;
9135
9136     var result = getObject();
9137     result.array = array;
9138     result.cache = cache;
9139     result.push = cachePush;
9140
9141     while (++index < length) {
9142       result.push(array[index]);
9143     }
9144     return result;
9145   }
9146
9147   /**
9148    * Used by `template` to escape characters for inclusion in compiled
9149    * string literals.
9150    *
9151    * @private
9152    * @param {string} match The matched character to escape.
9153    * @returns {string} Returns the escaped character.
9154    */
9155   function escapeStringChar(match) {
9156     return '\\' + stringEscapes[match];
9157   }
9158
9159   /**
9160    * Gets an array from the array pool or creates a new one if the pool is empty.
9161    *
9162    * @private
9163    * @returns {Array} The array from the pool.
9164    */
9165   function getArray() {
9166     return arrayPool.pop() || [];
9167   }
9168
9169   /**
9170    * Gets an object from the object pool or creates a new one if the pool is empty.
9171    *
9172    * @private
9173    * @returns {Object} The object from the pool.
9174    */
9175   function getObject() {
9176     return objectPool.pop() || {
9177       'array': null,
9178       'cache': null,
9179       'criteria': null,
9180       'false': false,
9181       'index': 0,
9182       'null': false,
9183       'number': null,
9184       'object': null,
9185       'push': null,
9186       'string': null,
9187       'true': false,
9188       'undefined': false,
9189       'value': null
9190     };
9191   }
9192
9193   /**
9194    * A no-operation function.
9195    *
9196    * @private
9197    */
9198   function noop() {
9199     // no operation performed
9200   }
9201
9202   /**
9203    * Releases the given array back to the array pool.
9204    *
9205    * @private
9206    * @param {Array} [array] The array to release.
9207    */
9208   function releaseArray(array) {
9209     array.length = 0;
9210     if (arrayPool.length < maxPoolSize) {
9211       arrayPool.push(array);
9212     }
9213   }
9214
9215   /**
9216    * Releases the given object back to the object pool.
9217    *
9218    * @private
9219    * @param {Object} [object] The object to release.
9220    */
9221   function releaseObject(object) {
9222     var cache = object.cache;
9223     if (cache) {
9224       releaseObject(cache);
9225     }
9226     object.array = object.cache = object.criteria = object.object = object.number = object.string = object.value = null;
9227     if (objectPool.length < maxPoolSize) {
9228       objectPool.push(object);
9229     }
9230   }
9231
9232   /**
9233    * Slices the `collection` from the `start` index up to, but not including,
9234    * the `end` index.
9235    *
9236    * Note: This function is used instead of `Array#slice` to support node lists
9237    * in IE < 9 and to ensure dense arrays are returned.
9238    *
9239    * @private
9240    * @param {Array|Object|string} collection The collection to slice.
9241    * @param {number} start The start index.
9242    * @param {number} end The end index.
9243    * @returns {Array} Returns the new array.
9244    */
9245   function slice(array, start, end) {
9246     start || (start = 0);
9247     if (typeof end == 'undefined') {
9248       end = array ? array.length : 0;
9249     }
9250     var index = -1,
9251         length = end - start || 0,
9252         result = Array(length < 0 ? 0 : length);
9253
9254     while (++index < length) {
9255       result[index] = array[start + index];
9256     }
9257     return result;
9258   }
9259
9260   /*--------------------------------------------------------------------------*/
9261
9262   /**
9263    * Create a new `lodash` function using the given context object.
9264    *
9265    * @static
9266    * @memberOf _
9267    * @category Utilities
9268    * @param {Object} [context=root] The context object.
9269    * @returns {Function} Returns the `lodash` function.
9270    */
9271   function runInContext(context) {
9272     // Avoid issues with some ES3 environments that attempt to use values, named
9273     // after built-in constructors like `Object`, for the creation of literals.
9274     // ES5 clears this up by stating that literals must use built-in constructors.
9275     // See http://es5.github.io/#x11.1.5.
9276     context = context ? _.defaults(root.Object(), context, _.pick(root, contextProps)) : root;
9277
9278     /** Native constructor references */
9279     var Array = context.Array,
9280         Boolean = context.Boolean,
9281         Date = context.Date,
9282         Function = context.Function,
9283         Math = context.Math,
9284         Number = context.Number,
9285         Object = context.Object,
9286         RegExp = context.RegExp,
9287         String = context.String,
9288         TypeError = context.TypeError;
9289
9290     /**
9291      * Used for `Array` method references.
9292      *
9293      * Normally `Array.prototype` would suffice, however, using an array literal
9294      * avoids issues in Narwhal.
9295      */
9296     var arrayRef = [];
9297
9298     /** Used for native method references */
9299     var objectProto = Object.prototype;
9300
9301     /** Used to restore the original `_` reference in `noConflict` */
9302     var oldDash = context._;
9303
9304     /** Used to detect if a method is native */
9305     var reNative = RegExp('^' +
9306       String(objectProto.valueOf)
9307         .replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
9308         .replace(/valueOf|for [^\]]+/g, '.+?') + '$'
9309     );
9310
9311     /** Native method shortcuts */
9312     var ceil = Math.ceil,
9313         clearTimeout = context.clearTimeout,
9314         floor = Math.floor,
9315         fnToString = Function.prototype.toString,
9316         getPrototypeOf = reNative.test(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf,
9317         hasOwnProperty = objectProto.hasOwnProperty,
9318         now = reNative.test(now = Date.now) && now || function() { return +new Date; },
9319         push = arrayRef.push,
9320         setImmediate = context.setImmediate,
9321         setTimeout = context.setTimeout,
9322         splice = arrayRef.splice,
9323         toString = objectProto.toString,
9324         unshift = arrayRef.unshift;
9325
9326     var defineProperty = (function() {
9327       try {
9328         var o = {},
9329             func = reNative.test(func = Object.defineProperty) && func,
9330             result = func(o, o, o) && func;
9331       } catch(e) { }
9332       return result;
9333     }());
9334
9335     /* Native method shortcuts for methods with the same name as other `lodash` methods */
9336     var nativeBind = reNative.test(nativeBind = toString.bind) && nativeBind,
9337         nativeCreate = reNative.test(nativeCreate = Object.create) && nativeCreate,
9338         nativeIsArray = reNative.test(nativeIsArray = Array.isArray) && nativeIsArray,
9339         nativeIsFinite = context.isFinite,
9340         nativeIsNaN = context.isNaN,
9341         nativeKeys = reNative.test(nativeKeys = Object.keys) && nativeKeys,
9342         nativeMax = Math.max,
9343         nativeMin = Math.min,
9344         nativeParseInt = context.parseInt,
9345         nativeRandom = Math.random,
9346         nativeSlice = arrayRef.slice;
9347
9348     /** Detect various environments */
9349     var isIeOpera = reNative.test(context.attachEvent),
9350         isV8 = nativeBind && !/\n|true/.test(nativeBind + isIeOpera);
9351
9352     /** Used to lookup a built-in constructor by [[Class]] */
9353     var ctorByClass = {};
9354     ctorByClass[arrayClass] = Array;
9355     ctorByClass[boolClass] = Boolean;
9356     ctorByClass[dateClass] = Date;
9357     ctorByClass[funcClass] = Function;
9358     ctorByClass[objectClass] = Object;
9359     ctorByClass[numberClass] = Number;
9360     ctorByClass[regexpClass] = RegExp;
9361     ctorByClass[stringClass] = String;
9362
9363     /*--------------------------------------------------------------------------*/
9364
9365     /**
9366      * Creates a `lodash` object which wraps the given value to enable intuitive
9367      * method chaining.
9368      *
9369      * In addition to Lo-Dash methods, wrappers also have the following `Array` methods:
9370      * `concat`, `join`, `pop`, `push`, `reverse`, `shift`, `slice`, `sort`, `splice`,
9371      * and `unshift`
9372      *
9373      * Chaining is supported in custom builds as long as the `value` method is
9374      * implicitly or explicitly included in the build.
9375      *
9376      * The chainable wrapper functions are:
9377      * `after`, `assign`, `bind`, `bindAll`, `bindKey`, `chain`, `compact`,
9378      * `compose`, `concat`, `countBy`, `createCallback`, `curry`, `debounce`,
9379      * `defaults`, `defer`, `delay`, `difference`, `filter`, `flatten`, `forEach`,
9380      * `forEachRight`, `forIn`, `forInRight`, `forOwn`, `forOwnRight`, `functions`,
9381      * `groupBy`, `indexBy`, `initial`, `intersection`, `invert`, `invoke`, `keys`,
9382      * `map`, `max`, `memoize`, `merge`, `min`, `object`, `omit`, `once`, `pairs`,
9383      * `partial`, `partialRight`, `pick`, `pluck`, `pull`, `push`, `range`, `reject`,
9384      * `remove`, `rest`, `reverse`, `shuffle`, `slice`, `sort`, `sortBy`, `splice`,
9385      * `tap`, `throttle`, `times`, `toArray`, `transform`, `union`, `uniq`, `unshift`,
9386      * `unzip`, `values`, `where`, `without`, `wrap`, and `zip`
9387      *
9388      * The non-chainable wrapper functions are:
9389      * `clone`, `cloneDeep`, `contains`, `escape`, `every`, `find`, `findIndex`,
9390      * `findKey`, `findLast`, `findLastIndex`, `findLastKey`, `has`, `identity`,
9391      * `indexOf`, `isArguments`, `isArray`, `isBoolean`, `isDate`, `isElement`,
9392      * `isEmpty`, `isEqual`, `isFinite`, `isFunction`, `isNaN`, `isNull`, `isNumber`,
9393      * `isObject`, `isPlainObject`, `isRegExp`, `isString`, `isUndefined`, `join`,
9394      * `lastIndexOf`, `mixin`, `noConflict`, `parseInt`, `pop`, `random`, `reduce`,
9395      * `reduceRight`, `result`, `shift`, `size`, `some`, `sortedIndex`, `runInContext`,
9396      * `template`, `unescape`, `uniqueId`, and `value`
9397      *
9398      * The wrapper functions `first` and `last` return wrapped values when `n` is
9399      * provided, otherwise they return unwrapped values.
9400      *
9401      * Explicit chaining can be enabled by using the `_.chain` method.
9402      *
9403      * @name _
9404      * @constructor
9405      * @category Chaining
9406      * @param {*} value The value to wrap in a `lodash` instance.
9407      * @returns {Object} Returns a `lodash` instance.
9408      * @example
9409      *
9410      * var wrapped = _([1, 2, 3]);
9411      *
9412      * // returns an unwrapped value
9413      * wrapped.reduce(function(sum, num) {
9414      *   return sum + num;
9415      * });
9416      * // => 6
9417      *
9418      * // returns a wrapped value
9419      * var squares = wrapped.map(function(num) {
9420      *   return num * num;
9421      * });
9422      *
9423      * _.isArray(squares);
9424      * // => false
9425      *
9426      * _.isArray(squares.value());
9427      * // => true
9428      */
9429     function lodash(value) {
9430       // don't wrap if already wrapped, even if wrapped by a different `lodash` constructor
9431       return (value && typeof value == 'object' && !isArray(value) && hasOwnProperty.call(value, '__wrapped__'))
9432        ? value
9433        : new lodashWrapper(value);
9434     }
9435
9436     /**
9437      * A fast path for creating `lodash` wrapper objects.
9438      *
9439      * @private
9440      * @param {*} value The value to wrap in a `lodash` instance.
9441      * @param {boolean} chainAll A flag to enable chaining for all methods
9442      * @returns {Object} Returns a `lodash` instance.
9443      */
9444     function lodashWrapper(value, chainAll) {
9445       this.__chain__ = !!chainAll;
9446       this.__wrapped__ = value;
9447     }
9448     // ensure `new lodashWrapper` is an instance of `lodash`
9449     lodashWrapper.prototype = lodash.prototype;
9450
9451     /**
9452      * An object used to flag environments features.
9453      *
9454      * @static
9455      * @memberOf _
9456      * @type Object
9457      */
9458     var support = lodash.support = {};
9459
9460     /**
9461      * Detect if `Function#bind` exists and is inferred to be fast (all but V8).
9462      *
9463      * @memberOf _.support
9464      * @type boolean
9465      */
9466     support.fastBind = nativeBind && !isV8;
9467
9468     /**
9469      * Detect if functions can be decompiled by `Function#toString`
9470      * (all but PS3 and older Opera mobile browsers & avoided in Windows 8 apps).
9471      *
9472      * @memberOf _.support
9473      * @type boolean
9474      */
9475     support.funcDecomp = !reNative.test(context.WinRTError) && reThis.test(runInContext);
9476
9477     /**
9478      * Detect if `Function#name` is supported (all but IE).
9479      *
9480      * @memberOf _.support
9481      * @type boolean
9482      */
9483     support.funcNames = typeof Function.name == 'string';
9484
9485     /**
9486      * By default, the template delimiters used by Lo-Dash are similar to those in
9487      * embedded Ruby (ERB). Change the following template settings to use alternative
9488      * delimiters.
9489      *
9490      * @static
9491      * @memberOf _
9492      * @type Object
9493      */
9494     lodash.templateSettings = {
9495
9496       /**
9497        * Used to detect `data` property values to be HTML-escaped.
9498        *
9499        * @memberOf _.templateSettings
9500        * @type RegExp
9501        */
9502       'escape': /<%-([\s\S]+?)%>/g,
9503
9504       /**
9505        * Used to detect code to be evaluated.
9506        *
9507        * @memberOf _.templateSettings
9508        * @type RegExp
9509        */
9510       'evaluate': /<%([\s\S]+?)%>/g,
9511
9512       /**
9513        * Used to detect `data` property values to inject.
9514        *
9515        * @memberOf _.templateSettings
9516        * @type RegExp
9517        */
9518       'interpolate': reInterpolate,
9519
9520       /**
9521        * Used to reference the data object in the template text.
9522        *
9523        * @memberOf _.templateSettings
9524        * @type string
9525        */
9526       'variable': '',
9527
9528       /**
9529        * Used to import variables into the compiled template.
9530        *
9531        * @memberOf _.templateSettings
9532        * @type Object
9533        */
9534       'imports': {
9535
9536         /**
9537          * A reference to the `lodash` function.
9538          *
9539          * @memberOf _.templateSettings.imports
9540          * @type Function
9541          */
9542         '_': lodash
9543       }
9544     };
9545
9546     /*--------------------------------------------------------------------------*/
9547
9548     /**
9549      * The base implementation of `_.clone` without argument juggling or support
9550      * for `thisArg` binding.
9551      *
9552      * @private
9553      * @param {*} value The value to clone.
9554      * @param {boolean} [deep=false] Specify a deep clone.
9555      * @param {Function} [callback] The function to customize cloning values.
9556      * @param {Array} [stackA=[]] Tracks traversed source objects.
9557      * @param {Array} [stackB=[]] Associates clones with source counterparts.
9558      * @returns {*} Returns the cloned value.
9559      */
9560     function baseClone(value, deep, callback, stackA, stackB) {
9561       if (callback) {
9562         var result = callback(value);
9563         if (typeof result != 'undefined') {
9564           return result;
9565         }
9566       }
9567       // inspect [[Class]]
9568       var isObj = isObject(value);
9569       if (isObj) {
9570         var className = toString.call(value);
9571         if (!cloneableClasses[className]) {
9572           return value;
9573         }
9574         var ctor = ctorByClass[className];
9575         switch (className) {
9576           case boolClass:
9577           case dateClass:
9578             return new ctor(+value);
9579
9580           case numberClass:
9581           case stringClass:
9582             return new ctor(value);
9583
9584           case regexpClass:
9585             result = ctor(value.source, reFlags.exec(value));
9586             result.lastIndex = value.lastIndex;
9587             return result;
9588         }
9589       } else {
9590         return value;
9591       }
9592       var isArr = isArray(value);
9593       if (deep) {
9594         // check for circular references and return corresponding clone
9595         var initedStack = !stackA;
9596         stackA || (stackA = getArray());
9597         stackB || (stackB = getArray());
9598
9599         var length = stackA.length;
9600         while (length--) {
9601           if (stackA[length] == value) {
9602             return stackB[length];
9603           }
9604         }
9605         result = isArr ? ctor(value.length) : {};
9606       }
9607       else {
9608         result = isArr ? slice(value) : assign({}, value);
9609       }
9610       // add array properties assigned by `RegExp#exec`
9611       if (isArr) {
9612         if (hasOwnProperty.call(value, 'index')) {
9613           result.index = value.index;
9614         }
9615         if (hasOwnProperty.call(value, 'input')) {
9616           result.input = value.input;
9617         }
9618       }
9619       // exit for shallow clone
9620       if (!deep) {
9621         return result;
9622       }
9623       // add the source value to the stack of traversed objects
9624       // and associate it with its clone
9625       stackA.push(value);
9626       stackB.push(result);
9627
9628       // recursively populate clone (susceptible to call stack limits)
9629       (isArr ? forEach : forOwn)(value, function(objValue, key) {
9630         result[key] = baseClone(objValue, deep, callback, stackA, stackB);
9631       });
9632
9633       if (initedStack) {
9634         releaseArray(stackA);
9635         releaseArray(stackB);
9636       }
9637       return result;
9638     }
9639
9640     /**
9641      * The base implementation of `_.createCallback` without support for creating
9642      * "_.pluck" or "_.where" style callbacks.
9643      *
9644      * @private
9645      * @param {*} [func=identity] The value to convert to a callback.
9646      * @param {*} [thisArg] The `this` binding of the created callback.
9647      * @param {number} [argCount] The number of arguments the callback accepts.
9648      * @returns {Function} Returns a callback function.
9649      */
9650     function baseCreateCallback(func, thisArg, argCount) {
9651       if (typeof func != 'function') {
9652         return identity;
9653       }
9654       // exit early if there is no `thisArg`
9655       if (typeof thisArg == 'undefined') {
9656         return func;
9657       }
9658       var bindData = func.__bindData__ || (support.funcNames && !func.name);
9659       if (typeof bindData == 'undefined') {
9660         var source = reThis && fnToString.call(func);
9661         if (!support.funcNames && source && !reFuncName.test(source)) {
9662           bindData = true;
9663         }
9664         if (support.funcNames || !bindData) {
9665           // checks if `func` references the `this` keyword and stores the result
9666           bindData = !support.funcDecomp || reThis.test(source);
9667           setBindData(func, bindData);
9668         }
9669       }
9670       // exit early if there are no `this` references or `func` is bound
9671       if (bindData !== true && (bindData && bindData[1] & 1)) {
9672         return func;
9673       }
9674       switch (argCount) {
9675         case 1: return function(value) {
9676           return func.call(thisArg, value);
9677         };
9678         case 2: return function(a, b) {
9679           return func.call(thisArg, a, b);
9680         };
9681         case 3: return function(value, index, collection) {
9682           return func.call(thisArg, value, index, collection);
9683         };
9684         case 4: return function(accumulator, value, index, collection) {
9685           return func.call(thisArg, accumulator, value, index, collection);
9686         };
9687       }
9688       return bind(func, thisArg);
9689     }
9690
9691     /**
9692      * The base implementation of `_.flatten` without support for callback
9693      * shorthands or `thisArg` binding.
9694      *
9695      * @private
9696      * @param {Array} array The array to flatten.
9697      * @param {boolean} [isShallow=false] A flag to restrict flattening to a single level.
9698      * @param {boolean} [isArgArrays=false] A flag to restrict flattening to arrays and `arguments` objects.
9699      * @param {number} [fromIndex=0] The index to start from.
9700      * @returns {Array} Returns a new flattened array.
9701      */
9702     function baseFlatten(array, isShallow, isArgArrays, fromIndex) {
9703       var index = (fromIndex || 0) - 1,
9704           length = array ? array.length : 0,
9705           result = [];
9706
9707       while (++index < length) {
9708         var value = array[index];
9709
9710         if (value && typeof value == 'object' && typeof value.length == 'number'
9711             && (isArray(value) || isArguments(value))) {
9712           // recursively flatten arrays (susceptible to call stack limits)
9713           if (!isShallow) {
9714             value = baseFlatten(value, isShallow, isArgArrays);
9715           }
9716           var valIndex = -1,
9717               valLength = value.length,
9718               resIndex = result.length;
9719
9720           result.length += valLength;
9721           while (++valIndex < valLength) {
9722             result[resIndex++] = value[valIndex];
9723           }
9724         } else if (!isArgArrays) {
9725           result.push(value);
9726         }
9727       }
9728       return result;
9729     }
9730
9731     /**
9732      * The base implementation of `_.isEqual`, without support for `thisArg` binding,
9733      * that allows partial "_.where" style comparisons.
9734      *
9735      * @private
9736      * @param {*} a The value to compare.
9737      * @param {*} b The other value to compare.
9738      * @param {Function} [callback] The function to customize comparing values.
9739      * @param {Function} [isWhere=false] A flag to indicate performing partial comparisons.
9740      * @param {Array} [stackA=[]] Tracks traversed `a` objects.
9741      * @param {Array} [stackB=[]] Tracks traversed `b` objects.
9742      * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
9743      */
9744     function baseIsEqual(a, b, callback, isWhere, stackA, stackB) {
9745       // used to indicate that when comparing objects, `a` has at least the properties of `b`
9746       if (callback) {
9747         var result = callback(a, b);
9748         if (typeof result != 'undefined') {
9749           return !!result;
9750         }
9751       }
9752       // exit early for identical values
9753       if (a === b) {
9754         // treat `+0` vs. `-0` as not equal
9755         return a !== 0 || (1 / a == 1 / b);
9756       }
9757       var type = typeof a,
9758           otherType = typeof b;
9759
9760       // exit early for unlike primitive values
9761       if (a === a &&
9762           !(a && objectTypes[type]) &&
9763           !(b && objectTypes[otherType])) {
9764         return false;
9765       }
9766       // exit early for `null` and `undefined` avoiding ES3's Function#call behavior
9767       // http://es5.github.io/#x15.3.4.4
9768       if (a == null || b == null) {
9769         return a === b;
9770       }
9771       // compare [[Class]] names
9772       var className = toString.call(a),
9773           otherClass = toString.call(b);
9774
9775       if (className == argsClass) {
9776         className = objectClass;
9777       }
9778       if (otherClass == argsClass) {
9779         otherClass = objectClass;
9780       }
9781       if (className != otherClass) {
9782         return false;
9783       }
9784       switch (className) {
9785         case boolClass:
9786         case dateClass:
9787           // coerce dates and booleans to numbers, dates to milliseconds and booleans
9788           // to `1` or `0` treating invalid dates coerced to `NaN` as not equal
9789           return +a == +b;
9790
9791         case numberClass:
9792           // treat `NaN` vs. `NaN` as equal
9793           return (a != +a)
9794             ? b != +b
9795             // but treat `+0` vs. `-0` as not equal
9796             : (a == 0 ? (1 / a == 1 / b) : a == +b);
9797
9798         case regexpClass:
9799         case stringClass:
9800           // coerce regexes to strings (http://es5.github.io/#x15.10.6.4)
9801           // treat string primitives and their corresponding object instances as equal
9802           return a == String(b);
9803       }
9804       var isArr = className == arrayClass;
9805       if (!isArr) {
9806         // unwrap any `lodash` wrapped values
9807         if (hasOwnProperty.call(a, '__wrapped__ ') || hasOwnProperty.call(b, '__wrapped__')) {
9808           return baseIsEqual(a.__wrapped__ || a, b.__wrapped__ || b, callback, isWhere, stackA, stackB);
9809         }
9810         // exit for functions and DOM nodes
9811         if (className != objectClass) {
9812           return false;
9813         }
9814         // in older versions of Opera, `arguments` objects have `Array` constructors
9815         var ctorA = a.constructor,
9816             ctorB = b.constructor;
9817
9818         // non `Object` object instances with different constructors are not equal
9819         if (ctorA != ctorB && !(
9820               isFunction(ctorA) && ctorA instanceof ctorA &&
9821               isFunction(ctorB) && ctorB instanceof ctorB
9822             )) {
9823           return false;
9824         }
9825       }
9826       // assume cyclic structures are equal
9827       // the algorithm for detecting cyclic structures is adapted from ES 5.1
9828       // section 15.12.3, abstract operation `JO` (http://es5.github.io/#x15.12.3)
9829       var initedStack = !stackA;
9830       stackA || (stackA = getArray());
9831       stackB || (stackB = getArray());
9832
9833       var length = stackA.length;
9834       while (length--) {
9835         if (stackA[length] == a) {
9836           return stackB[length] == b;
9837         }
9838       }
9839       var size = 0;
9840       result = true;
9841
9842       // add `a` and `b` to the stack of traversed objects
9843       stackA.push(a);
9844       stackB.push(b);
9845
9846       // recursively compare objects and arrays (susceptible to call stack limits)
9847       if (isArr) {
9848         length = a.length;
9849         size = b.length;
9850
9851         // compare lengths to determine if a deep comparison is necessary
9852         result = size == a.length;
9853         if (!result && !isWhere) {
9854           return result;
9855         }
9856         // deep compare the contents, ignoring non-numeric properties
9857         while (size--) {
9858           var index = length,
9859               value = b[size];
9860
9861           if (isWhere) {
9862             while (index--) {
9863               if ((result = baseIsEqual(a[index], value, callback, isWhere, stackA, stackB))) {
9864                 break;
9865               }
9866             }
9867           } else if (!(result = baseIsEqual(a[size], value, callback, isWhere, stackA, stackB))) {
9868             break;
9869           }
9870         }
9871         return result;
9872       }
9873       // deep compare objects using `forIn`, instead of `forOwn`, to avoid `Object.keys`
9874       // which, in this case, is more costly
9875       forIn(b, function(value, key, b) {
9876         if (hasOwnProperty.call(b, key)) {
9877           // count the number of properties.
9878           size++;
9879           // deep compare each property value.
9880           return (result = hasOwnProperty.call(a, key) && baseIsEqual(a[key], value, callback, isWhere, stackA, stackB));
9881         }
9882       });
9883
9884       if (result && !isWhere) {
9885         // ensure both objects have the same number of properties
9886         forIn(a, function(value, key, a) {
9887           if (hasOwnProperty.call(a, key)) {
9888             // `size` will be `-1` if `a` has more properties than `b`
9889             return (result = --size > -1);
9890           }
9891         });
9892       }
9893       if (initedStack) {
9894         releaseArray(stackA);
9895         releaseArray(stackB);
9896       }
9897       return result;
9898     }
9899
9900     /**
9901      * The base implementation of `_.merge` without argument juggling or support
9902      * for `thisArg` binding.
9903      *
9904      * @private
9905      * @param {Object} object The destination object.
9906      * @param {Object} source The source object.
9907      * @param {Function} [callback] The function to customize merging properties.
9908      * @param {Array} [stackA=[]] Tracks traversed source objects.
9909      * @param {Array} [stackB=[]] Associates values with source counterparts.
9910      */
9911     function baseMerge(object, source, callback, stackA, stackB) {
9912       (isArray(source) ? forEach : forOwn)(source, function(source, key) {
9913         var found,
9914             isArr,
9915             result = source,
9916             value = object[key];
9917
9918         if (source && ((isArr = isArray(source)) || isPlainObject(source))) {
9919           // avoid merging previously merged cyclic sources
9920           var stackLength = stackA.length;
9921           while (stackLength--) {
9922             if ((found = stackA[stackLength] == source)) {
9923               value = stackB[stackLength];
9924               break;
9925             }
9926           }
9927           if (!found) {
9928             var isShallow;
9929             if (callback) {
9930               result = callback(value, source);
9931               if ((isShallow = typeof result != 'undefined')) {
9932                 value = result;
9933               }
9934             }
9935             if (!isShallow) {
9936               value = isArr
9937                 ? (isArray(value) ? value : [])
9938                 : (isPlainObject(value) ? value : {});
9939             }
9940             // add `source` and associated `value` to the stack of traversed objects
9941             stackA.push(source);
9942             stackB.push(value);
9943
9944             // recursively merge objects and arrays (susceptible to call stack limits)
9945             if (!isShallow) {
9946               baseMerge(value, source, callback, stackA, stackB);
9947             }
9948           }
9949         }
9950         else {
9951           if (callback) {
9952             result = callback(value, source);
9953             if (typeof result == 'undefined') {
9954               result = source;
9955             }
9956           }
9957           if (typeof result != 'undefined') {
9958             value = result;
9959           }
9960         }
9961         object[key] = value;
9962       });
9963     }
9964
9965     /**
9966      * The base implementation of `_.uniq` without support for callback shorthands
9967      * or `thisArg` binding.
9968      *
9969      * @private
9970      * @param {Array} array The array to process.
9971      * @param {boolean} [isSorted=false] A flag to indicate that `array` is sorted.
9972      * @param {Function} [callback] The function called per iteration.
9973      * @returns {Array} Returns a duplicate-value-free array.
9974      */
9975     function baseUniq(array, isSorted, callback) {
9976       var index = -1,
9977           indexOf = getIndexOf(),
9978           length = array ? array.length : 0,
9979           result = [];
9980
9981       var isLarge = !isSorted && length >= largeArraySize && indexOf === baseIndexOf,
9982           seen = (callback || isLarge) ? getArray() : result;
9983
9984       if (isLarge) {
9985         var cache = createCache(seen);
9986         if (cache) {
9987           indexOf = cacheIndexOf;
9988           seen = cache;
9989         } else {
9990           isLarge = false;
9991           seen = callback ? seen : (releaseArray(seen), result);
9992         }
9993       }
9994       while (++index < length) {
9995         var value = array[index],
9996             computed = callback ? callback(value, index, array) : value;
9997
9998         if (isSorted
9999               ? !index || seen[seen.length - 1] !== computed
10000               : indexOf(seen, computed) < 0
10001             ) {
10002           if (callback || isLarge) {
10003             seen.push(computed);
10004           }
10005           result.push(value);
10006         }
10007       }
10008       if (isLarge) {
10009         releaseArray(seen.array);
10010         releaseObject(seen);
10011       } else if (callback) {
10012         releaseArray(seen);
10013       }
10014       return result;
10015     }
10016
10017     /**
10018      * Creates a function that aggregates a collection, creating an object composed
10019      * of keys generated from the results of running each element of the collection
10020      * through a callback. The given `setter` function sets the keys and values
10021      * of the composed object.
10022      *
10023      * @private
10024      * @param {Function} setter The setter function.
10025      * @returns {Function} Returns the new aggregator function.
10026      */
10027     function createAggregator(setter) {
10028       return function(collection, callback, thisArg) {
10029         var result = {};
10030         callback = lodash.createCallback(callback, thisArg, 3);
10031
10032         var index = -1,
10033             length = collection ? collection.length : 0;
10034
10035         if (typeof length == 'number') {
10036           while (++index < length) {
10037             var value = collection[index];
10038             setter(result, value, callback(value, index, collection), collection);
10039           }
10040         } else {
10041           forOwn(collection, function(value, key, collection) {
10042             setter(result, value, callback(value, key, collection), collection);
10043           });
10044         }
10045         return result;
10046       };
10047     }
10048
10049     /**
10050      * Creates a function that, when called, either curries or invokes `func`
10051      * with an optional `this` binding and partially applied arguments.
10052      *
10053      * @private
10054      * @param {Function|string} func The function or method name to reference.
10055      * @param {number} bitmask The bitmask of method flags to compose.
10056      *  The bitmask may be composed of the following flags:
10057      *  1 - `_.bind`
10058      *  2 - `_.bindKey`
10059      *  4 - `_.curry`
10060      *  8 - `_.curry` (bound)
10061      *  16 - `_.partial`
10062      *  32 - `_.partialRight`
10063      * @param {Array} [partialArgs] An array of arguments to prepend to those
10064      *  provided to the new function.
10065      * @param {Array} [partialRightArgs] An array of arguments to append to those
10066      *  provided to the new function.
10067      * @param {*} [thisArg] The `this` binding of `func`.
10068      * @param {number} [arity] The arity of `func`.
10069      * @returns {Function} Returns the new bound function.
10070      */
10071     function createBound(func, bitmask, partialArgs, partialRightArgs, thisArg, arity) {
10072       var isBind = bitmask & 1,
10073           isBindKey = bitmask & 2,
10074           isCurry = bitmask & 4,
10075           isCurryBound = bitmask & 8,
10076           isPartial = bitmask & 16,
10077           isPartialRight = bitmask & 32,
10078           key = func;
10079
10080       if (!isBindKey && !isFunction(func)) {
10081         throw new TypeError;
10082       }
10083       if (isPartial && !partialArgs.length) {
10084         bitmask &= ~16;
10085         isPartial = partialArgs = false;
10086       }
10087       if (isPartialRight && !partialRightArgs.length) {
10088         bitmask &= ~32;
10089         isPartialRight = partialRightArgs = false;
10090       }
10091       var bindData = func && func.__bindData__;
10092       if (bindData) {
10093         if (isBind && !(bindData[1] & 1)) {
10094           bindData[4] = thisArg;
10095         }
10096         if (!isBind && bindData[1] & 1) {
10097           bitmask |= 8;
10098         }
10099         if (isCurry && !(bindData[1] & 4)) {
10100           bindData[5] = arity;
10101         }
10102         if (isPartial) {
10103           push.apply(bindData[2] || (bindData[2] = []), partialArgs);
10104         }
10105         if (isPartialRight) {
10106           push.apply(bindData[3] || (bindData[3] = []), partialRightArgs);
10107         }
10108         bindData[1] |= bitmask;
10109         return createBound.apply(null, bindData);
10110       }
10111       // use `Function#bind` if it exists and is fast
10112       // (in V8 `Function#bind` is slower except when partially applied)
10113       if (isBind && !(isBindKey || isCurry || isPartialRight) &&
10114           (support.fastBind || (nativeBind && isPartial))) {
10115         if (isPartial) {
10116           var args = [thisArg];
10117           push.apply(args, partialArgs);
10118         }
10119         var bound = isPartial
10120           ? nativeBind.apply(func, args)
10121           : nativeBind.call(func, thisArg);
10122       }
10123       else {
10124         bound = function() {
10125           // `Function#bind` spec
10126           // http://es5.github.io/#x15.3.4.5
10127           var args = arguments,
10128               thisBinding = isBind ? thisArg : this;
10129
10130           if (isCurry || isPartial || isPartialRight) {
10131             args = nativeSlice.call(args);
10132             if (isPartial) {
10133               unshift.apply(args, partialArgs);
10134             }
10135             if (isPartialRight) {
10136               push.apply(args, partialRightArgs);
10137             }
10138             if (isCurry && args.length < arity) {
10139               bitmask |= 16 & ~32;
10140               return createBound(func, (isCurryBound ? bitmask : bitmask & ~3), args, null, thisArg, arity);
10141             }
10142           }
10143           if (isBindKey) {
10144             func = thisBinding[key];
10145           }
10146           if (this instanceof bound) {
10147             // ensure `new bound` is an instance of `func`
10148             thisBinding = createObject(func.prototype);
10149
10150             // mimic the constructor's `return` behavior
10151             // http://es5.github.io/#x13.2.2
10152             var result = func.apply(thisBinding, args);
10153             return isObject(result) ? result : thisBinding;
10154           }
10155           return func.apply(thisBinding, args);
10156         };
10157       }
10158       setBindData(bound, nativeSlice.call(arguments));
10159       return bound;
10160     }
10161
10162     /**
10163      * Creates a new object with the specified `prototype`.
10164      *
10165      * @private
10166      * @param {Object} prototype The prototype object.
10167      * @returns {Object} Returns the new object.
10168      */
10169     function createObject(prototype) {
10170       return isObject(prototype) ? nativeCreate(prototype) : {};
10171     }
10172     // fallback for browsers without `Object.create`
10173     if (!nativeCreate) {
10174       createObject = function(prototype) {
10175         if (isObject(prototype)) {
10176           noop.prototype = prototype;
10177           var result = new noop;
10178           noop.prototype = null;
10179         }
10180         return result || {};
10181       };
10182     }
10183
10184     /**
10185      * Used by `escape` to convert characters to HTML entities.
10186      *
10187      * @private
10188      * @param {string} match The matched character to escape.
10189      * @returns {string} Returns the escaped character.
10190      */
10191     function escapeHtmlChar(match) {
10192       return htmlEscapes[match];
10193     }
10194
10195     /**
10196      * Gets the appropriate "indexOf" function. If the `_.indexOf` method is
10197      * customized, this method returns the custom method, otherwise it returns
10198      * the `baseIndexOf` function.
10199      *
10200      * @private
10201      * @returns {Function} Returns the "indexOf" function.
10202      */
10203     function getIndexOf() {
10204       var result = (result = lodash.indexOf) === indexOf ? baseIndexOf : result;
10205       return result;
10206     }
10207
10208     /**
10209      * Sets `this` binding data on a given function.
10210      *
10211      * @private
10212      * @param {Function} func The function to set data on.
10213      * @param {*} value The value to set.
10214      */
10215     var setBindData = !defineProperty ? noop : function(func, value) {
10216       descriptor.value = value;
10217       defineProperty(func, '__bindData__', descriptor);
10218     };
10219
10220     /**
10221      * A fallback implementation of `isPlainObject` which checks if a given value
10222      * is an object created by the `Object` constructor, assuming objects created
10223      * by the `Object` constructor have no inherited enumerable properties and that
10224      * there are no `Object.prototype` extensions.
10225      *
10226      * @private
10227      * @param {*} value The value to check.
10228      * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
10229      */
10230     function shimIsPlainObject(value) {
10231       var ctor,
10232           result;
10233
10234       // avoid non Object objects, `arguments` objects, and DOM elements
10235       if (!(value && toString.call(value) == objectClass) ||
10236           (ctor = value.constructor, isFunction(ctor) && !(ctor instanceof ctor))) {
10237         return false;
10238       }
10239       // In most environments an object's own properties are iterated before
10240       // its inherited properties. If the last iterated property is an object's
10241       // own property then there are no inherited enumerable properties.
10242       forIn(value, function(value, key) {
10243         result = key;
10244       });
10245       return typeof result == 'undefined' || hasOwnProperty.call(value, result);
10246     }
10247
10248     /**
10249      * Used by `unescape` to convert HTML entities to characters.
10250      *
10251      * @private
10252      * @param {string} match The matched character to unescape.
10253      * @returns {string} Returns the unescaped character.
10254      */
10255     function unescapeHtmlChar(match) {
10256       return htmlUnescapes[match];
10257     }
10258
10259     /*--------------------------------------------------------------------------*/
10260
10261     /**
10262      * Checks if `value` is an `arguments` object.
10263      *
10264      * @static
10265      * @memberOf _
10266      * @category Objects
10267      * @param {*} value The value to check.
10268      * @returns {boolean} Returns `true` if the `value` is an `arguments` object, else `false`.
10269      * @example
10270      *
10271      * (function() { return _.isArguments(arguments); })(1, 2, 3);
10272      * // => true
10273      *
10274      * _.isArguments([1, 2, 3]);
10275      * // => false
10276      */
10277     function isArguments(value) {
10278       return value && typeof value == 'object' && typeof value.length == 'number' &&
10279         toString.call(value) == argsClass || false;
10280     }
10281
10282     /**
10283      * Checks if `value` is an array.
10284      *
10285      * @static
10286      * @memberOf _
10287      * @type Function
10288      * @category Objects
10289      * @param {*} value The value to check.
10290      * @returns {boolean} Returns `true` if the `value` is an array, else `false`.
10291      * @example
10292      *
10293      * (function() { return _.isArray(arguments); })();
10294      * // => false
10295      *
10296      * _.isArray([1, 2, 3]);
10297      * // => true
10298      */
10299     var isArray = nativeIsArray || function(value) {
10300       return value && typeof value == 'object' && typeof value.length == 'number' &&
10301         toString.call(value) == arrayClass || false;
10302     };
10303
10304     /**
10305      * A fallback implementation of `Object.keys` which produces an array of the
10306      * given object's own enumerable property names.
10307      *
10308      * @private
10309      * @type Function
10310      * @param {Object} object The object to inspect.
10311      * @returns {Array} Returns an array of property names.
10312      */
10313     var shimKeys = function(object) {
10314       var index, iterable = object, result = [];
10315       if (!iterable) return result;
10316       if (!(objectTypes[typeof object])) return result;
10317         for (index in iterable) {
10318           if (hasOwnProperty.call(iterable, index)) {
10319             result.push(index);
10320           }
10321         }
10322       return result
10323     };
10324
10325     /**
10326      * Creates an array composed of the own enumerable property names of an object.
10327      *
10328      * @static
10329      * @memberOf _
10330      * @category Objects
10331      * @param {Object} object The object to inspect.
10332      * @returns {Array} Returns an array of property names.
10333      * @example
10334      *
10335      * _.keys({ 'one': 1, 'two': 2, 'three': 3 });
10336      * // => ['one', 'two', 'three'] (property order is not guaranteed across environments)
10337      */
10338     var keys = !nativeKeys ? shimKeys : function(object) {
10339       if (!isObject(object)) {
10340         return [];
10341       }
10342       return nativeKeys(object);
10343     };
10344
10345     /**
10346      * Used to convert characters to HTML entities:
10347      *
10348      * Though the `>` character is escaped for symmetry, characters like `>` and `/`
10349      * don't require escaping in HTML and have no special meaning unless they're part
10350      * of a tag or an unquoted attribute value.
10351      * http://mathiasbynens.be/notes/ambiguous-ampersands (under "semi-related fun fact")
10352      */
10353     var htmlEscapes = {
10354       '&': '&amp;',
10355       '<': '&lt;',
10356       '>': '&gt;',
10357       '"': '&quot;',
10358       "'": '&#39;'
10359     };
10360
10361     /** Used to convert HTML entities to characters */
10362     var htmlUnescapes = invert(htmlEscapes);
10363
10364     /** Used to match HTML entities and HTML characters */
10365     var reEscapedHtml = RegExp('(' + keys(htmlUnescapes).join('|') + ')', 'g'),
10366         reUnescapedHtml = RegExp('[' + keys(htmlEscapes).join('') + ']', 'g');
10367
10368     /*--------------------------------------------------------------------------*/
10369
10370     /**
10371      * Assigns own enumerable properties of source object(s) to the destination
10372      * object. Subsequent sources will overwrite property assignments of previous
10373      * sources. If a callback is provided it will be executed to produce the
10374      * assigned values. The callback is bound to `thisArg` and invoked with two
10375      * arguments; (objectValue, sourceValue).
10376      *
10377      * @static
10378      * @memberOf _
10379      * @type Function
10380      * @alias extend
10381      * @category Objects
10382      * @param {Object} object The destination object.
10383      * @param {...Object} [source] The source objects.
10384      * @param {Function} [callback] The function to customize assigning values.
10385      * @param {*} [thisArg] The `this` binding of `callback`.
10386      * @returns {Object} Returns the destination object.
10387      * @example
10388      *
10389      * _.assign({ 'name': 'moe' }, { 'age': 40 });
10390      * // => { 'name': 'moe', 'age': 40 }
10391      *
10392      * var defaults = _.partialRight(_.assign, function(a, b) {
10393      *   return typeof a == 'undefined' ? b : a;
10394      * });
10395      *
10396      * var food = { 'name': 'apple' };
10397      * defaults(food, { 'name': 'banana', 'type': 'fruit' });
10398      * // => { 'name': 'apple', 'type': 'fruit' }
10399      */
10400     var assign = function(object, source, guard) {
10401       var index, iterable = object, result = iterable;
10402       if (!iterable) return result;
10403       var args = arguments,
10404           argsIndex = 0,
10405           argsLength = typeof guard == 'number' ? 2 : args.length;
10406       if (argsLength > 3 && typeof args[argsLength - 2] == 'function') {
10407         var callback = baseCreateCallback(args[--argsLength - 1], args[argsLength--], 2);
10408       } else if (argsLength > 2 && typeof args[argsLength - 1] == 'function') {
10409         callback = args[--argsLength];
10410       }
10411       while (++argsIndex < argsLength) {
10412         iterable = args[argsIndex];
10413         if (iterable && objectTypes[typeof iterable]) {
10414         var ownIndex = -1,
10415             ownProps = objectTypes[typeof iterable] && keys(iterable),
10416             length = ownProps ? ownProps.length : 0;
10417
10418         while (++ownIndex < length) {
10419           index = ownProps[ownIndex];
10420           result[index] = callback ? callback(result[index], iterable[index]) : iterable[index];
10421         }
10422         }
10423       }
10424       return result
10425     };
10426
10427     /**
10428      * Creates a clone of `value`. If `deep` is `true` nested objects will also
10429      * be cloned, otherwise they will be assigned by reference. If a callback
10430      * is provided it will be executed to produce the cloned values. If the
10431      * callback returns `undefined` cloning will be handled by the method instead.
10432      * The callback is bound to `thisArg` and invoked with one argument; (value).
10433      *
10434      * @static
10435      * @memberOf _
10436      * @category Objects
10437      * @param {*} value The value to clone.
10438      * @param {boolean} [deep=false] Specify a deep clone.
10439      * @param {Function} [callback] The function to customize cloning values.
10440      * @param {*} [thisArg] The `this` binding of `callback`.
10441      * @returns {*} Returns the cloned value.
10442      * @example
10443      *
10444      * var stooges = [
10445      *   { 'name': 'moe', 'age': 40 },
10446      *   { 'name': 'larry', 'age': 50 }
10447      * ];
10448      *
10449      * var shallow = _.clone(stooges);
10450      * shallow[0] === stooges[0];
10451      * // => true
10452      *
10453      * var deep = _.clone(stooges, true);
10454      * deep[0] === stooges[0];
10455      * // => false
10456      *
10457      * _.mixin({
10458      *   'clone': _.partialRight(_.clone, function(value) {
10459      *     return _.isElement(value) ? value.cloneNode(false) : undefined;
10460      *   })
10461      * });
10462      *
10463      * var clone = _.clone(document.body);
10464      * clone.childNodes.length;
10465      * // => 0
10466      */
10467     function clone(value, deep, callback, thisArg) {
10468       // allows working with "Collections" methods without using their `index`
10469       // and `collection` arguments for `deep` and `callback`
10470       if (typeof deep != 'boolean' && deep != null) {
10471         thisArg = callback;
10472         callback = deep;
10473         deep = false;
10474       }
10475       return baseClone(value, deep, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 1));
10476     }
10477
10478     /**
10479      * Creates a deep clone of `value`. If a callback is provided it will be
10480      * executed to produce the cloned values. If the callback returns `undefined`
10481      * cloning will be handled by the method instead. The callback is bound to
10482      * `thisArg` and invoked with one argument; (value).
10483      *
10484      * Note: This method is loosely based on the structured clone algorithm. Functions
10485      * and DOM nodes are **not** cloned. The enumerable properties of `arguments` objects and
10486      * objects created by constructors other than `Object` are cloned to plain `Object` objects.
10487      * See http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm.
10488      *
10489      * @static
10490      * @memberOf _
10491      * @category Objects
10492      * @param {*} value The value to deep clone.
10493      * @param {Function} [callback] The function to customize cloning values.
10494      * @param {*} [thisArg] The `this` binding of `callback`.
10495      * @returns {*} Returns the deep cloned value.
10496      * @example
10497      *
10498      * var stooges = [
10499      *   { 'name': 'moe', 'age': 40 },
10500      *   { 'name': 'larry', 'age': 50 }
10501      * ];
10502      *
10503      * var deep = _.cloneDeep(stooges);
10504      * deep[0] === stooges[0];
10505      * // => false
10506      *
10507      * var view = {
10508      *   'label': 'docs',
10509      *   'node': element
10510      * };
10511      *
10512      * var clone = _.cloneDeep(view, function(value) {
10513      *   return _.isElement(value) ? value.cloneNode(true) : undefined;
10514      * });
10515      *
10516      * clone.node == view.node;
10517      * // => false
10518      */
10519     function cloneDeep(value, callback, thisArg) {
10520       return baseClone(value, true, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 1));
10521     }
10522
10523     /**
10524      * Assigns own enumerable properties of source object(s) to the destination
10525      * object for all destination properties that resolve to `undefined`. Once a
10526      * property is set, additional defaults of the same property will be ignored.
10527      *
10528      * @static
10529      * @memberOf _
10530      * @type Function
10531      * @category Objects
10532      * @param {Object} object The destination object.
10533      * @param {...Object} [source] The source objects.
10534      * @param- {Object} [guard] Allows working with `_.reduce` without using its
10535      *  `key` and `object` arguments as sources.
10536      * @returns {Object} Returns the destination object.
10537      * @example
10538      *
10539      * var food = { 'name': 'apple' };
10540      * _.defaults(food, { 'name': 'banana', 'type': 'fruit' });
10541      * // => { 'name': 'apple', 'type': 'fruit' }
10542      */
10543     var defaults = function(object, source, guard) {
10544       var index, iterable = object, result = iterable;
10545       if (!iterable) return result;
10546       var args = arguments,
10547           argsIndex = 0,
10548           argsLength = typeof guard == 'number' ? 2 : args.length;
10549       while (++argsIndex < argsLength) {
10550         iterable = args[argsIndex];
10551         if (iterable && objectTypes[typeof iterable]) {
10552         var ownIndex = -1,
10553             ownProps = objectTypes[typeof iterable] && keys(iterable),
10554             length = ownProps ? ownProps.length : 0;
10555
10556         while (++ownIndex < length) {
10557           index = ownProps[ownIndex];
10558           if (typeof result[index] == 'undefined') result[index] = iterable[index];
10559         }
10560         }
10561       }
10562       return result
10563     };
10564
10565     /**
10566      * This method is like `_.findIndex` except that it returns the key of the
10567      * first element that passes the callback check, instead of the element itself.
10568      *
10569      * @static
10570      * @memberOf _
10571      * @category Objects
10572      * @param {Object} object The object to search.
10573      * @param {Function|Object|string} [callback=identity] The function called per
10574      *  iteration. If a property name or object is provided it will be used to
10575      *  create a "_.pluck" or "_.where" style callback, respectively.
10576      * @param {*} [thisArg] The `this` binding of `callback`.
10577      * @returns {string|undefined} Returns the key of the found element, else `undefined`.
10578      * @example
10579      *
10580      * _.findKey({ 'a': 1, 'b': 2, 'c': 3, 'd': 4 }, function(num) {
10581      *   return num % 2 == 0;
10582      * });
10583      * // => 'b' (property order is not guaranteed across environments)
10584      */
10585     function findKey(object, callback, thisArg) {
10586       var result;
10587       callback = lodash.createCallback(callback, thisArg, 3);
10588       forOwn(object, function(value, key, object) {
10589         if (callback(value, key, object)) {
10590           result = key;
10591           return false;
10592         }
10593       });
10594       return result;
10595     }
10596
10597     /**
10598      * This method is like `_.findKey` except that it iterates over elements
10599      * of a `collection` in the opposite order.
10600      *
10601      * @static
10602      * @memberOf _
10603      * @category Objects
10604      * @param {Object} object The object to search.
10605      * @param {Function|Object|string} [callback=identity] The function called per
10606      *  iteration. If a property name or object is provided it will be used to
10607      *  create a "_.pluck" or "_.where" style callback, respectively.
10608      * @param {*} [thisArg] The `this` binding of `callback`.
10609      * @returns {string|undefined} Returns the key of the found element, else `undefined`.
10610      * @example
10611      *
10612      * _.findLastKey({ 'a': 1, 'b': 2, 'c': 3, 'd': 4 }, function(num) {
10613      *   return num % 2 == 1;
10614      * });
10615      * // => returns `c`, assuming `_.findKey` returns `a`
10616      */
10617     function findLastKey(object, callback, thisArg) {
10618       var result;
10619       callback = lodash.createCallback(callback, thisArg, 3);
10620       forOwnRight(object, function(value, key, object) {
10621         if (callback(value, key, object)) {
10622           result = key;
10623           return false;
10624         }
10625       });
10626       return result;
10627     }
10628
10629     /**
10630      * Iterates over own and inherited enumerable properties of an object,
10631      * executing the callback for each property. The callback is bound to `thisArg`
10632      * and invoked with three arguments; (value, key, object). Callbacks may exit
10633      * iteration early by explicitly returning `false`.
10634      *
10635      * @static
10636      * @memberOf _
10637      * @type Function
10638      * @category Objects
10639      * @param {Object} object The object to iterate over.
10640      * @param {Function} [callback=identity] The function called per iteration.
10641      * @param {*} [thisArg] The `this` binding of `callback`.
10642      * @returns {Object} Returns `object`.
10643      * @example
10644      *
10645      * function Dog(name) {
10646      *   this.name = name;
10647      * }
10648      *
10649      * Dog.prototype.bark = function() {
10650      *   console.log('Woof, woof!');
10651      * };
10652      *
10653      * _.forIn(new Dog('Dagny'), function(value, key) {
10654      *   console.log(key);
10655      * });
10656      * // => logs 'bark' and 'name' (property order is not guaranteed across environments)
10657      */
10658     var forIn = function(collection, callback, thisArg) {
10659       var index, iterable = collection, result = iterable;
10660       if (!iterable) return result;
10661       if (!objectTypes[typeof iterable]) return result;
10662       callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);
10663         for (index in iterable) {
10664           if (callback(iterable[index], index, collection) === false) return result;
10665         }
10666       return result
10667     };
10668
10669     /**
10670      * This method is like `_.forIn` except that it iterates over elements
10671      * of a `collection` in the opposite order.
10672      *
10673      * @static
10674      * @memberOf _
10675      * @category Objects
10676      * @param {Object} object The object to iterate over.
10677      * @param {Function} [callback=identity] The function called per iteration.
10678      * @param {*} [thisArg] The `this` binding of `callback`.
10679      * @returns {Object} Returns `object`.
10680      * @example
10681      *
10682      * function Dog(name) {
10683      *   this.name = name;
10684      * }
10685      *
10686      * Dog.prototype.bark = function() {
10687      *   console.log('Woof, woof!');
10688      * };
10689      *
10690      * _.forInRight(new Dog('Dagny'), function(value, key) {
10691      *   console.log(key);
10692      * });
10693      * // => logs 'name' and 'bark' assuming `_.forIn ` logs 'bark' and 'name'
10694      */
10695     function forInRight(object, callback, thisArg) {
10696       var pairs = [];
10697
10698       forIn(object, function(value, key) {
10699         pairs.push(key, value);
10700       });
10701
10702       var length = pairs.length;
10703       callback = baseCreateCallback(callback, thisArg, 3);
10704       while (length--) {
10705         if (callback(pairs[length--], pairs[length], object) === false) {
10706           break;
10707         }
10708       }
10709       return object;
10710     }
10711
10712     /**
10713      * Iterates over own enumerable properties of an object, executing the callback
10714      * for each property. The callback is bound to `thisArg` and invoked with three
10715      * arguments; (value, key, object). Callbacks may exit iteration early by
10716      * explicitly returning `false`.
10717      *
10718      * @static
10719      * @memberOf _
10720      * @type Function
10721      * @category Objects
10722      * @param {Object} object The object to iterate over.
10723      * @param {Function} [callback=identity] The function called per iteration.
10724      * @param {*} [thisArg] The `this` binding of `callback`.
10725      * @returns {Object} Returns `object`.
10726      * @example
10727      *
10728      * _.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) {
10729      *   console.log(key);
10730      * });
10731      * // => logs '0', '1', and 'length' (property order is not guaranteed across environments)
10732      */
10733     var forOwn = function(collection, callback, thisArg) {
10734       var index, iterable = collection, result = iterable;
10735       if (!iterable) return result;
10736       if (!objectTypes[typeof iterable]) return result;
10737       callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);
10738         var ownIndex = -1,
10739             ownProps = objectTypes[typeof iterable] && keys(iterable),
10740             length = ownProps ? ownProps.length : 0;
10741
10742         while (++ownIndex < length) {
10743           index = ownProps[ownIndex];
10744           if (callback(iterable[index], index, collection) === false) return result;
10745         }
10746       return result
10747     };
10748
10749     /**
10750      * This method is like `_.forOwn` except that it iterates over elements
10751      * of a `collection` in the opposite order.
10752      *
10753      * @static
10754      * @memberOf _
10755      * @category Objects
10756      * @param {Object} object The object to iterate over.
10757      * @param {Function} [callback=identity] The function called per iteration.
10758      * @param {*} [thisArg] The `this` binding of `callback`.
10759      * @returns {Object} Returns `object`.
10760      * @example
10761      *
10762      * _.forOwnRight({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) {
10763      *   console.log(key);
10764      * });
10765      * // => logs 'length', '1', and '0' assuming `_.forOwn` logs '0', '1', and 'length'
10766      */
10767     function forOwnRight(object, callback, thisArg) {
10768       var props = keys(object),
10769           length = props.length;
10770
10771       callback = baseCreateCallback(callback, thisArg, 3);
10772       while (length--) {
10773         var key = props[length];
10774         if (callback(object[key], key, object) === false) {
10775           break;
10776         }
10777       }
10778       return object;
10779     }
10780
10781     /**
10782      * Creates a sorted array of property names of all enumerable properties,
10783      * own and inherited, of `object` that have function values.
10784      *
10785      * @static
10786      * @memberOf _
10787      * @alias methods
10788      * @category Objects
10789      * @param {Object} object The object to inspect.
10790      * @returns {Array} Returns an array of property names that have function values.
10791      * @example
10792      *
10793      * _.functions(_);
10794      * // => ['all', 'any', 'bind', 'bindAll', 'clone', 'compact', 'compose', ...]
10795      */
10796     function functions(object) {
10797       var result = [];
10798       forIn(object, function(value, key) {
10799         if (isFunction(value)) {
10800           result.push(key);
10801         }
10802       });
10803       return result.sort();
10804     }
10805
10806     /**
10807      * Checks if the specified object `property` exists and is a direct property,
10808      * instead of an inherited property.
10809      *
10810      * @static
10811      * @memberOf _
10812      * @category Objects
10813      * @param {Object} object The object to check.
10814      * @param {string} property The property to check for.
10815      * @returns {boolean} Returns `true` if key is a direct property, else `false`.
10816      * @example
10817      *
10818      * _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b');
10819      * // => true
10820      */
10821     function has(object, property) {
10822       return object ? hasOwnProperty.call(object, property) : false;
10823     }
10824
10825     /**
10826      * Creates an object composed of the inverted keys and values of the given object.
10827      *
10828      * @static
10829      * @memberOf _
10830      * @category Objects
10831      * @param {Object} object The object to invert.
10832      * @returns {Object} Returns the created inverted object.
10833      * @example
10834      *
10835      *  _.invert({ 'first': 'moe', 'second': 'larry' });
10836      * // => { 'moe': 'first', 'larry': 'second' }
10837      */
10838     function invert(object) {
10839       var index = -1,
10840           props = keys(object),
10841           length = props.length,
10842           result = {};
10843
10844       while (++index < length) {
10845         var key = props[index];
10846         result[object[key]] = key;
10847       }
10848       return result;
10849     }
10850
10851     /**
10852      * Checks if `value` is a boolean value.
10853      *
10854      * @static
10855      * @memberOf _
10856      * @category Objects
10857      * @param {*} value The value to check.
10858      * @returns {boolean} Returns `true` if the `value` is a boolean value, else `false`.
10859      * @example
10860      *
10861      * _.isBoolean(null);
10862      * // => false
10863      */
10864     function isBoolean(value) {
10865       return value === true || value === false || toString.call(value) == boolClass;
10866     }
10867
10868     /**
10869      * Checks if `value` is a date.
10870      *
10871      * @static
10872      * @memberOf _
10873      * @category Objects
10874      * @param {*} value The value to check.
10875      * @returns {boolean} Returns `true` if the `value` is a date, else `false`.
10876      * @example
10877      *
10878      * _.isDate(new Date);
10879      * // => true
10880      */
10881     function isDate(value) {
10882       return value ? (typeof value == 'object' && toString.call(value) == dateClass) : false;
10883     }
10884
10885     /**
10886      * Checks if `value` is a DOM element.
10887      *
10888      * @static
10889      * @memberOf _
10890      * @category Objects
10891      * @param {*} value The value to check.
10892      * @returns {boolean} Returns `true` if the `value` is a DOM element, else `false`.
10893      * @example
10894      *
10895      * _.isElement(document.body);
10896      * // => true
10897      */
10898     function isElement(value) {
10899       return value ? value.nodeType === 1 : false;
10900     }
10901
10902     /**
10903      * Checks if `value` is empty. Arrays, strings, or `arguments` objects with a
10904      * length of `0` and objects with no own enumerable properties are considered
10905      * "empty".
10906      *
10907      * @static
10908      * @memberOf _
10909      * @category Objects
10910      * @param {Array|Object|string} value The value to inspect.
10911      * @returns {boolean} Returns `true` if the `value` is empty, else `false`.
10912      * @example
10913      *
10914      * _.isEmpty([1, 2, 3]);
10915      * // => false
10916      *
10917      * _.isEmpty({});
10918      * // => true
10919      *
10920      * _.isEmpty('');
10921      * // => true
10922      */
10923     function isEmpty(value) {
10924       var result = true;
10925       if (!value) {
10926         return result;
10927       }
10928       var className = toString.call(value),
10929           length = value.length;
10930
10931       if ((className == arrayClass || className == stringClass || className == argsClass ) ||
10932           (className == objectClass && typeof length == 'number' && isFunction(value.splice))) {
10933         return !length;
10934       }
10935       forOwn(value, function() {
10936         return (result = false);
10937       });
10938       return result;
10939     }
10940
10941     /**
10942      * Performs a deep comparison between two values to determine if they are
10943      * equivalent to each other. If a callback is provided it will be executed
10944      * to compare values. If the callback returns `undefined` comparisons will
10945      * be handled by the method instead. The callback is bound to `thisArg` and
10946      * invoked with two arguments; (a, b).
10947      *
10948      * @static
10949      * @memberOf _
10950      * @category Objects
10951      * @param {*} a The value to compare.
10952      * @param {*} b The other value to compare.
10953      * @param {Function} [callback] The function to customize comparing values.
10954      * @param {*} [thisArg] The `this` binding of `callback`.
10955      * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
10956      * @example
10957      *
10958      * var moe = { 'name': 'moe', 'age': 40 };
10959      * var copy = { 'name': 'moe', 'age': 40 };
10960      *
10961      * moe == copy;
10962      * // => false
10963      *
10964      * _.isEqual(moe, copy);
10965      * // => true
10966      *
10967      * var words = ['hello', 'goodbye'];
10968      * var otherWords = ['hi', 'goodbye'];
10969      *
10970      * _.isEqual(words, otherWords, function(a, b) {
10971      *   var reGreet = /^(?:hello|hi)$/i,
10972      *       aGreet = _.isString(a) && reGreet.test(a),
10973      *       bGreet = _.isString(b) && reGreet.test(b);
10974      *
10975      *   return (aGreet || bGreet) ? (aGreet == bGreet) : undefined;
10976      * });
10977      * // => true
10978      */
10979     function isEqual(a, b, callback, thisArg) {
10980       return baseIsEqual(a, b, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 2));
10981     }
10982
10983     /**
10984      * Checks if `value` is, or can be coerced to, a finite number.
10985      *
10986      * Note: This is not the same as native `isFinite` which will return true for
10987      * booleans and empty strings. See http://es5.github.io/#x15.1.2.5.
10988      *
10989      * @static
10990      * @memberOf _
10991      * @category Objects
10992      * @param {*} value The value to check.
10993      * @returns {boolean} Returns `true` if the `value` is finite, else `false`.
10994      * @example
10995      *
10996      * _.isFinite(-101);
10997      * // => true
10998      *
10999      * _.isFinite('10');
11000      * // => true
11001      *
11002      * _.isFinite(true);
11003      * // => false
11004      *
11005      * _.isFinite('');
11006      * // => false
11007      *
11008      * _.isFinite(Infinity);
11009      * // => false
11010      */
11011     function isFinite(value) {
11012       return nativeIsFinite(value) && !nativeIsNaN(parseFloat(value));
11013     }
11014
11015     /**
11016      * Checks if `value` is a function.
11017      *
11018      * @static
11019      * @memberOf _
11020      * @category Objects
11021      * @param {*} value The value to check.
11022      * @returns {boolean} Returns `true` if the `value` is a function, else `false`.
11023      * @example
11024      *
11025      * _.isFunction(_);
11026      * // => true
11027      */
11028     function isFunction(value) {
11029       return typeof value == 'function';
11030     }
11031
11032     /**
11033      * Checks if `value` is the language type of Object.
11034      * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
11035      *
11036      * @static
11037      * @memberOf _
11038      * @category Objects
11039      * @param {*} value The value to check.
11040      * @returns {boolean} Returns `true` if the `value` is an object, else `false`.
11041      * @example
11042      *
11043      * _.isObject({});
11044      * // => true
11045      *
11046      * _.isObject([1, 2, 3]);
11047      * // => true
11048      *
11049      * _.isObject(1);
11050      * // => false
11051      */
11052     function isObject(value) {
11053       // check if the value is the ECMAScript language type of Object
11054       // http://es5.github.io/#x8
11055       // and avoid a V8 bug
11056       // http://code.google.com/p/v8/issues/detail?id=2291
11057       return !!(value && objectTypes[typeof value]);
11058     }
11059
11060     /**
11061      * Checks if `value` is `NaN`.
11062      *
11063      * Note: This is not the same as native `isNaN` which will return `true` for
11064      * `undefined` and other non-numeric values. See http://es5.github.io/#x15.1.2.4.
11065      *
11066      * @static
11067      * @memberOf _
11068      * @category Objects
11069      * @param {*} value The value to check.
11070      * @returns {boolean} Returns `true` if the `value` is `NaN`, else `false`.
11071      * @example
11072      *
11073      * _.isNaN(NaN);
11074      * // => true
11075      *
11076      * _.isNaN(new Number(NaN));
11077      * // => true
11078      *
11079      * isNaN(undefined);
11080      * // => true
11081      *
11082      * _.isNaN(undefined);
11083      * // => false
11084      */
11085     function isNaN(value) {
11086       // `NaN` as a primitive is the only value that is not equal to itself
11087       // (perform the [[Class]] check first to avoid errors with some host objects in IE)
11088       return isNumber(value) && value != +value;
11089     }
11090
11091     /**
11092      * Checks if `value` is `null`.
11093      *
11094      * @static
11095      * @memberOf _
11096      * @category Objects
11097      * @param {*} value The value to check.
11098      * @returns {boolean} Returns `true` if the `value` is `null`, else `false`.
11099      * @example
11100      *
11101      * _.isNull(null);
11102      * // => true
11103      *
11104      * _.isNull(undefined);
11105      * // => false
11106      */
11107     function isNull(value) {
11108       return value === null;
11109     }
11110
11111     /**
11112      * Checks if `value` is a number.
11113      *
11114      * Note: `NaN` is considered a number. See http://es5.github.io/#x8.5.
11115      *
11116      * @static
11117      * @memberOf _
11118      * @category Objects
11119      * @param {*} value The value to check.
11120      * @returns {boolean} Returns `true` if the `value` is a number, else `false`.
11121      * @example
11122      *
11123      * _.isNumber(8.4 * 5);
11124      * // => true
11125      */
11126     function isNumber(value) {
11127       return typeof value == 'number' || toString.call(value) == numberClass;
11128     }
11129
11130     /**
11131      * Checks if `value` is an object created by the `Object` constructor.
11132      *
11133      * @static
11134      * @memberOf _
11135      * @category Objects
11136      * @param {*} value The value to check.
11137      * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
11138      * @example
11139      *
11140      * function Stooge(name, age) {
11141      *   this.name = name;
11142      *   this.age = age;
11143      * }
11144      *
11145      * _.isPlainObject(new Stooge('moe', 40));
11146      * // => false
11147      *
11148      * _.isPlainObject([1, 2, 3]);
11149      * // => false
11150      *
11151      * _.isPlainObject({ 'name': 'moe', 'age': 40 });
11152      * // => true
11153      */
11154     var isPlainObject = function(value) {
11155       if (!(value && toString.call(value) == objectClass)) {
11156         return false;
11157       }
11158       var valueOf = value.valueOf,
11159           objProto = typeof valueOf == 'function' && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto);
11160
11161       return objProto
11162         ? (value == objProto || getPrototypeOf(value) == objProto)
11163         : shimIsPlainObject(value);
11164     };
11165
11166     /**
11167      * Checks if `value` is a regular expression.
11168      *
11169      * @static
11170      * @memberOf _
11171      * @category Objects
11172      * @param {*} value The value to check.
11173      * @returns {boolean} Returns `true` if the `value` is a regular expression, else `false`.
11174      * @example
11175      *
11176      * _.isRegExp(/moe/);
11177      * // => true
11178      */
11179     function isRegExp(value) {
11180       return value ? (typeof value == 'object' && toString.call(value) == regexpClass) : false;
11181     }
11182
11183     /**
11184      * Checks if `value` is a string.
11185      *
11186      * @static
11187      * @memberOf _
11188      * @category Objects
11189      * @param {*} value The value to check.
11190      * @returns {boolean} Returns `true` if the `value` is a string, else `false`.
11191      * @example
11192      *
11193      * _.isString('moe');
11194      * // => true
11195      */
11196     function isString(value) {
11197       return typeof value == 'string' || toString.call(value) == stringClass;
11198     }
11199
11200     /**
11201      * Checks if `value` is `undefined`.
11202      *
11203      * @static
11204      * @memberOf _
11205      * @category Objects
11206      * @param {*} value The value to check.
11207      * @returns {boolean} Returns `true` if the `value` is `undefined`, else `false`.
11208      * @example
11209      *
11210      * _.isUndefined(void 0);
11211      * // => true
11212      */
11213     function isUndefined(value) {
11214       return typeof value == 'undefined';
11215     }
11216
11217     /**
11218      * Recursively merges own enumerable properties of the source object(s), that
11219      * don't resolve to `undefined` into the destination object. Subsequent sources
11220      * will overwrite property assignments of previous sources. If a callback is
11221      * provided it will be executed to produce the merged values of the destination
11222      * and source properties. If the callback returns `undefined` merging will
11223      * be handled by the method instead. The callback is bound to `thisArg` and
11224      * invoked with two arguments; (objectValue, sourceValue).
11225      *
11226      * @static
11227      * @memberOf _
11228      * @category Objects
11229      * @param {Object} object The destination object.
11230      * @param {...Object} [source] The source objects.
11231      * @param {Function} [callback] The function to customize merging properties.
11232      * @param {*} [thisArg] The `this` binding of `callback`.
11233      * @returns {Object} Returns the destination object.
11234      * @example
11235      *
11236      * var names = {
11237      *   'stooges': [
11238      *     { 'name': 'moe' },
11239      *     { 'name': 'larry' }
11240      *   ]
11241      * };
11242      *
11243      * var ages = {
11244      *   'stooges': [
11245      *     { 'age': 40 },
11246      *     { 'age': 50 }
11247      *   ]
11248      * };
11249      *
11250      * _.merge(names, ages);
11251      * // => { 'stooges': [{ 'name': 'moe', 'age': 40 }, { 'name': 'larry', 'age': 50 }] }
11252      *
11253      * var food = {
11254      *   'fruits': ['apple'],
11255      *   'vegetables': ['beet']
11256      * };
11257      *
11258      * var otherFood = {
11259      *   'fruits': ['banana'],
11260      *   'vegetables': ['carrot']
11261      * };
11262      *
11263      * _.merge(food, otherFood, function(a, b) {
11264      *   return _.isArray(a) ? a.concat(b) : undefined;
11265      * });
11266      * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot] }
11267      */
11268     function merge(object) {
11269       var args = arguments,
11270           length = 2;
11271
11272       if (!isObject(object)) {
11273         return object;
11274       }
11275       // allows working with `_.reduce` and `_.reduceRight` without using
11276       // their `index` and `collection` arguments
11277       if (typeof args[2] != 'number') {
11278         length = args.length;
11279       }
11280       if (length > 3 && typeof args[length - 2] == 'function') {
11281         var callback = baseCreateCallback(args[--length - 1], args[length--], 2);
11282       } else if (length > 2 && typeof args[length - 1] == 'function') {
11283         callback = args[--length];
11284       }
11285       var sources = nativeSlice.call(arguments, 1, length),
11286           index = -1,
11287           stackA = getArray(),
11288           stackB = getArray();
11289
11290       while (++index < length) {
11291         baseMerge(object, sources[index], callback, stackA, stackB);
11292       }
11293       releaseArray(stackA);
11294       releaseArray(stackB);
11295       return object;
11296     }
11297
11298     /**
11299      * Creates a shallow clone of `object` excluding the specified properties.
11300      * Property names may be specified as individual arguments or as arrays of
11301      * property names. If a callback is provided it will be executed for each
11302      * property of `object` omitting the properties the callback returns truey
11303      * for. The callback is bound to `thisArg` and invoked with three arguments;
11304      * (value, key, object).
11305      *
11306      * @static
11307      * @memberOf _
11308      * @category Objects
11309      * @param {Object} object The source object.
11310      * @param {Function|...string|string[]} [callback] The properties to omit or the
11311      *  function called per iteration.
11312      * @param {*} [thisArg] The `this` binding of `callback`.
11313      * @returns {Object} Returns an object without the omitted properties.
11314      * @example
11315      *
11316      * _.omit({ 'name': 'moe', 'age': 40 }, 'age');
11317      * // => { 'name': 'moe' }
11318      *
11319      * _.omit({ 'name': 'moe', 'age': 40 }, function(value) {
11320      *   return typeof value == 'number';
11321      * });
11322      * // => { 'name': 'moe' }
11323      */
11324     function omit(object, callback, thisArg) {
11325       var indexOf = getIndexOf(),
11326           isFunc = typeof callback == 'function',
11327           result = {};
11328
11329       if (isFunc) {
11330         callback = lodash.createCallback(callback, thisArg, 3);
11331       } else {
11332         var props = baseFlatten(arguments, true, false, 1);
11333       }
11334       forIn(object, function(value, key, object) {
11335         if (isFunc
11336               ? !callback(value, key, object)
11337               : indexOf(props, key) < 0
11338             ) {
11339           result[key] = value;
11340         }
11341       });
11342       return result;
11343     }
11344
11345     /**
11346      * Creates a two dimensional array of an object's key-value pairs,
11347      * i.e. `[[key1, value1], [key2, value2]]`.
11348      *
11349      * @static
11350      * @memberOf _
11351      * @category Objects
11352      * @param {Object} object The object to inspect.
11353      * @returns {Array} Returns new array of key-value pairs.
11354      * @example
11355      *
11356      * _.pairs({ 'moe': 30, 'larry': 40 });
11357      * // => [['moe', 30], ['larry', 40]] (property order is not guaranteed across environments)
11358      */
11359     function pairs(object) {
11360       var index = -1,
11361           props = keys(object),
11362           length = props.length,
11363           result = Array(length);
11364
11365       while (++index < length) {
11366         var key = props[index];
11367         result[index] = [key, object[key]];
11368       }
11369       return result;
11370     }
11371
11372     /**
11373      * Creates a shallow clone of `object` composed of the specified properties.
11374      * Property names may be specified as individual arguments or as arrays of
11375      * property names. If a callback is provided it will be executed for each
11376      * property of `object` picking the properties the callback returns truey
11377      * for. The callback is bound to `thisArg` and invoked with three arguments;
11378      * (value, key, object).
11379      *
11380      * @static
11381      * @memberOf _
11382      * @category Objects
11383      * @param {Object} object The source object.
11384      * @param {Function|...string|string[]} [callback] The function called per
11385      *  iteration or property names to pick, specified as individual property
11386      *  names or arrays of property names.
11387      * @param {*} [thisArg] The `this` binding of `callback`.
11388      * @returns {Object} Returns an object composed of the picked properties.
11389      * @example
11390      *
11391      * _.pick({ 'name': 'moe', '_userid': 'moe1' }, 'name');
11392      * // => { 'name': 'moe' }
11393      *
11394      * _.pick({ 'name': 'moe', '_userid': 'moe1' }, function(value, key) {
11395      *   return key.charAt(0) != '_';
11396      * });
11397      * // => { 'name': 'moe' }
11398      */
11399     function pick(object, callback, thisArg) {
11400       var result = {};
11401       if (typeof callback != 'function') {
11402         var index = -1,
11403             props = baseFlatten(arguments, true, false, 1),
11404             length = isObject(object) ? props.length : 0;
11405
11406         while (++index < length) {
11407           var key = props[index];
11408           if (key in object) {
11409             result[key] = object[key];
11410           }
11411         }
11412       } else {
11413         callback = lodash.createCallback(callback, thisArg, 3);
11414         forIn(object, function(value, key, object) {
11415           if (callback(value, key, object)) {
11416             result[key] = value;
11417           }
11418         });
11419       }
11420       return result;
11421     }
11422
11423     /**
11424      * An alternative to `_.reduce` this method transforms `object` to a new
11425      * `accumulator` object which is the result of running each of its elements
11426      * through a callback, with each callback execution potentially mutating
11427      * the `accumulator` object. The callback is bound to `thisArg` and invoked
11428      * with four arguments; (accumulator, value, key, object). Callbacks may exit
11429      * iteration early by explicitly returning `false`.
11430      *
11431      * @static
11432      * @memberOf _
11433      * @category Objects
11434      * @param {Array|Object} collection The collection to iterate over.
11435      * @param {Function} [callback=identity] The function called per iteration.
11436      * @param {*} [accumulator] The custom accumulator value.
11437      * @param {*} [thisArg] The `this` binding of `callback`.
11438      * @returns {*} Returns the accumulated value.
11439      * @example
11440      *
11441      * var squares = _.transform([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], function(result, num) {
11442      *   num *= num;
11443      *   if (num % 2) {
11444      *     return result.push(num) < 3;
11445      *   }
11446      * });
11447      * // => [1, 9, 25]
11448      *
11449      * var mapped = _.transform({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) {
11450      *   result[key] = num * 3;
11451      * });
11452      * // => { 'a': 3, 'b': 6, 'c': 9 }
11453      */
11454     function transform(object, callback, accumulator, thisArg) {
11455       var isArr = isArray(object);
11456       callback = baseCreateCallback(callback, thisArg, 4);
11457
11458       if (accumulator == null) {
11459         if (isArr) {
11460           accumulator = [];
11461         } else {
11462           var ctor = object && object.constructor,
11463               proto = ctor && ctor.prototype;
11464
11465           accumulator = createObject(proto);
11466         }
11467       }
11468       (isArr ? forEach : forOwn)(object, function(value, index, object) {
11469         return callback(accumulator, value, index, object);
11470       });
11471       return accumulator;
11472     }
11473
11474     /**
11475      * Creates an array composed of the own enumerable property values of `object`.
11476      *
11477      * @static
11478      * @memberOf _
11479      * @category Objects
11480      * @param {Object} object The object to inspect.
11481      * @returns {Array} Returns an array of property values.
11482      * @example
11483      *
11484      * _.values({ 'one': 1, 'two': 2, 'three': 3 });
11485      * // => [1, 2, 3] (property order is not guaranteed across environments)
11486      */
11487     function values(object) {
11488       var index = -1,
11489           props = keys(object),
11490           length = props.length,
11491           result = Array(length);
11492
11493       while (++index < length) {
11494         result[index] = object[props[index]];
11495       }
11496       return result;
11497     }
11498
11499     /*--------------------------------------------------------------------------*/
11500
11501     /**
11502      * Creates an array of elements from the specified indexes, or keys, of the
11503      * `collection`. Indexes may be specified as individual arguments or as arrays
11504      * of indexes.
11505      *
11506      * @static
11507      * @memberOf _
11508      * @category Collections
11509      * @param {Array|Object|string} collection The collection to iterate over.
11510      * @param {...(number|number[]|string|string[])} [index] The indexes of `collection`
11511      *   to retrieve, specified as individual indexes or arrays of indexes.
11512      * @returns {Array} Returns a new array of elements corresponding to the
11513      *  provided indexes.
11514      * @example
11515      *
11516      * _.at(['a', 'b', 'c', 'd', 'e'], [0, 2, 4]);
11517      * // => ['a', 'c', 'e']
11518      *
11519      * _.at(['moe', 'larry', 'curly'], 0, 2);
11520      * // => ['moe', 'curly']
11521      */
11522     function at(collection) {
11523       var args = arguments,
11524           index = -1,
11525           props = baseFlatten(args, true, false, 1),
11526           length = (args[2] && args[2][args[1]] === collection) ? 1 : props.length,
11527           result = Array(length);
11528
11529       while(++index < length) {
11530         result[index] = collection[props[index]];
11531       }
11532       return result;
11533     }
11534
11535     /**
11536      * Checks if a given value is present in a collection using strict equality
11537      * for comparisons, i.e. `===`. If `fromIndex` is negative, it is used as the
11538      * offset from the end of the collection.
11539      *
11540      * @static
11541      * @memberOf _
11542      * @alias include
11543      * @category Collections
11544      * @param {Array|Object|string} collection The collection to iterate over.
11545      * @param {*} target The value to check for.
11546      * @param {number} [fromIndex=0] The index to search from.
11547      * @returns {boolean} Returns `true` if the `target` element is found, else `false`.
11548      * @example
11549      *
11550      * _.contains([1, 2, 3], 1);
11551      * // => true
11552      *
11553      * _.contains([1, 2, 3], 1, 2);
11554      * // => false
11555      *
11556      * _.contains({ 'name': 'moe', 'age': 40 }, 'moe');
11557      * // => true
11558      *
11559      * _.contains('curly', 'ur');
11560      * // => true
11561      */
11562     function contains(collection, target, fromIndex) {
11563       var index = -1,
11564           indexOf = getIndexOf(),
11565           length = collection ? collection.length : 0,
11566           result = false;
11567
11568       fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex) || 0;
11569       if (isArray(collection)) {
11570         result = indexOf(collection, target, fromIndex) > -1;
11571       } else if (typeof length == 'number') {
11572         result = (isString(collection) ? collection.indexOf(target, fromIndex) : indexOf(collection, target, fromIndex)) > -1;
11573       } else {
11574         forOwn(collection, function(value) {
11575           if (++index >= fromIndex) {
11576             return !(result = value === target);
11577           }
11578         });
11579       }
11580       return result;
11581     }
11582
11583     /**
11584      * Creates an object composed of keys generated from the results of running
11585      * each element of `collection` through the callback. The corresponding value
11586      * of each key is the number of times the key was returned by the callback.
11587      * The callback is bound to `thisArg` and invoked with three arguments;
11588      * (value, index|key, collection).
11589      *
11590      * If a property name is provided for `callback` the created "_.pluck" style
11591      * callback will return the property value of the given element.
11592      *
11593      * If an object is provided for `callback` the created "_.where" style callback
11594      * will return `true` for elements that have the properties of the given object,
11595      * else `false`.
11596      *
11597      * @static
11598      * @memberOf _
11599      * @category Collections
11600      * @param {Array|Object|string} collection The collection to iterate over.
11601      * @param {Function|Object|string} [callback=identity] The function called
11602      *  per iteration. If a property name or object is provided it will be used
11603      *  to create a "_.pluck" or "_.where" style callback, respectively.
11604      * @param {*} [thisArg] The `this` binding of `callback`.
11605      * @returns {Object} Returns the composed aggregate object.
11606      * @example
11607      *
11608      * _.countBy([4.3, 6.1, 6.4], function(num) { return Math.floor(num); });
11609      * // => { '4': 1, '6': 2 }
11610      *
11611      * _.countBy([4.3, 6.1, 6.4], function(num) { return this.floor(num); }, Math);
11612      * // => { '4': 1, '6': 2 }
11613      *
11614      * _.countBy(['one', 'two', 'three'], 'length');
11615      * // => { '3': 2, '5': 1 }
11616      */
11617     var countBy = createAggregator(function(result, value, key) {
11618       (hasOwnProperty.call(result, key) ? result[key]++ : result[key] = 1);
11619     });
11620
11621     /**
11622      * Checks if the given callback returns truey value for **all** elements of
11623      * a collection. The callback is bound to `thisArg` and invoked with three
11624      * arguments; (value, index|key, collection).
11625      *
11626      * If a property name is provided for `callback` the created "_.pluck" style
11627      * callback will return the property value of the given element.
11628      *
11629      * If an object is provided for `callback` the created "_.where" style callback
11630      * will return `true` for elements that have the properties of the given object,
11631      * else `false`.
11632      *
11633      * @static
11634      * @memberOf _
11635      * @alias all
11636      * @category Collections
11637      * @param {Array|Object|string} collection The collection to iterate over.
11638      * @param {Function|Object|string} [callback=identity] The function called
11639      *  per iteration. If a property name or object is provided it will be used
11640      *  to create a "_.pluck" or "_.where" style callback, respectively.
11641      * @param {*} [thisArg] The `this` binding of `callback`.
11642      * @returns {boolean} Returns `true` if all elements passed the callback check,
11643      *  else `false`.
11644      * @example
11645      *
11646      * _.every([true, 1, null, 'yes'], Boolean);
11647      * // => false
11648      *
11649      * var stooges = [
11650      *   { 'name': 'moe', 'age': 40 },
11651      *   { 'name': 'larry', 'age': 50 }
11652      * ];
11653      *
11654      * // using "_.pluck" callback shorthand
11655      * _.every(stooges, 'age');
11656      * // => true
11657      *
11658      * // using "_.where" callback shorthand
11659      * _.every(stooges, { 'age': 50 });
11660      * // => false
11661      */
11662     function every(collection, callback, thisArg) {
11663       var result = true;
11664       callback = lodash.createCallback(callback, thisArg, 3);
11665
11666       var index = -1,
11667           length = collection ? collection.length : 0;
11668
11669       if (typeof length == 'number') {
11670         while (++index < length) {
11671           if (!(result = !!callback(collection[index], index, collection))) {
11672             break;
11673           }
11674         }
11675       } else {
11676         forOwn(collection, function(value, index, collection) {
11677           return (result = !!callback(value, index, collection));
11678         });
11679       }
11680       return result;
11681     }
11682
11683     /**
11684      * Iterates over elements of a collection, returning an array of all elements
11685      * the callback returns truey for. The callback is bound to `thisArg` and
11686      * invoked with three arguments; (value, index|key, collection).
11687      *
11688      * If a property name is provided for `callback` the created "_.pluck" style
11689      * callback will return the property value of the given element.
11690      *
11691      * If an object is provided for `callback` the created "_.where" style callback
11692      * will return `true` for elements that have the properties of the given object,
11693      * else `false`.
11694      *
11695      * @static
11696      * @memberOf _
11697      * @alias select
11698      * @category Collections
11699      * @param {Array|Object|string} collection The collection to iterate over.
11700      * @param {Function|Object|string} [callback=identity] The function called
11701      *  per iteration. If a property name or object is provided it will be used
11702      *  to create a "_.pluck" or "_.where" style callback, respectively.
11703      * @param {*} [thisArg] The `this` binding of `callback`.
11704      * @returns {Array} Returns a new array of elements that passed the callback check.
11705      * @example
11706      *
11707      * var evens = _.filter([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
11708      * // => [2, 4, 6]
11709      *
11710      * var food = [
11711      *   { 'name': 'apple',  'organic': false, 'type': 'fruit' },
11712      *   { 'name': 'carrot', 'organic': true,  'type': 'vegetable' }
11713      * ];
11714      *
11715      * // using "_.pluck" callback shorthand
11716      * _.filter(food, 'organic');
11717      * // => [{ 'name': 'carrot', 'organic': true, 'type': 'vegetable' }]
11718      *
11719      * // using "_.where" callback shorthand
11720      * _.filter(food, { 'type': 'fruit' });
11721      * // => [{ 'name': 'apple', 'organic': false, 'type': 'fruit' }]
11722      */
11723     function filter(collection, callback, thisArg) {
11724       var result = [];
11725       callback = lodash.createCallback(callback, thisArg, 3);
11726
11727       var index = -1,
11728           length = collection ? collection.length : 0;
11729
11730       if (typeof length == 'number') {
11731         while (++index < length) {
11732           var value = collection[index];
11733           if (callback(value, index, collection)) {
11734             result.push(value);
11735           }
11736         }
11737       } else {
11738         forOwn(collection, function(value, index, collection) {
11739           if (callback(value, index, collection)) {
11740             result.push(value);
11741           }
11742         });
11743       }
11744       return result;
11745     }
11746
11747     /**
11748      * Iterates over elements of a collection, returning the first element that
11749      * the callback returns truey for. The callback is bound to `thisArg` and
11750      * invoked with three arguments; (value, index|key, collection).
11751      *
11752      * If a property name is provided for `callback` the created "_.pluck" style
11753      * callback will return the property value of the given element.
11754      *
11755      * If an object is provided for `callback` the created "_.where" style callback
11756      * will return `true` for elements that have the properties of the given object,
11757      * else `false`.
11758      *
11759      * @static
11760      * @memberOf _
11761      * @alias detect, findWhere
11762      * @category Collections
11763      * @param {Array|Object|string} collection The collection to iterate over.
11764      * @param {Function|Object|string} [callback=identity] The function called
11765      *  per iteration. If a property name or object is provided it will be used
11766      *  to create a "_.pluck" or "_.where" style callback, respectively.
11767      * @param {*} [thisArg] The `this` binding of `callback`.
11768      * @returns {*} Returns the found element, else `undefined`.
11769      * @example
11770      *
11771      * _.find([1, 2, 3, 4], function(num) {
11772      *   return num % 2 == 0;
11773      * });
11774      * // => 2
11775      *
11776      * var food = [
11777      *   { 'name': 'apple',  'organic': false, 'type': 'fruit' },
11778      *   { 'name': 'banana', 'organic': true,  'type': 'fruit' },
11779      *   { 'name': 'beet',   'organic': false, 'type': 'vegetable' }
11780      * ];
11781      *
11782      * // using "_.where" callback shorthand
11783      * _.find(food, { 'type': 'vegetable' });
11784      * // => { 'name': 'beet', 'organic': false, 'type': 'vegetable' }
11785      *
11786      * // using "_.pluck" callback shorthand
11787      * _.find(food, 'organic');
11788      * // => { 'name': 'banana', 'organic': true, 'type': 'fruit' }
11789      */
11790     function find(collection, callback, thisArg) {
11791       callback = lodash.createCallback(callback, thisArg, 3);
11792
11793       var index = -1,
11794           length = collection ? collection.length : 0;
11795
11796       if (typeof length == 'number') {
11797         while (++index < length) {
11798           var value = collection[index];
11799           if (callback(value, index, collection)) {
11800             return value;
11801           }
11802         }
11803       } else {
11804         var result;
11805         forOwn(collection, function(value, index, collection) {
11806           if (callback(value, index, collection)) {
11807             result = value;
11808             return false;
11809           }
11810         });
11811         return result;
11812       }
11813     }
11814
11815     /**
11816      * This method is like `_.find` except that it iterates over elements
11817      * of a `collection` from right to left.
11818      *
11819      * @static
11820      * @memberOf _
11821      * @category Collections
11822      * @param {Array|Object|string} collection The collection to iterate over.
11823      * @param {Function|Object|string} [callback=identity] The function called
11824      *  per iteration. If a property name or object is provided it will be used
11825      *  to create a "_.pluck" or "_.where" style callback, respectively.
11826      * @param {*} [thisArg] The `this` binding of `callback`.
11827      * @returns {*} Returns the found element, else `undefined`.
11828      * @example
11829      *
11830      * _.findLast([1, 2, 3, 4], function(num) {
11831      *   return num % 2 == 1;
11832      * });
11833      * // => 3
11834      */
11835     function findLast(collection, callback, thisArg) {
11836       var result;
11837       callback = lodash.createCallback(callback, thisArg, 3);
11838       forEachRight(collection, function(value, index, collection) {
11839         if (callback(value, index, collection)) {
11840           result = value;
11841           return false;
11842         }
11843       });
11844       return result;
11845     }
11846
11847     /**
11848      * Iterates over elements of a collection, executing the callback for each
11849      * element. The callback is bound to `thisArg` and invoked with three arguments;
11850      * (value, index|key, collection). Callbacks may exit iteration early by
11851      * explicitly returning `false`.
11852      *
11853      * @static
11854      * @memberOf _
11855      * @alias each
11856      * @category Collections
11857      * @param {Array|Object|string} collection The collection to iterate over.
11858      * @param {Function} [callback=identity] The function called per iteration.
11859      * @param {*} [thisArg] The `this` binding of `callback`.
11860      * @returns {Array|Object|string} Returns `collection`.
11861      * @example
11862      *
11863      * _([1, 2, 3]).forEach(function(num) { console.log(num); }).join(',');
11864      * // => logs each number and returns '1,2,3'
11865      *
11866      * _.forEach({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { console.log(num); });
11867      * // => logs each number and returns the object (property order is not guaranteed across environments)
11868      */
11869     function forEach(collection, callback, thisArg) {
11870       var index = -1,
11871           length = collection ? collection.length : 0;
11872
11873       callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);
11874       if (typeof length == 'number') {
11875         while (++index < length) {
11876           if (callback(collection[index], index, collection) === false) {
11877             break;
11878           }
11879         }
11880       } else {
11881         forOwn(collection, callback);
11882       }
11883       return collection;
11884     }
11885
11886     /**
11887      * This method is like `_.forEach` except that it iterates over elements
11888      * of a `collection` from right to left.
11889      *
11890      * @static
11891      * @memberOf _
11892      * @alias eachRight
11893      * @category Collections
11894      * @param {Array|Object|string} collection The collection to iterate over.
11895      * @param {Function} [callback=identity] The function called per iteration.
11896      * @param {*} [thisArg] The `this` binding of `callback`.
11897      * @returns {Array|Object|string} Returns `collection`.
11898      * @example
11899      *
11900      * _([1, 2, 3]).forEachRight(function(num) { console.log(num); }).join(',');
11901      * // => logs each number from right to left and returns '3,2,1'
11902      */
11903     function forEachRight(collection, callback, thisArg) {
11904       var length = collection ? collection.length : 0;
11905       callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);
11906       if (typeof length == 'number') {
11907         while (length--) {
11908           if (callback(collection[length], length, collection) === false) {
11909             break;
11910           }
11911         }
11912       } else {
11913         var props = keys(collection);
11914         length = props.length;
11915         forOwn(collection, function(value, key, collection) {
11916           key = props ? props[--length] : --length;
11917           return callback(collection[key], key, collection);
11918         });
11919       }
11920       return collection;
11921     }
11922
11923     /**
11924      * Creates an object composed of keys generated from the results of running
11925      * each element of a collection through the callback. The corresponding value
11926      * of each key is an array of the elements responsible for generating the key.
11927      * The callback is bound to `thisArg` and invoked with three arguments;
11928      * (value, index|key, collection).
11929      *
11930      * If a property name is provided for `callback` the created "_.pluck" style
11931      * callback will return the property value of the given element.
11932      *
11933      * If an object is provided for `callback` the created "_.where" style callback
11934      * will return `true` for elements that have the properties of the given object,
11935      * else `false`
11936      *
11937      * @static
11938      * @memberOf _
11939      * @category Collections
11940      * @param {Array|Object|string} collection The collection to iterate over.
11941      * @param {Function|Object|string} [callback=identity] The function called
11942      *  per iteration. If a property name or object is provided it will be used
11943      *  to create a "_.pluck" or "_.where" style callback, respectively.
11944      * @param {*} [thisArg] The `this` binding of `callback`.
11945      * @returns {Object} Returns the composed aggregate object.
11946      * @example
11947      *
11948      * _.groupBy([4.2, 6.1, 6.4], function(num) { return Math.floor(num); });
11949      * // => { '4': [4.2], '6': [6.1, 6.4] }
11950      *
11951      * _.groupBy([4.2, 6.1, 6.4], function(num) { return this.floor(num); }, Math);
11952      * // => { '4': [4.2], '6': [6.1, 6.4] }
11953      *
11954      * // using "_.pluck" callback shorthand
11955      * _.groupBy(['one', 'two', 'three'], 'length');
11956      * // => { '3': ['one', 'two'], '5': ['three'] }
11957      */
11958     var groupBy = createAggregator(function(result, value, key) {
11959       (hasOwnProperty.call(result, key) ? result[key] : result[key] = []).push(value);
11960     });
11961
11962     /**
11963      * Creates an object composed of keys generated from the results of running
11964      * each element of the collection through the given callback. The corresponding
11965      * value of each key is the last element responsible for generating the key.
11966      * The callback is bound to `thisArg` and invoked with three arguments;
11967      * (value, index|key, collection).
11968      *
11969      * If a property name is provided for `callback` the created "_.pluck" style
11970      * callback will return the property value of the given element.
11971      *
11972      * If an object is provided for `callback` the created "_.where" style callback
11973      * will return `true` for elements that have the properties of the given object,
11974      * else `false`.
11975      *
11976      * @static
11977      * @memberOf _
11978      * @category Collections
11979      * @param {Array|Object|string} collection The collection to iterate over.
11980      * @param {Function|Object|string} [callback=identity] The function called
11981      *  per iteration. If a property name or object is provided it will be used
11982      *  to create a "_.pluck" or "_.where" style callback, respectively.
11983      * @param {*} [thisArg] The `this` binding of `callback`.
11984      * @returns {Object} Returns the composed aggregate object.
11985      * @example
11986      *
11987      * var keys = [
11988      *   { 'dir': 'left', 'code': 97 },
11989      *   { 'dir': 'right', 'code': 100 }
11990      * ];
11991      *
11992      * _.indexBy(keys, 'dir');
11993      * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } }
11994      *
11995      * _.indexBy(keys, function(key) { return String.fromCharCode(key.code); });
11996      * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
11997      *
11998      * _.indexBy(stooges, function(key) { this.fromCharCode(key.code); }, String);
11999      * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
12000      */
12001     var indexBy = createAggregator(function(result, value, key) {
12002       result[key] = value;
12003     });
12004
12005     /**
12006      * Invokes the method named by `methodName` on each element in the `collection`
12007      * returning an array of the results of each invoked method. Additional arguments
12008      * will be provided to each invoked method. If `methodName` is a function it
12009      * will be invoked for, and `this` bound to, each element in the `collection`.
12010      *
12011      * @static
12012      * @memberOf _
12013      * @category Collections
12014      * @param {Array|Object|string} collection The collection to iterate over.
12015      * @param {Function|string} methodName The name of the method to invoke or
12016      *  the function invoked per iteration.
12017      * @param {...*} [arg] Arguments to invoke the method with.
12018      * @returns {Array} Returns a new array of the results of each invoked method.
12019      * @example
12020      *
12021      * _.invoke([[5, 1, 7], [3, 2, 1]], 'sort');
12022      * // => [[1, 5, 7], [1, 2, 3]]
12023      *
12024      * _.invoke([123, 456], String.prototype.split, '');
12025      * // => [['1', '2', '3'], ['4', '5', '6']]
12026      */
12027     function invoke(collection, methodName) {
12028       var args = nativeSlice.call(arguments, 2),
12029           index = -1,
12030           isFunc = typeof methodName == 'function',
12031           length = collection ? collection.length : 0,
12032           result = Array(typeof length == 'number' ? length : 0);
12033
12034       forEach(collection, function(value) {
12035         result[++index] = (isFunc ? methodName : value[methodName]).apply(value, args);
12036       });
12037       return result;
12038     }
12039
12040     /**
12041      * Creates an array of values by running each element in the collection
12042      * through the callback. The callback is bound to `thisArg` and invoked with
12043      * three arguments; (value, index|key, collection).
12044      *
12045      * If a property name is provided for `callback` the created "_.pluck" style
12046      * callback will return the property value of the given element.
12047      *
12048      * If an object is provided for `callback` the created "_.where" style callback
12049      * will return `true` for elements that have the properties of the given object,
12050      * else `false`.
12051      *
12052      * @static
12053      * @memberOf _
12054      * @alias collect
12055      * @category Collections
12056      * @param {Array|Object|string} collection The collection to iterate over.
12057      * @param {Function|Object|string} [callback=identity] The function called
12058      *  per iteration. If a property name or object is provided it will be used
12059      *  to create a "_.pluck" or "_.where" style callback, respectively.
12060      * @param {*} [thisArg] The `this` binding of `callback`.
12061      * @returns {Array} Returns a new array of the results of each `callback` execution.
12062      * @example
12063      *
12064      * _.map([1, 2, 3], function(num) { return num * 3; });
12065      * // => [3, 6, 9]
12066      *
12067      * _.map({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { return num * 3; });
12068      * // => [3, 6, 9] (property order is not guaranteed across environments)
12069      *
12070      * var stooges = [
12071      *   { 'name': 'moe', 'age': 40 },
12072      *   { 'name': 'larry', 'age': 50 }
12073      * ];
12074      *
12075      * // using "_.pluck" callback shorthand
12076      * _.map(stooges, 'name');
12077      * // => ['moe', 'larry']
12078      */
12079     function map(collection, callback, thisArg) {
12080       var index = -1,
12081           length = collection ? collection.length : 0;
12082
12083       callback = lodash.createCallback(callback, thisArg, 3);
12084       if (typeof length == 'number') {
12085         var result = Array(length);
12086         while (++index < length) {
12087           result[index] = callback(collection[index], index, collection);
12088         }
12089       } else {
12090         result = [];
12091         forOwn(collection, function(value, key, collection) {
12092           result[++index] = callback(value, key, collection);
12093         });
12094       }
12095       return result;
12096     }
12097
12098     /**
12099      * Retrieves the maximum value of a collection. If the collection is empty or
12100      * falsey `-Infinity` is returned. If a callback is provided it will be executed
12101      * for each value in the collection to generate the criterion by which the value
12102      * is ranked. The callback is bound to `thisArg` and invoked with three
12103      * arguments; (value, index, collection).
12104      *
12105      * If a property name is provided for `callback` the created "_.pluck" style
12106      * callback will return the property value of the given element.
12107      *
12108      * If an object is provided for `callback` the created "_.where" style callback
12109      * will return `true` for elements that have the properties of the given object,
12110      * else `false`.
12111      *
12112      * @static
12113      * @memberOf _
12114      * @category Collections
12115      * @param {Array|Object|string} collection The collection to iterate over.
12116      * @param {Function|Object|string} [callback=identity] The function called
12117      *  per iteration. If a property name or object is provided it will be used
12118      *  to create a "_.pluck" or "_.where" style callback, respectively.
12119      * @param {*} [thisArg] The `this` binding of `callback`.
12120      * @returns {*} Returns the maximum value.
12121      * @example
12122      *
12123      * _.max([4, 2, 8, 6]);
12124      * // => 8
12125      *
12126      * var stooges = [
12127      *   { 'name': 'moe', 'age': 40 },
12128      *   { 'name': 'larry', 'age': 50 }
12129      * ];
12130      *
12131      * _.max(stooges, function(stooge) { return stooge.age; });
12132      * // => { 'name': 'larry', 'age': 50 };
12133      *
12134      * // using "_.pluck" callback shorthand
12135      * _.max(stooges, 'age');
12136      * // => { 'name': 'larry', 'age': 50 };
12137      */
12138     function max(collection, callback, thisArg) {
12139       var computed = -Infinity,
12140           result = computed;
12141
12142       if (!callback && isArray(collection)) {
12143         var index = -1,
12144             length = collection.length;
12145
12146         while (++index < length) {
12147           var value = collection[index];
12148           if (value > result) {
12149             result = value;
12150           }
12151         }
12152       } else {
12153         callback = (!callback && isString(collection))
12154           ? charAtCallback
12155           : lodash.createCallback(callback, thisArg, 3);
12156
12157         forEach(collection, function(value, index, collection) {
12158           var current = callback(value, index, collection);
12159           if (current > computed) {
12160             computed = current;
12161             result = value;
12162           }
12163         });
12164       }
12165       return result;
12166     }
12167
12168     /**
12169      * Retrieves the minimum value of a collection. If the collection is empty or
12170      * falsey `Infinity` is returned. If a callback is provided it will be executed
12171      * for each value in the collection to generate the criterion by which the value
12172      * is ranked. The callback is bound to `thisArg` and invoked with three
12173      * arguments; (value, index, collection).
12174      *
12175      * If a property name is provided for `callback` the created "_.pluck" style
12176      * callback will return the property value of the given element.
12177      *
12178      * If an object is provided for `callback` the created "_.where" style callback
12179      * will return `true` for elements that have the properties of the given object,
12180      * else `false`.
12181      *
12182      * @static
12183      * @memberOf _
12184      * @category Collections
12185      * @param {Array|Object|string} collection The collection to iterate over.
12186      * @param {Function|Object|string} [callback=identity] The function called
12187      *  per iteration. If a property name or object is provided it will be used
12188      *  to create a "_.pluck" or "_.where" style callback, respectively.
12189      * @param {*} [thisArg] The `this` binding of `callback`.
12190      * @returns {*} Returns the minimum value.
12191      * @example
12192      *
12193      * _.min([4, 2, 8, 6]);
12194      * // => 2
12195      *
12196      * var stooges = [
12197      *   { 'name': 'moe', 'age': 40 },
12198      *   { 'name': 'larry', 'age': 50 }
12199      * ];
12200      *
12201      * _.min(stooges, function(stooge) { return stooge.age; });
12202      * // => { 'name': 'moe', 'age': 40 };
12203      *
12204      * // using "_.pluck" callback shorthand
12205      * _.min(stooges, 'age');
12206      * // => { 'name': 'moe', 'age': 40 };
12207      */
12208     function min(collection, callback, thisArg) {
12209       var computed = Infinity,
12210           result = computed;
12211
12212       if (!callback && isArray(collection)) {
12213         var index = -1,
12214             length = collection.length;
12215
12216         while (++index < length) {
12217           var value = collection[index];
12218           if (value < result) {
12219             result = value;
12220           }
12221         }
12222       } else {
12223         callback = (!callback && isString(collection))
12224           ? charAtCallback
12225           : lodash.createCallback(callback, thisArg, 3);
12226
12227         forEach(collection, function(value, index, collection) {
12228           var current = callback(value, index, collection);
12229           if (current < computed) {
12230             computed = current;
12231             result = value;
12232           }
12233         });
12234       }
12235       return result;
12236     }
12237
12238     /**
12239      * Retrieves the value of a specified property from all elements in the `collection`.
12240      *
12241      * @static
12242      * @memberOf _
12243      * @type Function
12244      * @category Collections
12245      * @param {Array|Object|string} collection The collection to iterate over.
12246      * @param {string} property The property to pluck.
12247      * @returns {Array} Returns a new array of property values.
12248      * @example
12249      *
12250      * var stooges = [
12251      *   { 'name': 'moe', 'age': 40 },
12252      *   { 'name': 'larry', 'age': 50 }
12253      * ];
12254      *
12255      * _.pluck(stooges, 'name');
12256      * // => ['moe', 'larry']
12257      */
12258     function pluck(collection, property) {
12259       var index = -1,
12260           length = collection ? collection.length : 0;
12261
12262       if (typeof length == 'number') {
12263         var result = Array(length);
12264         while (++index < length) {
12265           result[index] = collection[index][property];
12266         }
12267       }
12268       return result || map(collection, property);
12269     }
12270
12271     /**
12272      * Reduces a collection to a value which is the accumulated result of running
12273      * each element in the collection through the callback, where each successive
12274      * callback execution consumes the return value of the previous execution. If
12275      * `accumulator` is not provided the first element of the collection will be
12276      * used as the initial `accumulator` value. The callback is bound to `thisArg`
12277      * and invoked with four arguments; (accumulator, value, index|key, collection).
12278      *
12279      * @static
12280      * @memberOf _
12281      * @alias foldl, inject
12282      * @category Collections
12283      * @param {Array|Object|string} collection The collection to iterate over.
12284      * @param {Function} [callback=identity] The function called per iteration.
12285      * @param {*} [accumulator] Initial value of the accumulator.
12286      * @param {*} [thisArg] The `this` binding of `callback`.
12287      * @returns {*} Returns the accumulated value.
12288      * @example
12289      *
12290      * var sum = _.reduce([1, 2, 3], function(sum, num) {
12291      *   return sum + num;
12292      * });
12293      * // => 6
12294      *
12295      * var mapped = _.reduce({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) {
12296      *   result[key] = num * 3;
12297      *   return result;
12298      * }, {});
12299      * // => { 'a': 3, 'b': 6, 'c': 9 }
12300      */
12301     function reduce(collection, callback, accumulator, thisArg) {
12302       if (!collection) return accumulator;
12303       var noaccum = arguments.length < 3;
12304       callback = baseCreateCallback(callback, thisArg, 4);
12305
12306       var index = -1,
12307           length = collection.length;
12308
12309       if (typeof length == 'number') {
12310         if (noaccum) {
12311           accumulator = collection[++index];
12312         }
12313         while (++index < length) {
12314           accumulator = callback(accumulator, collection[index], index, collection);
12315         }
12316       } else {
12317         forOwn(collection, function(value, index, collection) {
12318           accumulator = noaccum
12319             ? (noaccum = false, value)
12320             : callback(accumulator, value, index, collection)
12321         });
12322       }
12323       return accumulator;
12324     }
12325
12326     /**
12327      * This method is like `_.reduce` except that it iterates over elements
12328      * of a `collection` from right to left.
12329      *
12330      * @static
12331      * @memberOf _
12332      * @alias foldr
12333      * @category Collections
12334      * @param {Array|Object|string} collection The collection to iterate over.
12335      * @param {Function} [callback=identity] The function called per iteration.
12336      * @param {*} [accumulator] Initial value of the accumulator.
12337      * @param {*} [thisArg] The `this` binding of `callback`.
12338      * @returns {*} Returns the accumulated value.
12339      * @example
12340      *
12341      * var list = [[0, 1], [2, 3], [4, 5]];
12342      * var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []);
12343      * // => [4, 5, 2, 3, 0, 1]
12344      */
12345     function reduceRight(collection, callback, accumulator, thisArg) {
12346       var noaccum = arguments.length < 3;
12347       callback = baseCreateCallback(callback, thisArg, 4);
12348       forEachRight(collection, function(value, index, collection) {
12349         accumulator = noaccum
12350           ? (noaccum = false, value)
12351           : callback(accumulator, value, index, collection);
12352       });
12353       return accumulator;
12354     }
12355
12356     /**
12357      * The opposite of `_.filter` this method returns the elements of a
12358      * collection that the callback does **not** return truey for.
12359      *
12360      * If a property name is provided for `callback` the created "_.pluck" style
12361      * callback will return the property value of the given element.
12362      *
12363      * If an object is provided for `callback` the created "_.where" style callback
12364      * will return `true` for elements that have the properties of the given object,
12365      * else `false`.
12366      *
12367      * @static
12368      * @memberOf _
12369      * @category Collections
12370      * @param {Array|Object|string} collection The collection to iterate over.
12371      * @param {Function|Object|string} [callback=identity] The function called
12372      *  per iteration. If a property name or object is provided it will be used
12373      *  to create a "_.pluck" or "_.where" style callback, respectively.
12374      * @param {*} [thisArg] The `this` binding of `callback`.
12375      * @returns {Array} Returns a new array of elements that failed the callback check.
12376      * @example
12377      *
12378      * var odds = _.reject([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
12379      * // => [1, 3, 5]
12380      *
12381      * var food = [
12382      *   { 'name': 'apple',  'organic': false, 'type': 'fruit' },
12383      *   { 'name': 'carrot', 'organic': true,  'type': 'vegetable' }
12384      * ];
12385      *
12386      * // using "_.pluck" callback shorthand
12387      * _.reject(food, 'organic');
12388      * // => [{ 'name': 'apple', 'organic': false, 'type': 'fruit' }]
12389      *
12390      * // using "_.where" callback shorthand
12391      * _.reject(food, { 'type': 'fruit' });
12392      * // => [{ 'name': 'carrot', 'organic': true, 'type': 'vegetable' }]
12393      */
12394     function reject(collection, callback, thisArg) {
12395       callback = lodash.createCallback(callback, thisArg, 3);
12396       return filter(collection, function(value, index, collection) {
12397         return !callback(value, index, collection);
12398       });
12399     }
12400
12401     /**
12402      * Retrieves a random element or `n` random elements from a collection.
12403      *
12404      * @static
12405      * @memberOf _
12406      * @category Collections
12407      * @param {Array|Object|string} collection The collection to sample.
12408      * @param {number} [n] The number of elements to sample.
12409      * @param- {Object} [guard] Allows working with functions, like `_.map`,
12410      *  without using their `key` and `object` arguments as sources.
12411      * @returns {Array} Returns the random sample(s) of `collection`.
12412      * @example
12413      *
12414      * _.sample([1, 2, 3, 4]);
12415      * // => 2
12416      *
12417      * _.sample([1, 2, 3, 4], 2);
12418      * // => [3, 1]
12419      */
12420     function sample(collection, n, guard) {
12421       var length = collection ? collection.length : 0;
12422       if (typeof length != 'number') {
12423         collection = values(collection);
12424       }
12425       if (n == null || guard) {
12426         return collection ? collection[random(length - 1)] : undefined;
12427       }
12428       var result = shuffle(collection);
12429       result.length = nativeMin(nativeMax(0, n), result.length);
12430       return result;
12431     }
12432
12433     /**
12434      * Creates an array of shuffled values, using a version of the Fisher-Yates
12435      * shuffle. See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle.
12436      *
12437      * @static
12438      * @memberOf _
12439      * @category Collections
12440      * @param {Array|Object|string} collection The collection to shuffle.
12441      * @returns {Array} Returns a new shuffled collection.
12442      * @example
12443      *
12444      * _.shuffle([1, 2, 3, 4, 5, 6]);
12445      * // => [4, 1, 6, 3, 5, 2]
12446      */
12447     function shuffle(collection) {
12448       var index = -1,
12449           length = collection ? collection.length : 0,
12450           result = Array(typeof length == 'number' ? length : 0);
12451
12452       forEach(collection, function(value) {
12453         var rand = random(++index);
12454         result[index] = result[rand];
12455         result[rand] = value;
12456       });
12457       return result;
12458     }
12459
12460     /**
12461      * Gets the size of the `collection` by returning `collection.length` for arrays
12462      * and array-like objects or the number of own enumerable properties for objects.
12463      *
12464      * @static
12465      * @memberOf _
12466      * @category Collections
12467      * @param {Array|Object|string} collection The collection to inspect.
12468      * @returns {number} Returns `collection.length` or number of own enumerable properties.
12469      * @example
12470      *
12471      * _.size([1, 2]);
12472      * // => 2
12473      *
12474      * _.size({ 'one': 1, 'two': 2, 'three': 3 });
12475      * // => 3
12476      *
12477      * _.size('curly');
12478      * // => 5
12479      */
12480     function size(collection) {
12481       var length = collection ? collection.length : 0;
12482       return typeof length == 'number' ? length : keys(collection).length;
12483     }
12484
12485     /**
12486      * Checks if the callback returns a truey value for **any** element of a
12487      * collection. The function returns as soon as it finds a passing value and
12488      * does not iterate over the entire collection. The callback is bound to
12489      * `thisArg` and invoked with three arguments; (value, index|key, collection).
12490      *
12491      * If a property name is provided for `callback` the created "_.pluck" style
12492      * callback will return the property value of the given element.
12493      *
12494      * If an object is provided for `callback` the created "_.where" style callback
12495      * will return `true` for elements that have the properties of the given object,
12496      * else `false`.
12497      *
12498      * @static
12499      * @memberOf _
12500      * @alias any
12501      * @category Collections
12502      * @param {Array|Object|string} collection The collection to iterate over.
12503      * @param {Function|Object|string} [callback=identity] The function called
12504      *  per iteration. If a property name or object is provided it will be used
12505      *  to create a "_.pluck" or "_.where" style callback, respectively.
12506      * @param {*} [thisArg] The `this` binding of `callback`.
12507      * @returns {boolean} Returns `true` if any element passed the callback check,
12508      *  else `false`.
12509      * @example
12510      *
12511      * _.some([null, 0, 'yes', false], Boolean);
12512      * // => true
12513      *
12514      * var food = [
12515      *   { 'name': 'apple',  'organic': false, 'type': 'fruit' },
12516      *   { 'name': 'carrot', 'organic': true,  'type': 'vegetable' }
12517      * ];
12518      *
12519      * // using "_.pluck" callback shorthand
12520      * _.some(food, 'organic');
12521      * // => true
12522      *
12523      * // using "_.where" callback shorthand
12524      * _.some(food, { 'type': 'meat' });
12525      * // => false
12526      */
12527     function some(collection, callback, thisArg) {
12528       var result;
12529       callback = lodash.createCallback(callback, thisArg, 3);
12530
12531       var index = -1,
12532           length = collection ? collection.length : 0;
12533
12534       if (typeof length == 'number') {
12535         while (++index < length) {
12536           if ((result = callback(collection[index], index, collection))) {
12537             break;
12538           }
12539         }
12540       } else {
12541         forOwn(collection, function(value, index, collection) {
12542           return !(result = callback(value, index, collection));
12543         });
12544       }
12545       return !!result;
12546     }
12547
12548     /**
12549      * Creates an array of elements, sorted in ascending order by the results of
12550      * running each element in a collection through the callback. This method
12551      * performs a stable sort, that is, it will preserve the original sort order
12552      * of equal elements. The callback is bound to `thisArg` and invoked with
12553      * three arguments; (value, index|key, collection).
12554      *
12555      * If a property name is provided for `callback` the created "_.pluck" style
12556      * callback will return the property value of the given element.
12557      *
12558      * If an object is provided for `callback` the created "_.where" style callback
12559      * will return `true` for elements that have the properties of the given object,
12560      * else `false`.
12561      *
12562      * @static
12563      * @memberOf _
12564      * @category Collections
12565      * @param {Array|Object|string} collection The collection to iterate over.
12566      * @param {Function|Object|string} [callback=identity] The function called
12567      *  per iteration. If a property name or object is provided it will be used
12568      *  to create a "_.pluck" or "_.where" style callback, respectively.
12569      * @param {*} [thisArg] The `this` binding of `callback`.
12570      * @returns {Array} Returns a new array of sorted elements.
12571      * @example
12572      *
12573      * _.sortBy([1, 2, 3], function(num) { return Math.sin(num); });
12574      * // => [3, 1, 2]
12575      *
12576      * _.sortBy([1, 2, 3], function(num) { return this.sin(num); }, Math);
12577      * // => [3, 1, 2]
12578      *
12579      * // using "_.pluck" callback shorthand
12580      * _.sortBy(['banana', 'strawberry', 'apple'], 'length');
12581      * // => ['apple', 'banana', 'strawberry']
12582      */
12583     function sortBy(collection, callback, thisArg) {
12584       var index = -1,
12585           length = collection ? collection.length : 0,
12586           result = Array(typeof length == 'number' ? length : 0);
12587
12588       callback = lodash.createCallback(callback, thisArg, 3);
12589       forEach(collection, function(value, key, collection) {
12590         var object = result[++index] = getObject();
12591         object.criteria = callback(value, key, collection);
12592         object.index = index;
12593         object.value = value;
12594       });
12595
12596       length = result.length;
12597       result.sort(compareAscending);
12598       while (length--) {
12599         var object = result[length];
12600         result[length] = object.value;
12601         releaseObject(object);
12602       }
12603       return result;
12604     }
12605
12606     /**
12607      * Converts the `collection` to an array.
12608      *
12609      * @static
12610      * @memberOf _
12611      * @category Collections
12612      * @param {Array|Object|string} collection The collection to convert.
12613      * @returns {Array} Returns the new converted array.
12614      * @example
12615      *
12616      * (function() { return _.toArray(arguments).slice(1); })(1, 2, 3, 4);
12617      * // => [2, 3, 4]
12618      */
12619     function toArray(collection) {
12620       if (collection && typeof collection.length == 'number') {
12621         return slice(collection);
12622       }
12623       return values(collection);
12624     }
12625
12626     /**
12627      * Performs a deep comparison of each element in a `collection` to the given
12628      * `properties` object, returning an array of all elements that have equivalent
12629      * property values.
12630      *
12631      * @static
12632      * @memberOf _
12633      * @type Function
12634      * @category Collections
12635      * @param {Array|Object|string} collection The collection to iterate over.
12636      * @param {Object} properties The object of property values to filter by.
12637      * @returns {Array} Returns a new array of elements that have the given properties.
12638      * @example
12639      *
12640      * var stooges = [
12641      *   { 'name': 'curly', 'age': 30, 'quotes': ['Oh, a wise guy, eh?', 'Poifect!'] },
12642      *   { 'name': 'moe', 'age': 40, 'quotes': ['Spread out!', 'You knucklehead!'] }
12643      * ];
12644      *
12645      * _.where(stooges, { 'age': 40 });
12646      * // => [{ 'name': 'moe', 'age': 40, 'quotes': ['Spread out!', 'You knucklehead!'] }]
12647      *
12648      * _.where(stooges, { 'quotes': ['Poifect!'] });
12649      * // => [{ 'name': 'curly', 'age': 30, 'quotes': ['Oh, a wise guy, eh?', 'Poifect!'] }]
12650      */
12651     var where = filter;
12652
12653     /*--------------------------------------------------------------------------*/
12654
12655     /**
12656      * Creates an array with all falsey values removed. The values `false`, `null`,
12657      * `0`, `""`, `undefined`, and `NaN` are all falsey.
12658      *
12659      * @static
12660      * @memberOf _
12661      * @category Arrays
12662      * @param {Array} array The array to compact.
12663      * @returns {Array} Returns a new array of filtered values.
12664      * @example
12665      *
12666      * _.compact([0, 1, false, 2, '', 3]);
12667      * // => [1, 2, 3]
12668      */
12669     function compact(array) {
12670       var index = -1,
12671           length = array ? array.length : 0,
12672           result = [];
12673
12674       while (++index < length) {
12675         var value = array[index];
12676         if (value) {
12677           result.push(value);
12678         }
12679       }
12680       return result;
12681     }
12682
12683     /**
12684      * Creates an array excluding all values of the provided arrays using strict
12685      * equality for comparisons, i.e. `===`.
12686      *
12687      * @static
12688      * @memberOf _
12689      * @category Arrays
12690      * @param {Array} array The array to process.
12691      * @param {...Array} [array] The arrays of values to exclude.
12692      * @returns {Array} Returns a new array of filtered values.
12693      * @example
12694      *
12695      * _.difference([1, 2, 3, 4, 5], [5, 2, 10]);
12696      * // => [1, 3, 4]
12697      */
12698     function difference(array) {
12699       var index = -1,
12700           indexOf = getIndexOf(),
12701           length = array ? array.length : 0,
12702           seen = baseFlatten(arguments, true, true, 1),
12703           result = [];
12704
12705       var isLarge = length >= largeArraySize && indexOf === baseIndexOf;
12706
12707       if (isLarge) {
12708         var cache = createCache(seen);
12709         if (cache) {
12710           indexOf = cacheIndexOf;
12711           seen = cache;
12712         } else {
12713           isLarge = false;
12714         }
12715       }
12716       while (++index < length) {
12717         var value = array[index];
12718         if (indexOf(seen, value) < 0) {
12719           result.push(value);
12720         }
12721       }
12722       if (isLarge) {
12723         releaseObject(seen);
12724       }
12725       return result;
12726     }
12727
12728     /**
12729      * This method is like `_.find` except that it returns the index of the first
12730      * element that passes the callback check, instead of the element itself.
12731      *
12732      * @static
12733      * @memberOf _
12734      * @category Arrays
12735      * @param {Array} array The array to search.
12736      * @param {Function|Object|string} [callback=identity] The function called
12737      *  per iteration. If a property name or object is provided it will be used
12738      *  to create a "_.pluck" or "_.where" style callback, respectively.
12739      * @param {*} [thisArg] The `this` binding of `callback`.
12740      * @returns {number} Returns the index of the found element, else `-1`.
12741      * @example
12742      *
12743      * _.findIndex(['apple', 'banana', 'beet'], function(food) {
12744      *   return /^b/.test(food);
12745      * });
12746      * // => 1
12747      */
12748     function findIndex(array, callback, thisArg) {
12749       var index = -1,
12750           length = array ? array.length : 0;
12751
12752       callback = lodash.createCallback(callback, thisArg, 3);
12753       while (++index < length) {
12754         if (callback(array[index], index, array)) {
12755           return index;
12756         }
12757       }
12758       return -1;
12759     }
12760
12761     /**
12762      * This method is like `_.findIndex` except that it iterates over elements
12763      * of a `collection` from right to left.
12764      *
12765      * @static
12766      * @memberOf _
12767      * @category Arrays
12768      * @param {Array} array The array to search.
12769      * @param {Function|Object|string} [callback=identity] The function called
12770      *  per iteration. If a property name or object is provided it will be used
12771      *  to create a "_.pluck" or "_.where" style callback, respectively.
12772      * @param {*} [thisArg] The `this` binding of `callback`.
12773      * @returns {number} Returns the index of the found element, else `-1`.
12774      * @example
12775      *
12776      * _.findLastIndex(['apple', 'banana', 'beet'], function(food) {
12777      *   return /^b/.test(food);
12778      * });
12779      * // => 2
12780      */
12781     function findLastIndex(array, callback, thisArg) {
12782       var length = array ? array.length : 0;
12783       callback = lodash.createCallback(callback, thisArg, 3);
12784       while (length--) {
12785         if (callback(array[length], length, array)) {
12786           return length;
12787         }
12788       }
12789       return -1;
12790     }
12791
12792     /**
12793      * Gets the first element or first `n` elements of an array. If a callback
12794      * is provided elements at the beginning of the array are returned as long
12795      * as the callback returns truey. The callback is bound to `thisArg` and
12796      * invoked with three arguments; (value, index, array).
12797      *
12798      * If a property name is provided for `callback` the created "_.pluck" style
12799      * callback will return the property value of the given element.
12800      *
12801      * If an object is provided for `callback` the created "_.where" style callback
12802      * will return `true` for elements that have the properties of the given object,
12803      * else `false`.
12804      *
12805      * @static
12806      * @memberOf _
12807      * @alias head, take
12808      * @category Arrays
12809      * @param {Array} array The array to query.
12810      * @param {Function|Object|number|string} [callback] The function called
12811      *  per element or the number of elements to return. If a property name or
12812      *  object is provided it will be used to create a "_.pluck" or "_.where"
12813      *  style callback, respectively.
12814      * @param {*} [thisArg] The `this` binding of `callback`.
12815      * @returns {*} Returns the first element(s) of `array`.
12816      * @example
12817      *
12818      * _.first([1, 2, 3]);
12819      * // => 1
12820      *
12821      * _.first([1, 2, 3], 2);
12822      * // => [1, 2]
12823      *
12824      * _.first([1, 2, 3], function(num) {
12825      *   return num < 3;
12826      * });
12827      * // => [1, 2]
12828      *
12829      * var food = [
12830      *   { 'name': 'banana', 'organic': true },
12831      *   { 'name': 'beet',   'organic': false },
12832      * ];
12833      *
12834      * // using "_.pluck" callback shorthand
12835      * _.first(food, 'organic');
12836      * // => [{ 'name': 'banana', 'organic': true }]
12837      *
12838      * var food = [
12839      *   { 'name': 'apple',  'type': 'fruit' },
12840      *   { 'name': 'banana', 'type': 'fruit' },
12841      *   { 'name': 'beet',   'type': 'vegetable' }
12842      * ];
12843      *
12844      * // using "_.where" callback shorthand
12845      * _.first(food, { 'type': 'fruit' });
12846      * // => [{ 'name': 'apple', 'type': 'fruit' }, { 'name': 'banana', 'type': 'fruit' }]
12847      */
12848     function first(array, callback, thisArg) {
12849       var n = 0,
12850           length = array ? array.length : 0;
12851
12852       if (typeof callback != 'number' && callback != null) {
12853         var index = -1;
12854         callback = lodash.createCallback(callback, thisArg, 3);
12855         while (++index < length && callback(array[index], index, array)) {
12856           n++;
12857         }
12858       } else {
12859         n = callback;
12860         if (n == null || thisArg) {
12861           return array ? array[0] : undefined;
12862         }
12863       }
12864       return slice(array, 0, nativeMin(nativeMax(0, n), length));
12865     }
12866
12867     /**
12868      * Flattens a nested array (the nesting can be to any depth). If `isShallow`
12869      * is truey, the array will only be flattened a single level. If a callback
12870      * is provided each element of the array is passed through the callback before
12871      * flattening. The callback is bound to `thisArg` and invoked with three
12872      * arguments; (value, index, array).
12873      *
12874      * If a property name is provided for `callback` the created "_.pluck" style
12875      * callback will return the property value of the given element.
12876      *
12877      * If an object is provided for `callback` the created "_.where" style callback
12878      * will return `true` for elements that have the properties of the given object,
12879      * else `false`.
12880      *
12881      * @static
12882      * @memberOf _
12883      * @category Arrays
12884      * @param {Array} array The array to flatten.
12885      * @param {boolean} [isShallow=false] A flag to restrict flattening to a single level.
12886      * @param {Function|Object|string} [callback=identity] The function called
12887      *  per iteration. If a property name or object is provided it will be used
12888      *  to create a "_.pluck" or "_.where" style callback, respectively.
12889      * @param {*} [thisArg] The `this` binding of `callback`.
12890      * @returns {Array} Returns a new flattened array.
12891      * @example
12892      *
12893      * _.flatten([1, [2], [3, [[4]]]]);
12894      * // => [1, 2, 3, 4];
12895      *
12896      * _.flatten([1, [2], [3, [[4]]]], true);
12897      * // => [1, 2, 3, [[4]]];
12898      *
12899      * var stooges = [
12900      *   { 'name': 'curly', 'quotes': ['Oh, a wise guy, eh?', 'Poifect!'] },
12901      *   { 'name': 'moe', 'quotes': ['Spread out!', 'You knucklehead!'] }
12902      * ];
12903      *
12904      * // using "_.pluck" callback shorthand
12905      * _.flatten(stooges, 'quotes');
12906      * // => ['Oh, a wise guy, eh?', 'Poifect!', 'Spread out!', 'You knucklehead!']
12907      */
12908     function flatten(array, isShallow, callback, thisArg) {
12909       // juggle arguments
12910       if (typeof isShallow != 'boolean' && isShallow != null) {
12911         thisArg = callback;
12912         callback = !(thisArg && thisArg[isShallow] === array) ? isShallow : null;
12913         isShallow = false;
12914       }
12915       if (callback != null) {
12916         array = map(array, callback, thisArg);
12917       }
12918       return baseFlatten(array, isShallow);
12919     }
12920
12921     /**
12922      * Gets the index at which the first occurrence of `value` is found using
12923      * strict equality for comparisons, i.e. `===`. If the array is already sorted
12924      * providing `true` for `fromIndex` will run a faster binary search.
12925      *
12926      * @static
12927      * @memberOf _
12928      * @category Arrays
12929      * @param {Array} array The array to search.
12930      * @param {*} value The value to search for.
12931      * @param {boolean|number} [fromIndex=0] The index to search from or `true`
12932      *  to perform a binary search on a sorted array.
12933      * @returns {number} Returns the index of the matched value or `-1`.
12934      * @example
12935      *
12936      * _.indexOf([1, 2, 3, 1, 2, 3], 2);
12937      * // => 1
12938      *
12939      * _.indexOf([1, 2, 3, 1, 2, 3], 2, 3);
12940      * // => 4
12941      *
12942      * _.indexOf([1, 1, 2, 2, 3, 3], 2, true);
12943      * // => 2
12944      */
12945     function indexOf(array, value, fromIndex) {
12946       if (typeof fromIndex == 'number') {
12947         var length = array ? array.length : 0;
12948         fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex || 0);
12949       } else if (fromIndex) {
12950         var index = sortedIndex(array, value);
12951         return array[index] === value ? index : -1;
12952       }
12953       return baseIndexOf(array, value, fromIndex);
12954     }
12955
12956     /**
12957      * Gets all but the last element or last `n` elements of an array. If a
12958      * callback is provided elements at the end of the array are excluded from
12959      * the result as long as the callback returns truey. The callback is bound
12960      * to `thisArg` and invoked with three arguments; (value, index, array).
12961      *
12962      * If a property name is provided for `callback` the created "_.pluck" style
12963      * callback will return the property value of the given element.
12964      *
12965      * If an object is provided for `callback` the created "_.where" style callback
12966      * will return `true` for elements that have the properties of the given object,
12967      * else `false`.
12968      *
12969      * @static
12970      * @memberOf _
12971      * @category Arrays
12972      * @param {Array} array The array to query.
12973      * @param {Function|Object|number|string} [callback=1] The function called
12974      *  per element or the number of elements to exclude. If a property name or
12975      *  object is provided it will be used to create a "_.pluck" or "_.where"
12976      *  style callback, respectively.
12977      * @param {*} [thisArg] The `this` binding of `callback`.
12978      * @returns {Array} Returns a slice of `array`.
12979      * @example
12980      *
12981      * _.initial([1, 2, 3]);
12982      * // => [1, 2]
12983      *
12984      * _.initial([1, 2, 3], 2);
12985      * // => [1]
12986      *
12987      * _.initial([1, 2, 3], function(num) {
12988      *   return num > 1;
12989      * });
12990      * // => [1]
12991      *
12992      * var food = [
12993      *   { 'name': 'beet',   'organic': false },
12994      *   { 'name': 'carrot', 'organic': true }
12995      * ];
12996      *
12997      * // using "_.pluck" callback shorthand
12998      * _.initial(food, 'organic');
12999      * // => [{ 'name': 'beet',   'organic': false }]
13000      *
13001      * var food = [
13002      *   { 'name': 'banana', 'type': 'fruit' },
13003      *   { 'name': 'beet',   'type': 'vegetable' },
13004      *   { 'name': 'carrot', 'type': 'vegetable' }
13005      * ];
13006      *
13007      * // using "_.where" callback shorthand
13008      * _.initial(food, { 'type': 'vegetable' });
13009      * // => [{ 'name': 'banana', 'type': 'fruit' }]
13010      */
13011     function initial(array, callback, thisArg) {
13012       var n = 0,
13013           length = array ? array.length : 0;
13014
13015       if (typeof callback != 'number' && callback != null) {
13016         var index = length;
13017         callback = lodash.createCallback(callback, thisArg, 3);
13018         while (index-- && callback(array[index], index, array)) {
13019           n++;
13020         }
13021       } else {
13022         n = (callback == null || thisArg) ? 1 : callback || n;
13023       }
13024       return slice(array, 0, nativeMin(nativeMax(0, length - n), length));
13025     }
13026
13027     /**
13028      * Creates an array of unique values present in all provided arrays using
13029      * strict equality for comparisons, i.e. `===`.
13030      *
13031      * @static
13032      * @memberOf _
13033      * @category Arrays
13034      * @param {...Array} [array] The arrays to inspect.
13035      * @returns {Array} Returns an array of composite values.
13036      * @example
13037      *
13038      * _.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]);
13039      * // => [1, 2]
13040      */
13041     function intersection(array) {
13042       var args = arguments,
13043           argsLength = args.length,
13044           argsIndex = -1,
13045           caches = getArray(),
13046           index = -1,
13047           indexOf = getIndexOf(),
13048           length = array ? array.length : 0,
13049           result = [],
13050           seen = getArray();
13051
13052       while (++argsIndex < argsLength) {
13053         var value = args[argsIndex];
13054         caches[argsIndex] = indexOf === baseIndexOf &&
13055           (value ? value.length : 0) >= largeArraySize &&
13056           createCache(argsIndex ? args[argsIndex] : seen);
13057       }
13058       outer:
13059       while (++index < length) {
13060         var cache = caches[0];
13061         value = array[index];
13062
13063         if ((cache ? cacheIndexOf(cache, value) : indexOf(seen, value)) < 0) {
13064           argsIndex = argsLength;
13065           (cache || seen).push(value);
13066           while (--argsIndex) {
13067             cache = caches[argsIndex];
13068             if ((cache ? cacheIndexOf(cache, value) : indexOf(args[argsIndex], value)) < 0) {
13069               continue outer;
13070             }
13071           }
13072           result.push(value);
13073         }
13074       }
13075       while (argsLength--) {
13076         cache = caches[argsLength];
13077         if (cache) {
13078           releaseObject(cache);
13079         }
13080       }
13081       releaseArray(caches);
13082       releaseArray(seen);
13083       return result;
13084     }
13085
13086     /**
13087      * Gets the last element or last `n` elements of an array. If a callback is
13088      * provided elements at the end of the array are returned as long as the
13089      * callback returns truey. The callback is bound to `thisArg` and invoked
13090      * with three arguments; (value, index, array).
13091      *
13092      * If a property name is provided for `callback` the created "_.pluck" style
13093      * callback will return the property value of the given element.
13094      *
13095      * If an object is provided for `callback` the created "_.where" style callback
13096      * will return `true` for elements that have the properties of the given object,
13097      * else `false`.
13098      *
13099      * @static
13100      * @memberOf _
13101      * @category Arrays
13102      * @param {Array} array The array to query.
13103      * @param {Function|Object|number|string} [callback] The function called
13104      *  per element or the number of elements to return. If a property name or
13105      *  object is provided it will be used to create a "_.pluck" or "_.where"
13106      *  style callback, respectively.
13107      * @param {*} [thisArg] The `this` binding of `callback`.
13108      * @returns {*} Returns the last element(s) of `array`.
13109      * @example
13110      *
13111      * _.last([1, 2, 3]);
13112      * // => 3
13113      *
13114      * _.last([1, 2, 3], 2);
13115      * // => [2, 3]
13116      *
13117      * _.last([1, 2, 3], function(num) {
13118      *   return num > 1;
13119      * });
13120      * // => [2, 3]
13121      *
13122      * var food = [
13123      *   { 'name': 'beet',   'organic': false },
13124      *   { 'name': 'carrot', 'organic': true }
13125      * ];
13126      *
13127      * // using "_.pluck" callback shorthand
13128      * _.last(food, 'organic');
13129      * // => [{ 'name': 'carrot', 'organic': true }]
13130      *
13131      * var food = [
13132      *   { 'name': 'banana', 'type': 'fruit' },
13133      *   { 'name': 'beet',   'type': 'vegetable' },
13134      *   { 'name': 'carrot', 'type': 'vegetable' }
13135      * ];
13136      *
13137      * // using "_.where" callback shorthand
13138      * _.last(food, { 'type': 'vegetable' });
13139      * // => [{ 'name': 'beet', 'type': 'vegetable' }, { 'name': 'carrot', 'type': 'vegetable' }]
13140      */
13141     function last(array, callback, thisArg) {
13142       var n = 0,
13143           length = array ? array.length : 0;
13144
13145       if (typeof callback != 'number' && callback != null) {
13146         var index = length;
13147         callback = lodash.createCallback(callback, thisArg, 3);
13148         while (index-- && callback(array[index], index, array)) {
13149           n++;
13150         }
13151       } else {
13152         n = callback;
13153         if (n == null || thisArg) {
13154           return array ? array[length - 1] : undefined;
13155         }
13156       }
13157       return slice(array, nativeMax(0, length - n));
13158     }
13159
13160     /**
13161      * Gets the index at which the last occurrence of `value` is found using strict
13162      * equality for comparisons, i.e. `===`. If `fromIndex` is negative, it is used
13163      * as the offset from the end of the collection.
13164      *
13165      * @static
13166      * @memberOf _
13167      * @category Arrays
13168      * @param {Array} array The array to search.
13169      * @param {*} value The value to search for.
13170      * @param {number} [fromIndex=array.length-1] The index to search from.
13171      * @returns {number} Returns the index of the matched value or `-1`.
13172      * @example
13173      *
13174      * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2);
13175      * // => 4
13176      *
13177      * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2, 3);
13178      * // => 1
13179      */
13180     function lastIndexOf(array, value, fromIndex) {
13181       var index = array ? array.length : 0;
13182       if (typeof fromIndex == 'number') {
13183         index = (fromIndex < 0 ? nativeMax(0, index + fromIndex) : nativeMin(fromIndex, index - 1)) + 1;
13184       }
13185       while (index--) {
13186         if (array[index] === value) {
13187           return index;
13188         }
13189       }
13190       return -1;
13191     }
13192
13193     /**
13194      * Removes all provided values from the given array using strict equality for
13195      * comparisons, i.e. `===`.
13196      *
13197      * @static
13198      * @memberOf _
13199      * @category Arrays
13200      * @param {Array} array The array to modify.
13201      * @param {...*} [value] The values to remove.
13202      * @returns {Array} Returns `array`.
13203      * @example
13204      *
13205      * var array = [1, 2, 3, 1, 2, 3];
13206      * _.pull(array, 2, 3);
13207      * console.log(array);
13208      * // => [1, 1]
13209      */
13210     function pull(array) {
13211       var args = arguments,
13212           argsIndex = 0,
13213           argsLength = args.length,
13214           length = array ? array.length : 0;
13215
13216       while (++argsIndex < argsLength) {
13217         var index = -1,
13218             value = args[argsIndex];
13219         while (++index < length) {
13220           if (array[index] === value) {
13221             splice.call(array, index--, 1);
13222             length--;
13223           }
13224         }
13225       }
13226       return array;
13227     }
13228
13229     /**
13230      * Creates an array of numbers (positive and/or negative) progressing from
13231      * `start` up to but not including `end`. If `start` is less than `stop` a
13232      * zero-length range is created unless a negative `step` is specified.
13233      *
13234      * @static
13235      * @memberOf _
13236      * @category Arrays
13237      * @param {number} [start=0] The start of the range.
13238      * @param {number} end The end of the range.
13239      * @param {number} [step=1] The value to increment or decrement by.
13240      * @returns {Array} Returns a new range array.
13241      * @example
13242      *
13243      * _.range(10);
13244      * // => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
13245      *
13246      * _.range(1, 11);
13247      * // => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
13248      *
13249      * _.range(0, 30, 5);
13250      * // => [0, 5, 10, 15, 20, 25]
13251      *
13252      * _.range(0, -10, -1);
13253      * // => [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
13254      *
13255      * _.range(1, 4, 0);
13256      * // => [1, 1, 1]
13257      *
13258      * _.range(0);
13259      * // => []
13260      */
13261     function range(start, end, step) {
13262       start = +start || 0;
13263       step = typeof step == 'number' ? step : (+step || 1);
13264
13265       if (end == null) {
13266         end = start;
13267         start = 0;
13268       }
13269       // use `Array(length)` so engines, like Chakra and V8, avoid slower modes
13270       // http://youtu.be/XAqIpGU8ZZk#t=17m25s
13271       var index = -1,
13272           length = nativeMax(0, ceil((end - start) / (step || 1))),
13273           result = Array(length);
13274
13275       while (++index < length) {
13276         result[index] = start;
13277         start += step;
13278       }
13279       return result;
13280     }
13281
13282     /**
13283      * Removes all elements from an array that the callback returns truey for
13284      * and returns an array of removed elements. The callback is bound to `thisArg`
13285      * and invoked with three arguments; (value, index, array).
13286      *
13287      * If a property name is provided for `callback` the created "_.pluck" style
13288      * callback will return the property value of the given element.
13289      *
13290      * If an object is provided for `callback` the created "_.where" style callback
13291      * will return `true` for elements that have the properties of the given object,
13292      * else `false`.
13293      *
13294      * @static
13295      * @memberOf _
13296      * @category Arrays
13297      * @param {Array} array The array to modify.
13298      * @param {Function|Object|string} [callback=identity] The function called
13299      *  per iteration. If a property name or object is provided it will be used
13300      *  to create a "_.pluck" or "_.where" style callback, respectively.
13301      * @param {*} [thisArg] The `this` binding of `callback`.
13302      * @returns {Array} Returns a new array of removed elements.
13303      * @example
13304      *
13305      * var array = [1, 2, 3, 4, 5, 6];
13306      * var evens = _.remove(array, function(num) { return num % 2 == 0; });
13307      *
13308      * console.log(array);
13309      * // => [1, 3, 5]
13310      *
13311      * console.log(evens);
13312      * // => [2, 4, 6]
13313      */
13314     function remove(array, callback, thisArg) {
13315       var index = -1,
13316           length = array ? array.length : 0,
13317           result = [];
13318
13319       callback = lodash.createCallback(callback, thisArg, 3);
13320       while (++index < length) {
13321         var value = array[index];
13322         if (callback(value, index, array)) {
13323           result.push(value);
13324           splice.call(array, index--, 1);
13325           length--;
13326         }
13327       }
13328       return result;
13329     }
13330
13331     /**
13332      * The opposite of `_.initial` this method gets all but the first element or
13333      * first `n` elements of an array. If a callback function is provided elements
13334      * at the beginning of the array are excluded from the result as long as the
13335      * callback returns truey. The callback is bound to `thisArg` and invoked
13336      * with three arguments; (value, index, array).
13337      *
13338      * If a property name is provided for `callback` the created "_.pluck" style
13339      * callback will return the property value of the given element.
13340      *
13341      * If an object is provided for `callback` the created "_.where" style callback
13342      * will return `true` for elements that have the properties of the given object,
13343      * else `false`.
13344      *
13345      * @static
13346      * @memberOf _
13347      * @alias drop, tail
13348      * @category Arrays
13349      * @param {Array} array The array to query.
13350      * @param {Function|Object|number|string} [callback=1] The function called
13351      *  per element or the number of elements to exclude. If a property name or
13352      *  object is provided it will be used to create a "_.pluck" or "_.where"
13353      *  style callback, respectively.
13354      * @param {*} [thisArg] The `this` binding of `callback`.
13355      * @returns {Array} Returns a slice of `array`.
13356      * @example
13357      *
13358      * _.rest([1, 2, 3]);
13359      * // => [2, 3]
13360      *
13361      * _.rest([1, 2, 3], 2);
13362      * // => [3]
13363      *
13364      * _.rest([1, 2, 3], function(num) {
13365      *   return num < 3;
13366      * });
13367      * // => [3]
13368      *
13369      * var food = [
13370      *   { 'name': 'banana', 'organic': true },
13371      *   { 'name': 'beet',   'organic': false },
13372      * ];
13373      *
13374      * // using "_.pluck" callback shorthand
13375      * _.rest(food, 'organic');
13376      * // => [{ 'name': 'beet', 'organic': false }]
13377      *
13378      * var food = [
13379      *   { 'name': 'apple',  'type': 'fruit' },
13380      *   { 'name': 'banana', 'type': 'fruit' },
13381      *   { 'name': 'beet',   'type': 'vegetable' }
13382      * ];
13383      *
13384      * // using "_.where" callback shorthand
13385      * _.rest(food, { 'type': 'fruit' });
13386      * // => [{ 'name': 'beet', 'type': 'vegetable' }]
13387      */
13388     function rest(array, callback, thisArg) {
13389       if (typeof callback != 'number' && callback != null) {
13390         var n = 0,
13391             index = -1,
13392             length = array ? array.length : 0;
13393
13394         callback = lodash.createCallback(callback, thisArg, 3);
13395         while (++index < length && callback(array[index], index, array)) {
13396           n++;
13397         }
13398       } else {
13399         n = (callback == null || thisArg) ? 1 : nativeMax(0, callback);
13400       }
13401       return slice(array, n);
13402     }
13403
13404     /**
13405      * Uses a binary search to determine the smallest index at which a value
13406      * should be inserted into a given sorted array in order to maintain the sort
13407      * order of the array. If a callback is provided it will be executed for
13408      * `value` and each element of `array` to compute their sort ranking. The
13409      * callback is bound to `thisArg` and invoked with one argument; (value).
13410      *
13411      * If a property name is provided for `callback` the created "_.pluck" style
13412      * callback will return the property value of the given element.
13413      *
13414      * If an object is provided for `callback` the created "_.where" style callback
13415      * will return `true` for elements that have the properties of the given object,
13416      * else `false`.
13417      *
13418      * @static
13419      * @memberOf _
13420      * @category Arrays
13421      * @param {Array} array The array to inspect.
13422      * @param {*} value The value to evaluate.
13423      * @param {Function|Object|string} [callback=identity] The function called
13424      *  per iteration. If a property name or object is provided it will be used
13425      *  to create a "_.pluck" or "_.where" style callback, respectively.
13426      * @param {*} [thisArg] The `this` binding of `callback`.
13427      * @returns {number} Returns the index at which `value` should be inserted
13428      *  into `array`.
13429      * @example
13430      *
13431      * _.sortedIndex([20, 30, 50], 40);
13432      * // => 2
13433      *
13434      * // using "_.pluck" callback shorthand
13435      * _.sortedIndex([{ 'x': 20 }, { 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x');
13436      * // => 2
13437      *
13438      * var dict = {
13439      *   'wordToNumber': { 'twenty': 20, 'thirty': 30, 'fourty': 40, 'fifty': 50 }
13440      * };
13441      *
13442      * _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) {
13443      *   return dict.wordToNumber[word];
13444      * });
13445      * // => 2
13446      *
13447      * _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) {
13448      *   return this.wordToNumber[word];
13449      * }, dict);
13450      * // => 2
13451      */
13452     function sortedIndex(array, value, callback, thisArg) {
13453       var low = 0,
13454           high = array ? array.length : low;
13455
13456       // explicitly reference `identity` for better inlining in Firefox
13457       callback = callback ? lodash.createCallback(callback, thisArg, 1) : identity;
13458       value = callback(value);
13459
13460       while (low < high) {
13461         var mid = (low + high) >>> 1;
13462         (callback(array[mid]) < value)
13463           ? low = mid + 1
13464           : high = mid;
13465       }
13466       return low;
13467     }
13468
13469     /**
13470      * Creates an array of unique values, in order, of the provided arrays using
13471      * strict equality for comparisons, i.e. `===`.
13472      *
13473      * @static
13474      * @memberOf _
13475      * @category Arrays
13476      * @param {...Array} [array] The arrays to inspect.
13477      * @returns {Array} Returns an array of composite values.
13478      * @example
13479      *
13480      * _.union([1, 2, 3], [101, 2, 1, 10], [2, 1]);
13481      * // => [1, 2, 3, 101, 10]
13482      */
13483     function union(array) {
13484       return baseUniq(baseFlatten(arguments, true, true));
13485     }
13486
13487     /**
13488      * Creates a duplicate-value-free version of an array using strict equality
13489      * for comparisons, i.e. `===`. If the array is sorted, providing
13490      * `true` for `isSorted` will use a faster algorithm. If a callback is provided
13491      * each element of `array` is passed through the callback before uniqueness
13492      * is computed. The callback is bound to `thisArg` and invoked with three
13493      * arguments; (value, index, array).
13494      *
13495      * If a property name is provided for `callback` the created "_.pluck" style
13496      * callback will return the property value of the given element.
13497      *
13498      * If an object is provided for `callback` the created "_.where" style callback
13499      * will return `true` for elements that have the properties of the given object,
13500      * else `false`.
13501      *
13502      * @static
13503      * @memberOf _
13504      * @alias unique
13505      * @category Arrays
13506      * @param {Array} array The array to process.
13507      * @param {boolean} [isSorted=false] A flag to indicate that `array` is sorted.
13508      * @param {Function|Object|string} [callback=identity] The function called
13509      *  per iteration. If a property name or object is provided it will be used
13510      *  to create a "_.pluck" or "_.where" style callback, respectively.
13511      * @param {*} [thisArg] The `this` binding of `callback`.
13512      * @returns {Array} Returns a duplicate-value-free array.
13513      * @example
13514      *
13515      * _.uniq([1, 2, 1, 3, 1]);
13516      * // => [1, 2, 3]
13517      *
13518      * _.uniq([1, 1, 2, 2, 3], true);
13519      * // => [1, 2, 3]
13520      *
13521      * _.uniq(['A', 'b', 'C', 'a', 'B', 'c'], function(letter) { return letter.toLowerCase(); });
13522      * // => ['A', 'b', 'C']
13523      *
13524      * _.uniq([1, 2.5, 3, 1.5, 2, 3.5], function(num) { return this.floor(num); }, Math);
13525      * // => [1, 2.5, 3]
13526      *
13527      * // using "_.pluck" callback shorthand
13528      * _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
13529      * // => [{ 'x': 1 }, { 'x': 2 }]
13530      */
13531     function uniq(array, isSorted, callback, thisArg) {
13532       // juggle arguments
13533       if (typeof isSorted != 'boolean' && isSorted != null) {
13534         thisArg = callback;
13535         callback = !(thisArg && thisArg[isSorted] === array) ? isSorted : null;
13536         isSorted = false;
13537       }
13538       if (callback != null) {
13539         callback = lodash.createCallback(callback, thisArg, 3);
13540       }
13541       return baseUniq(array, isSorted, callback);
13542     }
13543
13544     /**
13545      * Creates an array excluding all provided values using strict equality for
13546      * comparisons, i.e. `===`.
13547      *
13548      * @static
13549      * @memberOf _
13550      * @category Arrays
13551      * @param {Array} array The array to filter.
13552      * @param {...*} [value] The values to exclude.
13553      * @returns {Array} Returns a new array of filtered values.
13554      * @example
13555      *
13556      * _.without([1, 2, 1, 0, 3, 1, 4], 0, 1);
13557      * // => [2, 3, 4]
13558      */
13559     function without(array) {
13560       return difference(array, nativeSlice.call(arguments, 1));
13561     }
13562
13563     /**
13564      * Creates an array of grouped elements, the first of which contains the first
13565      * elements of the given arrays, the second of which contains the second
13566      * elements of the given arrays, and so on.
13567      *
13568      * @static
13569      * @memberOf _
13570      * @alias unzip
13571      * @category Arrays
13572      * @param {...Array} [array] Arrays to process.
13573      * @returns {Array} Returns a new array of grouped elements.
13574      * @example
13575      *
13576      * _.zip(['moe', 'larry'], [30, 40], [true, false]);
13577      * // => [['moe', 30, true], ['larry', 40, false]]
13578      */
13579     function zip() {
13580       var array = arguments.length > 1 ? arguments : arguments[0],
13581           index = -1,
13582           length = array ? max(pluck(array, 'length')) : 0,
13583           result = Array(length < 0 ? 0 : length);
13584
13585       while (++index < length) {
13586         result[index] = pluck(array, index);
13587       }
13588       return result;
13589     }
13590
13591     /**
13592      * Creates an object composed from arrays of `keys` and `values`. Provide
13593      * either a single two dimensional array, i.e. `[[key1, value1], [key2, value2]]`
13594      * or two arrays, one of `keys` and one of corresponding `values`.
13595      *
13596      * @static
13597      * @memberOf _
13598      * @alias object
13599      * @category Arrays
13600      * @param {Array} keys The array of keys.
13601      * @param {Array} [values=[]] The array of values.
13602      * @returns {Object} Returns an object composed of the given keys and
13603      *  corresponding values.
13604      * @example
13605      *
13606      * _.zipObject(['moe', 'larry'], [30, 40]);
13607      * // => { 'moe': 30, 'larry': 40 }
13608      */
13609     function zipObject(keys, values) {
13610       var index = -1,
13611           length = keys ? keys.length : 0,
13612           result = {};
13613
13614       while (++index < length) {
13615         var key = keys[index];
13616         if (values) {
13617           result[key] = values[index];
13618         } else if (key) {
13619           result[key[0]] = key[1];
13620         }
13621       }
13622       return result;
13623     }
13624
13625     /*--------------------------------------------------------------------------*/
13626
13627     /**
13628      * Creates a function that executes `func`, with  the `this` binding and
13629      * arguments of the created function, only after being called `n` times.
13630      *
13631      * @static
13632      * @memberOf _
13633      * @category Functions
13634      * @param {number} n The number of times the function must be called before
13635      *  `func` is executed.
13636      * @param {Function} func The function to restrict.
13637      * @returns {Function} Returns the new restricted function.
13638      * @example
13639      *
13640      * var saves = ['profile', 'settings'];
13641      *
13642      * var done = _.after(saves.length, function() {
13643      *   console.log('Done saving!');
13644      * });
13645      *
13646      * _.forEach(saves, function(type) {
13647      *   asyncSave({ 'type': type, 'complete': done });
13648      * });
13649      * // => logs 'Done saving!', after all saves have completed
13650      */
13651     function after(n, func) {
13652       if (!isFunction(func)) {
13653         throw new TypeError;
13654       }
13655       return function() {
13656         if (--n < 1) {
13657           return func.apply(this, arguments);
13658         }
13659       };
13660     }
13661
13662     /**
13663      * Creates a function that, when called, invokes `func` with the `this`
13664      * binding of `thisArg` and prepends any additional `bind` arguments to those
13665      * provided to the bound function.
13666      *
13667      * @static
13668      * @memberOf _
13669      * @category Functions
13670      * @param {Function} func The function to bind.
13671      * @param {*} [thisArg] The `this` binding of `func`.
13672      * @param {...*} [arg] Arguments to be partially applied.
13673      * @returns {Function} Returns the new bound function.
13674      * @example
13675      *
13676      * var func = function(greeting) {
13677      *   return greeting + ' ' + this.name;
13678      * };
13679      *
13680      * func = _.bind(func, { 'name': 'moe' }, 'hi');
13681      * func();
13682      * // => 'hi moe'
13683      */
13684     function bind(func, thisArg) {
13685       return arguments.length > 2
13686         ? createBound(func, 17, nativeSlice.call(arguments, 2), null, thisArg)
13687         : createBound(func, 1, null, null, thisArg);
13688     }
13689
13690     /**
13691      * Binds methods of an object to the object itself, overwriting the existing
13692      * method. Method names may be specified as individual arguments or as arrays
13693      * of method names. If no method names are provided all the function properties
13694      * of `object` will be bound.
13695      *
13696      * @static
13697      * @memberOf _
13698      * @category Functions
13699      * @param {Object} object The object to bind and assign the bound methods to.
13700      * @param {...string} [methodName] The object method names to
13701      *  bind, specified as individual method names or arrays of method names.
13702      * @returns {Object} Returns `object`.
13703      * @example
13704      *
13705      * var view = {
13706      *  'label': 'docs',
13707      *  'onClick': function() { console.log('clicked ' + this.label); }
13708      * };
13709      *
13710      * _.bindAll(view);
13711      * jQuery('#docs').on('click', view.onClick);
13712      * // => logs 'clicked docs', when the button is clicked
13713      */
13714     function bindAll(object) {
13715       var funcs = arguments.length > 1 ? baseFlatten(arguments, true, false, 1) : functions(object),
13716           index = -1,
13717           length = funcs.length;
13718
13719       while (++index < length) {
13720         var key = funcs[index];
13721         object[key] = createBound(object[key], 1, null, null, object);
13722       }
13723       return object;
13724     }
13725
13726     /**
13727      * Creates a function that, when called, invokes the method at `object[key]`
13728      * and prepends any additional `bindKey` arguments to those provided to the bound
13729      * function. This method differs from `_.bind` by allowing bound functions to
13730      * reference methods that will be redefined or don't yet exist.
13731      * See http://michaux.ca/articles/lazy-function-definition-pattern.
13732      *
13733      * @static
13734      * @memberOf _
13735      * @category Functions
13736      * @param {Object} object The object the method belongs to.
13737      * @param {string} key The key of the method.
13738      * @param {...*} [arg] Arguments to be partially applied.
13739      * @returns {Function} Returns the new bound function.
13740      * @example
13741      *
13742      * var object = {
13743      *   'name': 'moe',
13744      *   'greet': function(greeting) {
13745      *     return greeting + ' ' + this.name;
13746      *   }
13747      * };
13748      *
13749      * var func = _.bindKey(object, 'greet', 'hi');
13750      * func();
13751      * // => 'hi moe'
13752      *
13753      * object.greet = function(greeting) {
13754      *   return greeting + ', ' + this.name + '!';
13755      * };
13756      *
13757      * func();
13758      * // => 'hi, moe!'
13759      */
13760     function bindKey(object, key) {
13761       return arguments.length > 2
13762         ? createBound(key, 19, nativeSlice.call(arguments, 2), null, object)
13763         : createBound(key, 3, null, null, object);
13764     }
13765
13766     /**
13767      * Creates a function that is the composition of the provided functions,
13768      * where each function consumes the return value of the function that follows.
13769      * For example, composing the functions `f()`, `g()`, and `h()` produces `f(g(h()))`.
13770      * Each function is executed with the `this` binding of the composed function.
13771      *
13772      * @static
13773      * @memberOf _
13774      * @category Functions
13775      * @param {...Function} [func] Functions to compose.
13776      * @returns {Function} Returns the new composed function.
13777      * @example
13778      *
13779      * var realNameMap = {
13780      *   'curly': 'jerome'
13781      * };
13782      *
13783      * var format = function(name) {
13784      *   name = realNameMap[name.toLowerCase()] || name;
13785      *   return name.charAt(0).toUpperCase() + name.slice(1).toLowerCase();
13786      * };
13787      *
13788      * var greet = function(formatted) {
13789      *   return 'Hiya ' + formatted + '!';
13790      * };
13791      *
13792      * var welcome = _.compose(greet, format);
13793      * welcome('curly');
13794      * // => 'Hiya Jerome!'
13795      */
13796     function compose() {
13797       var funcs = arguments,
13798           length = funcs.length;
13799
13800       while (length--) {
13801         if (!isFunction(funcs[length])) {
13802           throw new TypeError;
13803         }
13804       }
13805       return function() {
13806         var args = arguments,
13807             length = funcs.length;
13808
13809         while (length--) {
13810           args = [funcs[length].apply(this, args)];
13811         }
13812         return args[0];
13813       };
13814     }
13815
13816     /**
13817      * Produces a callback bound to an optional `thisArg`. If `func` is a property
13818      * name the created callback will return the property value for a given element.
13819      * If `func` is an object the created callback will return `true` for elements
13820      * that contain the equivalent object properties, otherwise it will return `false`.
13821      *
13822      * @static
13823      * @memberOf _
13824      * @category Functions
13825      * @param {*} [func=identity] The value to convert to a callback.
13826      * @param {*} [thisArg] The `this` binding of the created callback.
13827      * @param {number} [argCount] The number of arguments the callback accepts.
13828      * @returns {Function} Returns a callback function.
13829      * @example
13830      *
13831      * var stooges = [
13832      *   { 'name': 'moe', 'age': 40 },
13833      *   { 'name': 'larry', 'age': 50 }
13834      * ];
13835      *
13836      * // wrap to create custom callback shorthands
13837      * _.createCallback = _.wrap(_.createCallback, function(func, callback, thisArg) {
13838      *   var match = /^(.+?)__([gl]t)(.+)$/.exec(callback);
13839      *   return !match ? func(callback, thisArg) : function(object) {
13840      *     return match[2] == 'gt' ? object[match[1]] > match[3] : object[match[1]] < match[3];
13841      *   };
13842      * });
13843      *
13844      * _.filter(stooges, 'age__gt45');
13845      * // => [{ 'name': 'larry', 'age': 50 }]
13846      */
13847     function createCallback(func, thisArg, argCount) {
13848       var type = typeof func;
13849       if (func == null || type == 'function') {
13850         return baseCreateCallback(func, thisArg, argCount);
13851       }
13852       // handle "_.pluck" style callback shorthands
13853       if (type != 'object') {
13854         return function(object) {
13855           return object[func];
13856         };
13857       }
13858       var props = keys(func),
13859           key = props[0],
13860           a = func[key];
13861
13862       // handle "_.where" style callback shorthands
13863       if (props.length == 1 && a === a && !isObject(a)) {
13864         // fast path the common case of providing an object with a single
13865         // property containing a primitive value
13866         return function(object) {
13867           var b = object[key];
13868           return a === b && (a !== 0 || (1 / a == 1 / b));
13869         };
13870       }
13871       return function(object) {
13872         var length = props.length,
13873             result = false;
13874
13875         while (length--) {
13876           if (!(result = baseIsEqual(object[props[length]], func[props[length]], null, true))) {
13877             break;
13878           }
13879         }
13880         return result;
13881       };
13882     }
13883
13884     /**
13885      * Creates a function which accepts one or more arguments of `func` that when
13886      * invoked either executes `func` returning its result, if all `func` arguments
13887      * have been provided, or returns a function that accepts one or more of the
13888      * remaining `func` arguments, and so on. The arity of `func` can be specified
13889      * if `func.length` is not sufficient.
13890      *
13891      * @static
13892      * @memberOf _
13893      * @category Functions
13894      * @param {Function} func The function to curry.
13895      * @param {number} [arity=func.length] The arity of `func`.
13896      * @returns {Function} Returns the new curried function.
13897      * @example
13898      *
13899      * var curried = _.curry(function(a, b, c) {
13900      *   console.log(a + b + c);
13901      * });
13902      *
13903      * curried(1)(2)(3);
13904      * // => 6
13905      *
13906      * curried(1, 2)(3);
13907      * // => 6
13908      *
13909      * curried(1, 2, 3);
13910      * // => 6
13911      */
13912     function curry(func, arity) {
13913       arity = typeof arity == 'number' ? arity : (+arity || func.length);
13914       return createBound(func, 4, null, null, null, arity);
13915     }
13916
13917     /**
13918      * Creates a function that will delay the execution of `func` until after
13919      * `wait` milliseconds have elapsed since the last time it was invoked.
13920      * Provide an options object to indicate that `func` should be invoked on
13921      * the leading and/or trailing edge of the `wait` timeout. Subsequent calls
13922      * to the debounced function will return the result of the last `func` call.
13923      *
13924      * Note: If `leading` and `trailing` options are `true` `func` will be called
13925      * on the trailing edge of the timeout only if the the debounced function is
13926      * invoked more than once during the `wait` timeout.
13927      *
13928      * @static
13929      * @memberOf _
13930      * @category Functions
13931      * @param {Function} func The function to debounce.
13932      * @param {number} wait The number of milliseconds to delay.
13933      * @param {Object} [options] The options object.
13934      * @param {boolean} [options.leading=false] Specify execution on the leading edge of the timeout.
13935      * @param {number} [options.maxWait] The maximum time `func` is allowed to be delayed before it's called.
13936      * @param {boolean} [options.trailing=true] Specify execution on the trailing edge of the timeout.
13937      * @returns {Function} Returns the new debounced function.
13938      * @example
13939      *
13940      * // avoid costly calculations while the window size is in flux
13941      * var lazyLayout = _.debounce(calculateLayout, 150);
13942      * jQuery(window).on('resize', lazyLayout);
13943      *
13944      * // execute `sendMail` when the click event is fired, debouncing subsequent calls
13945      * jQuery('#postbox').on('click', _.debounce(sendMail, 300, {
13946      *   'leading': true,
13947      *   'trailing': false
13948      * });
13949      *
13950      * // ensure `batchLog` is executed once after 1 second of debounced calls
13951      * var source = new EventSource('/stream');
13952      * source.addEventListener('message', _.debounce(batchLog, 250, {
13953      *   'maxWait': 1000
13954      * }, false);
13955      */
13956     function debounce(func, wait, options) {
13957       var args,
13958           maxTimeoutId,
13959           result,
13960           stamp,
13961           thisArg,
13962           timeoutId,
13963           trailingCall,
13964           lastCalled = 0,
13965           maxWait = false,
13966           trailing = true;
13967
13968       if (!isFunction(func)) {
13969         throw new TypeError;
13970       }
13971       wait = nativeMax(0, wait) || 0;
13972       if (options === true) {
13973         var leading = true;
13974         trailing = false;
13975       } else if (isObject(options)) {
13976         leading = options.leading;
13977         maxWait = 'maxWait' in options && (nativeMax(wait, options.maxWait) || 0);
13978         trailing = 'trailing' in options ? options.trailing : trailing;
13979       }
13980       var delayed = function() {
13981         var remaining = wait - (now() - stamp);
13982         if (remaining <= 0) {
13983           if (maxTimeoutId) {
13984             clearTimeout(maxTimeoutId);
13985           }
13986           var isCalled = trailingCall;
13987           maxTimeoutId = timeoutId = trailingCall = undefined;
13988           if (isCalled) {
13989             lastCalled = now();
13990             result = func.apply(thisArg, args);
13991           }
13992         } else {
13993           timeoutId = setTimeout(delayed, remaining);
13994         }
13995       };
13996
13997       var maxDelayed = function() {
13998         if (timeoutId) {
13999           clearTimeout(timeoutId);
14000         }
14001         maxTimeoutId = timeoutId = trailingCall = undefined;
14002         if (trailing || (maxWait !== wait)) {
14003           lastCalled = now();
14004           result = func.apply(thisArg, args);
14005         }
14006       };
14007
14008       return function() {
14009         args = arguments;
14010         stamp = now();
14011         thisArg = this;
14012         trailingCall = trailing && (timeoutId || !leading);
14013
14014         if (maxWait === false) {
14015           var leadingCall = leading && !timeoutId;
14016         } else {
14017           if (!maxTimeoutId && !leading) {
14018             lastCalled = stamp;
14019           }
14020           var remaining = maxWait - (stamp - lastCalled);
14021           if (remaining <= 0) {
14022             if (maxTimeoutId) {
14023               maxTimeoutId = clearTimeout(maxTimeoutId);
14024             }
14025             lastCalled = stamp;
14026             result = func.apply(thisArg, args);
14027           }
14028           else if (!maxTimeoutId) {
14029             maxTimeoutId = setTimeout(maxDelayed, remaining);
14030           }
14031         }
14032         if (!timeoutId && wait !== maxWait) {
14033           timeoutId = setTimeout(delayed, wait);
14034         }
14035         if (leadingCall) {
14036           result = func.apply(thisArg, args);
14037         }
14038         return result;
14039       };
14040     }
14041
14042     /**
14043      * Defers executing the `func` function until the current call stack has cleared.
14044      * Additional arguments will be provided to `func` when it is invoked.
14045      *
14046      * @static
14047      * @memberOf _
14048      * @category Functions
14049      * @param {Function} func The function to defer.
14050      * @param {...*} [arg] Arguments to invoke the function with.
14051      * @returns {number} Returns the timer id.
14052      * @example
14053      *
14054      * _.defer(function() { console.log('deferred'); });
14055      * // returns from the function before 'deferred' is logged
14056      */
14057     function defer(func) {
14058       if (!isFunction(func)) {
14059         throw new TypeError;
14060       }
14061       var args = nativeSlice.call(arguments, 1);
14062       return setTimeout(function() { func.apply(undefined, args); }, 1);
14063     }
14064     // use `setImmediate` if available in Node.js
14065     if (isV8 && moduleExports && typeof setImmediate == 'function') {
14066       defer = function(func) {
14067         if (!isFunction(func)) {
14068           throw new TypeError;
14069         }
14070         return setImmediate.apply(context, arguments);
14071       };
14072     }
14073
14074     /**
14075      * Executes the `func` function after `wait` milliseconds. Additional arguments
14076      * will be provided to `func` when it is invoked.
14077      *
14078      * @static
14079      * @memberOf _
14080      * @category Functions
14081      * @param {Function} func The function to delay.
14082      * @param {number} wait The number of milliseconds to delay execution.
14083      * @param {...*} [arg] Arguments to invoke the function with.
14084      * @returns {number} Returns the timer id.
14085      * @example
14086      *
14087      * var log = _.bind(console.log, console);
14088      * _.delay(log, 1000, 'logged later');
14089      * // => 'logged later' (Appears after one second.)
14090      */
14091     function delay(func, wait) {
14092       if (!isFunction(func)) {
14093         throw new TypeError;
14094       }
14095       var args = nativeSlice.call(arguments, 2);
14096       return setTimeout(function() { func.apply(undefined, args); }, wait);
14097     }
14098
14099     /**
14100      * Creates a function that memoizes the result of `func`. If `resolver` is
14101      * provided it will be used to determine the cache key for storing the result
14102      * based on the arguments provided to the memoized function. By default, the
14103      * first argument provided to the memoized function is used as the cache key.
14104      * The `func` is executed with the `this` binding of the memoized function.
14105      * The result cache is exposed as the `cache` property on the memoized function.
14106      *
14107      * @static
14108      * @memberOf _
14109      * @category Functions
14110      * @param {Function} func The function to have its output memoized.
14111      * @param {Function} [resolver] A function used to resolve the cache key.
14112      * @returns {Function} Returns the new memoizing function.
14113      * @example
14114      *
14115      * var fibonacci = _.memoize(function(n) {
14116      *   return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
14117      * });
14118      *
14119      * var data = {
14120      *   'moe': { 'name': 'moe', 'age': 40 },
14121      *   'curly': { 'name': 'curly', 'age': 60 }
14122      * };
14123      *
14124      * // modifying the result cache
14125      * var stooge = _.memoize(function(name) { return data[name]; }, _.identity);
14126      * stooge('curly');
14127      * // => { 'name': 'curly', 'age': 60 }
14128      *
14129      * stooge.cache.curly.name = 'jerome';
14130      * stooge('curly');
14131      * // => { 'name': 'jerome', 'age': 60 }
14132      */
14133     function memoize(func, resolver) {
14134       if (!isFunction(func)) {
14135         throw new TypeError;
14136       }
14137       var memoized = function() {
14138         var cache = memoized.cache,
14139             key = resolver ? resolver.apply(this, arguments) : keyPrefix + arguments[0];
14140
14141         return hasOwnProperty.call(cache, key)
14142           ? cache[key]
14143           : (cache[key] = func.apply(this, arguments));
14144       }
14145       memoized.cache = {};
14146       return memoized;
14147     }
14148
14149     /**
14150      * Creates a function that is restricted to execute `func` once. Repeat calls to
14151      * the function will return the value of the first call. The `func` is executed
14152      * with the `this` binding of the created function.
14153      *
14154      * @static
14155      * @memberOf _
14156      * @category Functions
14157      * @param {Function} func The function to restrict.
14158      * @returns {Function} Returns the new restricted function.
14159      * @example
14160      *
14161      * var initialize = _.once(createApplication);
14162      * initialize();
14163      * initialize();
14164      * // `initialize` executes `createApplication` once
14165      */
14166     function once(func) {
14167       var ran,
14168           result;
14169
14170       if (!isFunction(func)) {
14171         throw new TypeError;
14172       }
14173       return function() {
14174         if (ran) {
14175           return result;
14176         }
14177         ran = true;
14178         result = func.apply(this, arguments);
14179
14180         // clear the `func` variable so the function may be garbage collected
14181         func = null;
14182         return result;
14183       };
14184     }
14185
14186     /**
14187      * Creates a function that, when called, invokes `func` with any additional
14188      * `partial` arguments prepended to those provided to the new function. This
14189      * method is similar to `_.bind` except it does **not** alter the `this` binding.
14190      *
14191      * @static
14192      * @memberOf _
14193      * @category Functions
14194      * @param {Function} func The function to partially apply arguments to.
14195      * @param {...*} [arg] Arguments to be partially applied.
14196      * @returns {Function} Returns the new partially applied function.
14197      * @example
14198      *
14199      * var greet = function(greeting, name) { return greeting + ' ' + name; };
14200      * var hi = _.partial(greet, 'hi');
14201      * hi('moe');
14202      * // => 'hi moe'
14203      */
14204     function partial(func) {
14205       return createBound(func, 16, nativeSlice.call(arguments, 1));
14206     }
14207
14208     /**
14209      * This method is like `_.partial` except that `partial` arguments are
14210      * appended to those provided to the new function.
14211      *
14212      * @static
14213      * @memberOf _
14214      * @category Functions
14215      * @param {Function} func The function to partially apply arguments to.
14216      * @param {...*} [arg] Arguments to be partially applied.
14217      * @returns {Function} Returns the new partially applied function.
14218      * @example
14219      *
14220      * var defaultsDeep = _.partialRight(_.merge, _.defaults);
14221      *
14222      * var options = {
14223      *   'variable': 'data',
14224      *   'imports': { 'jq': $ }
14225      * };
14226      *
14227      * defaultsDeep(options, _.templateSettings);
14228      *
14229      * options.variable
14230      * // => 'data'
14231      *
14232      * options.imports
14233      * // => { '_': _, 'jq': $ }
14234      */
14235     function partialRight(func) {
14236       return createBound(func, 32, null, nativeSlice.call(arguments, 1));
14237     }
14238
14239     /**
14240      * Creates a function that, when executed, will only call the `func` function
14241      * at most once per every `wait` milliseconds. Provide an options object to
14242      * indicate that `func` should be invoked on the leading and/or trailing edge
14243      * of the `wait` timeout. Subsequent calls to the throttled function will
14244      * return the result of the last `func` call.
14245      *
14246      * Note: If `leading` and `trailing` options are `true` `func` will be called
14247      * on the trailing edge of the timeout only if the the throttled function is
14248      * invoked more than once during the `wait` timeout.
14249      *
14250      * @static
14251      * @memberOf _
14252      * @category Functions
14253      * @param {Function} func The function to throttle.
14254      * @param {number} wait The number of milliseconds to throttle executions to.
14255      * @param {Object} [options] The options object.
14256      * @param {boolean} [options.leading=true] Specify execution on the leading edge of the timeout.
14257      * @param {boolean} [options.trailing=true] Specify execution on the trailing edge of the timeout.
14258      * @returns {Function} Returns the new throttled function.
14259      * @example
14260      *
14261      * // avoid excessively updating the position while scrolling
14262      * var throttled = _.throttle(updatePosition, 100);
14263      * jQuery(window).on('scroll', throttled);
14264      *
14265      * // execute `renewToken` when the click event is fired, but not more than once every 5 minutes
14266      * jQuery('.interactive').on('click', _.throttle(renewToken, 300000, {
14267      *   'trailing': false
14268      * }));
14269      */
14270     function throttle(func, wait, options) {
14271       var leading = true,
14272           trailing = true;
14273
14274       if (!isFunction(func)) {
14275         throw new TypeError;
14276       }
14277       if (options === false) {
14278         leading = false;
14279       } else if (isObject(options)) {
14280         leading = 'leading' in options ? options.leading : leading;
14281         trailing = 'trailing' in options ? options.trailing : trailing;
14282       }
14283       debounceOptions.leading = leading;
14284       debounceOptions.maxWait = wait;
14285       debounceOptions.trailing = trailing;
14286
14287       var result = debounce(func, wait, debounceOptions);
14288       return result;
14289     }
14290
14291     /**
14292      * Creates a function that provides `value` to the wrapper function as its
14293      * first argument. Additional arguments provided to the function are appended
14294      * to those provided to the wrapper function. The wrapper is executed with
14295      * the `this` binding of the created function.
14296      *
14297      * @static
14298      * @memberOf _
14299      * @category Functions
14300      * @param {*} value The value to wrap.
14301      * @param {Function} wrapper The wrapper function.
14302      * @returns {Function} Returns the new function.
14303      * @example
14304      *
14305      * var hello = function(name) { return 'hello ' + name; };
14306      * hello = _.wrap(hello, function(func) {
14307      *   return 'before, ' + func('moe') + ', after';
14308      * });
14309      * hello();
14310      * // => 'before, hello moe, after'
14311      */
14312     function wrap(value, wrapper) {
14313       if (!isFunction(wrapper)) {
14314         throw new TypeError;
14315       }
14316       return function() {
14317         var args = [value];
14318         push.apply(args, arguments);
14319         return wrapper.apply(this, args);
14320       };
14321     }
14322
14323     /*--------------------------------------------------------------------------*/
14324
14325     /**
14326      * Converts the characters `&`, `<`, `>`, `"`, and `'` in `string` to their
14327      * corresponding HTML entities.
14328      *
14329      * @static
14330      * @memberOf _
14331      * @category Utilities
14332      * @param {string} string The string to escape.
14333      * @returns {string} Returns the escaped string.
14334      * @example
14335      *
14336      * _.escape('Moe, Larry & Curly');
14337      * // => 'Moe, Larry &amp; Curly'
14338      */
14339     function escape(string) {
14340       return string == null ? '' : String(string).replace(reUnescapedHtml, escapeHtmlChar);
14341     }
14342
14343     /**
14344      * This method returns the first argument provided to it.
14345      *
14346      * @static
14347      * @memberOf _
14348      * @category Utilities
14349      * @param {*} value Any value.
14350      * @returns {*} Returns `value`.
14351      * @example
14352      *
14353      * var moe = { 'name': 'moe' };
14354      * moe === _.identity(moe);
14355      * // => true
14356      */
14357     function identity(value) {
14358       return value;
14359     }
14360
14361     /**
14362      * Adds function properties of a source object to the `lodash` function and
14363      * chainable wrapper.
14364      *
14365      * @static
14366      * @memberOf _
14367      * @category Utilities
14368      * @param {Object} object The object of function properties to add to `lodash`.
14369      * @param {Object} object The object of function properties to add to `lodash`.
14370      * @example
14371      *
14372      * _.mixin({
14373      *   'capitalize': function(string) {
14374      *     return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase();
14375      *   }
14376      * });
14377      *
14378      * _.capitalize('moe');
14379      * // => 'Moe'
14380      *
14381      * _('moe').capitalize();
14382      * // => 'Moe'
14383      */
14384     function mixin(object, source) {
14385       var ctor = object,
14386           isFunc = !source || isFunction(ctor);
14387
14388       if (!source) {
14389         ctor = lodashWrapper;
14390         source = object;
14391         object = lodash;
14392       }
14393       forEach(functions(source), function(methodName) {
14394         var func = object[methodName] = source[methodName];
14395         if (isFunc) {
14396           ctor.prototype[methodName] = function() {
14397             var value = this.__wrapped__,
14398                 args = [value];
14399
14400             push.apply(args, arguments);
14401             var result = func.apply(object, args);
14402             if (value && typeof value == 'object' && value === result) {
14403               return this;
14404             }
14405             result = new ctor(result);
14406             result.__chain__ = this.__chain__;
14407             return result;
14408           };
14409         }
14410       });
14411     }
14412
14413     /**
14414      * Reverts the '_' variable to its previous value and returns a reference to
14415      * the `lodash` function.
14416      *
14417      * @static
14418      * @memberOf _
14419      * @category Utilities
14420      * @returns {Function} Returns the `lodash` function.
14421      * @example
14422      *
14423      * var lodash = _.noConflict();
14424      */
14425     function noConflict() {
14426       context._ = oldDash;
14427       return this;
14428     }
14429
14430     /**
14431      * Converts the given value into an integer of the specified radix.
14432      * If `radix` is `undefined` or `0` a `radix` of `10` is used unless the
14433      * `value` is a hexadecimal, in which case a `radix` of `16` is used.
14434      *
14435      * Note: This method avoids differences in native ES3 and ES5 `parseInt`
14436      * implementations. See http://es5.github.io/#E.
14437      *
14438      * @static
14439      * @memberOf _
14440      * @category Utilities
14441      * @param {string} value The value to parse.
14442      * @param {number} [radix] The radix used to interpret the value to parse.
14443      * @returns {number} Returns the new integer value.
14444      * @example
14445      *
14446      * _.parseInt('08');
14447      * // => 8
14448      */
14449     var parseInt = nativeParseInt(whitespace + '08') == 8 ? nativeParseInt : function(value, radix) {
14450       // Firefox and Opera still follow the ES3 specified implementation of `parseInt`
14451       return nativeParseInt(isString(value) ? value.replace(reLeadingSpacesAndZeros, '') : value, radix || 0);
14452     };
14453
14454     /**
14455      * Produces a random number between `min` and `max` (inclusive). If only one
14456      * argument is provided a number between `0` and the given number will be
14457      * returned. If `floating` is truey or either `min` or `max` are floats a
14458      * floating-point number will be returned instead of an integer.
14459      *
14460      * @static
14461      * @memberOf _
14462      * @category Utilities
14463      * @param {number} [min=0] The minimum possible value.
14464      * @param {number} [max=1] The maximum possible value.
14465      * @param {boolean} [floating=false] Specify returning a floating-point number.
14466      * @returns {number} Returns a random number.
14467      * @example
14468      *
14469      * _.random(0, 5);
14470      * // => an integer between 0 and 5
14471      *
14472      * _.random(5);
14473      * // => also an integer between 0 and 5
14474      *
14475      * _.random(5, true);
14476      * // => a floating-point number between 0 and 5
14477      *
14478      * _.random(1.2, 5.2);
14479      * // => a floating-point number between 1.2 and 5.2
14480      */
14481     function random(min, max, floating) {
14482       var noMin = min == null,
14483           noMax = max == null;
14484
14485       if (floating == null) {
14486         if (typeof min == 'boolean' && noMax) {
14487           floating = min;
14488           min = 1;
14489         }
14490         else if (!noMax && typeof max == 'boolean') {
14491           floating = max;
14492           noMax = true;
14493         }
14494       }
14495       if (noMin && noMax) {
14496         max = 1;
14497       }
14498       min = +min || 0;
14499       if (noMax) {
14500         max = min;
14501         min = 0;
14502       } else {
14503         max = +max || 0;
14504       }
14505       var rand = nativeRandom();
14506       return (floating || min % 1 || max % 1)
14507         ? nativeMin(min + (rand * (max - min + parseFloat('1e-' + ((rand +'').length - 1)))), max)
14508         : min + floor(rand * (max - min + 1));
14509     }
14510
14511     /**
14512      * Resolves the value of `property` on `object`. If `property` is a function
14513      * it will be invoked with the `this` binding of `object` and its result returned,
14514      * else the property value is returned. If `object` is falsey then `undefined`
14515      * is returned.
14516      *
14517      * @static
14518      * @memberOf _
14519      * @category Utilities
14520      * @param {Object} object The object to inspect.
14521      * @param {string} property The property to get the value of.
14522      * @returns {*} Returns the resolved value.
14523      * @example
14524      *
14525      * var object = {
14526      *   'cheese': 'crumpets',
14527      *   'stuff': function() {
14528      *     return 'nonsense';
14529      *   }
14530      * };
14531      *
14532      * _.result(object, 'cheese');
14533      * // => 'crumpets'
14534      *
14535      * _.result(object, 'stuff');
14536      * // => 'nonsense'
14537      */
14538     function result(object, property) {
14539       if (object) {
14540         var value = object[property];
14541         return isFunction(value) ? object[property]() : value;
14542       }
14543     }
14544
14545     /**
14546      * A micro-templating method that handles arbitrary delimiters, preserves
14547      * whitespace, and correctly escapes quotes within interpolated code.
14548      *
14549      * Note: In the development build, `_.template` utilizes sourceURLs for easier
14550      * debugging. See http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl
14551      *
14552      * For more information on precompiling templates see:
14553      * http://lodash.com/#custom-builds
14554      *
14555      * For more information on Chrome extension sandboxes see:
14556      * http://developer.chrome.com/stable/extensions/sandboxingEval.html
14557      *
14558      * @static
14559      * @memberOf _
14560      * @category Utilities
14561      * @param {string} text The template text.
14562      * @param {Object} data The data object used to populate the text.
14563      * @param {Object} [options] The options object.
14564      * @param {RegExp} [options.escape] The "escape" delimiter.
14565      * @param {RegExp} [options.evaluate] The "evaluate" delimiter.
14566      * @param {Object} [options.imports] An object to import into the template as local variables.
14567      * @param {RegExp} [options.interpolate] The "interpolate" delimiter.
14568      * @param {string} [sourceURL] The sourceURL of the template's compiled source.
14569      * @param {string} [variable] The data object variable name.
14570      * @returns {Function|string} Returns a compiled function when no `data` object
14571      *  is given, else it returns the interpolated text.
14572      * @example
14573      *
14574      * // using the "interpolate" delimiter to create a compiled template
14575      * var compiled = _.template('hello <%= name %>');
14576      * compiled({ 'name': 'moe' });
14577      * // => 'hello moe'
14578      *
14579      * // using the "escape" delimiter to escape HTML in data property values
14580      * _.template('<b><%- value %></b>', { 'value': '<script>' });
14581      * // => '<b>&lt;script&gt;</b>'
14582      *
14583      * // using the "evaluate" delimiter to generate HTML
14584      * var list = '<% _.forEach(people, function(name) { %><li><%- name %></li><% }); %>';
14585      * _.template(list, { 'people': ['moe', 'larry'] });
14586      * // => '<li>moe</li><li>larry</li>'
14587      *
14588      * // using the ES6 delimiter as an alternative to the default "interpolate" delimiter
14589      * _.template('hello ${ name }', { 'name': 'curly' });
14590      * // => 'hello curly'
14591      *
14592      * // using the internal `print` function in "evaluate" delimiters
14593      * _.template('<% print("hello " + name); %>!', { 'name': 'larry' });
14594      * // => 'hello larry!'
14595      *
14596      * // using a custom template delimiters
14597      * _.templateSettings = {
14598      *   'interpolate': /{{([\s\S]+?)}}/g
14599      * };
14600      *
14601      * _.template('hello {{ name }}!', { 'name': 'mustache' });
14602      * // => 'hello mustache!'
14603      *
14604      * // using the `imports` option to import jQuery
14605      * var list = '<% $.each(people, function(name) { %><li><%- name %></li><% }); %>';
14606      * _.template(list, { 'people': ['moe', 'larry'] }, { 'imports': { '$': jQuery } });
14607      * // => '<li>moe</li><li>larry</li>'
14608      *
14609      * // using the `sourceURL` option to specify a custom sourceURL for the template
14610      * var compiled = _.template('hello <%= name %>', null, { 'sourceURL': '/basic/greeting.jst' });
14611      * compiled(data);
14612      * // => find the source of "greeting.jst" under the Sources tab or Resources panel of the web inspector
14613      *
14614      * // using the `variable` option to ensure a with-statement isn't used in the compiled template
14615      * var compiled = _.template('hi <%= data.name %>!', null, { 'variable': 'data' });
14616      * compiled.source;
14617      * // => function(data) {
14618      *   var __t, __p = '', __e = _.escape;
14619      *   __p += 'hi ' + ((__t = ( data.name )) == null ? '' : __t) + '!';
14620      *   return __p;
14621      * }
14622      *
14623      * // using the `source` property to inline compiled templates for meaningful
14624      * // line numbers in error messages and a stack trace
14625      * fs.writeFileSync(path.join(cwd, 'jst.js'), '\
14626      *   var JST = {\
14627      *     "main": ' + _.template(mainText).source + '\
14628      *   };\
14629      * ');
14630      */
14631     function template(text, data, options) {
14632       // based on John Resig's `tmpl` implementation
14633       // http://ejohn.org/blog/javascript-micro-templating/
14634       // and Laura Doktorova's doT.js
14635       // https://github.com/olado/doT
14636       var settings = lodash.templateSettings;
14637       text || (text = '');
14638
14639       // avoid missing dependencies when `iteratorTemplate` is not defined
14640       options = defaults({}, options, settings);
14641
14642       var imports = defaults({}, options.imports, settings.imports),
14643           importsKeys = keys(imports),
14644           importsValues = values(imports);
14645
14646       var isEvaluating,
14647           index = 0,
14648           interpolate = options.interpolate || reNoMatch,
14649           source = "__p += '";
14650
14651       // compile the regexp to match each delimiter
14652       var reDelimiters = RegExp(
14653         (options.escape || reNoMatch).source + '|' +
14654         interpolate.source + '|' +
14655         (interpolate === reInterpolate ? reEsTemplate : reNoMatch).source + '|' +
14656         (options.evaluate || reNoMatch).source + '|$'
14657       , 'g');
14658
14659       text.replace(reDelimiters, function(match, escapeValue, interpolateValue, esTemplateValue, evaluateValue, offset) {
14660         interpolateValue || (interpolateValue = esTemplateValue);
14661
14662         // escape characters that cannot be included in string literals
14663         source += text.slice(index, offset).replace(reUnescapedString, escapeStringChar);
14664
14665         // replace delimiters with snippets
14666         if (escapeValue) {
14667           source += "' +\n__e(" + escapeValue + ") +\n'";
14668         }
14669         if (evaluateValue) {
14670           isEvaluating = true;
14671           source += "';\n" + evaluateValue + ";\n__p += '";
14672         }
14673         if (interpolateValue) {
14674           source += "' +\n((__t = (" + interpolateValue + ")) == null ? '' : __t) +\n'";
14675         }
14676         index = offset + match.length;
14677
14678         // the JS engine embedded in Adobe products requires returning the `match`
14679         // string in order to produce the correct `offset` value
14680         return match;
14681       });
14682
14683       source += "';\n";
14684
14685       // if `variable` is not specified, wrap a with-statement around the generated
14686       // code to add the data object to the top of the scope chain
14687       var variable = options.variable,
14688           hasVariable = variable;
14689
14690       if (!hasVariable) {
14691         variable = 'obj';
14692         source = 'with (' + variable + ') {\n' + source + '\n}\n';
14693       }
14694       // cleanup code by stripping empty strings
14695       source = (isEvaluating ? source.replace(reEmptyStringLeading, '') : source)
14696         .replace(reEmptyStringMiddle, '$1')
14697         .replace(reEmptyStringTrailing, '$1;');
14698
14699       // frame code as the function body
14700       source = 'function(' + variable + ') {\n' +
14701         (hasVariable ? '' : variable + ' || (' + variable + ' = {});\n') +
14702         "var __t, __p = '', __e = _.escape" +
14703         (isEvaluating
14704           ? ', __j = Array.prototype.join;\n' +
14705             "function print() { __p += __j.call(arguments, '') }\n"
14706           : ';\n'
14707         ) +
14708         source +
14709         'return __p\n}';
14710
14711       // Use a sourceURL for easier debugging.
14712       // http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl
14713       var sourceURL = '\n/*\n//# sourceURL=' + (options.sourceURL || '/lodash/template/source[' + (templateCounter++) + ']') + '\n*/';
14714
14715       try {
14716         var result = Function(importsKeys, 'return ' + source + sourceURL).apply(undefined, importsValues);
14717       } catch(e) {
14718         e.source = source;
14719         throw e;
14720       }
14721       if (data) {
14722         return result(data);
14723       }
14724       // provide the compiled function's source by its `toString` method, in
14725       // supported environments, or the `source` property as a convenience for
14726       // inlining compiled templates during the build process
14727       result.source = source;
14728       return result;
14729     }
14730
14731     /**
14732      * Executes the callback `n` times, returning an array of the results
14733      * of each callback execution. The callback is bound to `thisArg` and invoked
14734      * with one argument; (index).
14735      *
14736      * @static
14737      * @memberOf _
14738      * @category Utilities
14739      * @param {number} n The number of times to execute the callback.
14740      * @param {Function} callback The function called per iteration.
14741      * @param {*} [thisArg] The `this` binding of `callback`.
14742      * @returns {Array} Returns an array of the results of each `callback` execution.
14743      * @example
14744      *
14745      * var diceRolls = _.times(3, _.partial(_.random, 1, 6));
14746      * // => [3, 6, 4]
14747      *
14748      * _.times(3, function(n) { mage.castSpell(n); });
14749      * // => calls `mage.castSpell(n)` three times, passing `n` of `0`, `1`, and `2` respectively
14750      *
14751      * _.times(3, function(n) { this.cast(n); }, mage);
14752      * // => also calls `mage.castSpell(n)` three times
14753      */
14754     function times(n, callback, thisArg) {
14755       n = (n = +n) > -1 ? n : 0;
14756       var index = -1,
14757           result = Array(n);
14758
14759       callback = baseCreateCallback(callback, thisArg, 1);
14760       while (++index < n) {
14761         result[index] = callback(index);
14762       }
14763       return result;
14764     }
14765
14766     /**
14767      * The inverse of `_.escape` this method converts the HTML entities
14768      * `&amp;`, `&lt;`, `&gt;`, `&quot;`, and `&#39;` in `string` to their
14769      * corresponding characters.
14770      *
14771      * @static
14772      * @memberOf _
14773      * @category Utilities
14774      * @param {string} string The string to unescape.
14775      * @returns {string} Returns the unescaped string.
14776      * @example
14777      *
14778      * _.unescape('Moe, Larry &amp; Curly');
14779      * // => 'Moe, Larry & Curly'
14780      */
14781     function unescape(string) {
14782       return string == null ? '' : String(string).replace(reEscapedHtml, unescapeHtmlChar);
14783     }
14784
14785     /**
14786      * Generates a unique ID. If `prefix` is provided the ID will be appended to it.
14787      *
14788      * @static
14789      * @memberOf _
14790      * @category Utilities
14791      * @param {string} [prefix] The value to prefix the ID with.
14792      * @returns {string} Returns the unique ID.
14793      * @example
14794      *
14795      * _.uniqueId('contact_');
14796      * // => 'contact_104'
14797      *
14798      * _.uniqueId();
14799      * // => '105'
14800      */
14801     function uniqueId(prefix) {
14802       var id = ++idCounter;
14803       return String(prefix == null ? '' : prefix) + id;
14804     }
14805
14806     /*--------------------------------------------------------------------------*/
14807
14808     /**
14809      * Creates a `lodash` object that wraps the given value with explicit
14810      * method chaining enabled.
14811      *
14812      * @static
14813      * @memberOf _
14814      * @category Chaining
14815      * @param {*} value The value to wrap.
14816      * @returns {Object} Returns the wrapper object.
14817      * @example
14818      *
14819      * var stooges = [
14820      *   { 'name': 'moe', 'age': 40 },
14821      *   { 'name': 'larry', 'age': 50 },
14822      *   { 'name': 'curly', 'age': 60 }
14823      * ];
14824      *
14825      * var youngest = _.chain(stooges)
14826      *     .sortBy('age')
14827      *     .map(function(stooge) { return stooge.name + ' is ' + stooge.age; })
14828      *     .first()
14829      *     .value();
14830      * // => 'moe is 40'
14831      */
14832     function chain(value) {
14833       value = new lodashWrapper(value);
14834       value.__chain__ = true;
14835       return value;
14836     }
14837
14838     /**
14839      * Invokes `interceptor` with the `value` as the first argument and then
14840      * returns `value`. The purpose of this method is to "tap into" a method
14841      * chain in order to perform operations on intermediate results within
14842      * the chain.
14843      *
14844      * @static
14845      * @memberOf _
14846      * @category Chaining
14847      * @param {*} value The value to provide to `interceptor`.
14848      * @param {Function} interceptor The function to invoke.
14849      * @returns {*} Returns `value`.
14850      * @example
14851      *
14852      * _([1, 2, 3, 4])
14853      *  .filter(function(num) { return num % 2 == 0; })
14854      *  .tap(function(array) { console.log(array); })
14855      *  .map(function(num) { return num * num; })
14856      *  .value();
14857      * // => // [2, 4] (logged)
14858      * // => [4, 16]
14859      */
14860     function tap(value, interceptor) {
14861       interceptor(value);
14862       return value;
14863     }
14864
14865     /**
14866      * Enables explicit method chaining on the wrapper object.
14867      *
14868      * @name chain
14869      * @memberOf _
14870      * @category Chaining
14871      * @returns {*} Returns the wrapper object.
14872      * @example
14873      *
14874      * var stooges = [
14875      *   { 'name': 'moe', 'age': 40 },
14876      *   { 'name': 'larry', 'age': 50 }
14877      * ];
14878      *
14879      * // without explicit chaining
14880      * _(stooges).first();
14881      * // => { 'name': 'moe', 'age': 40 }
14882      *
14883      * // with explicit chaining
14884      * _(stooges).chain()
14885      *   .first()
14886      *   .pick('age')
14887      *   .value()
14888      * // => { 'age': 40 }
14889      */
14890     function wrapperChain() {
14891       this.__chain__ = true;
14892       return this;
14893     }
14894
14895     /**
14896      * Produces the `toString` result of the wrapped value.
14897      *
14898      * @name toString
14899      * @memberOf _
14900      * @category Chaining
14901      * @returns {string} Returns the string result.
14902      * @example
14903      *
14904      * _([1, 2, 3]).toString();
14905      * // => '1,2,3'
14906      */
14907     function wrapperToString() {
14908       return String(this.__wrapped__);
14909     }
14910
14911     /**
14912      * Extracts the wrapped value.
14913      *
14914      * @name valueOf
14915      * @memberOf _
14916      * @alias value
14917      * @category Chaining
14918      * @returns {*} Returns the wrapped value.
14919      * @example
14920      *
14921      * _([1, 2, 3]).valueOf();
14922      * // => [1, 2, 3]
14923      */
14924     function wrapperValueOf() {
14925       return this.__wrapped__;
14926     }
14927
14928     /*--------------------------------------------------------------------------*/
14929
14930     // add functions that return wrapped values when chaining
14931     lodash.after = after;
14932     lodash.assign = assign;
14933     lodash.at = at;
14934     lodash.bind = bind;
14935     lodash.bindAll = bindAll;
14936     lodash.bindKey = bindKey;
14937     lodash.chain = chain;
14938     lodash.compact = compact;
14939     lodash.compose = compose;
14940     lodash.countBy = countBy;
14941     lodash.createCallback = createCallback;
14942     lodash.curry = curry;
14943     lodash.debounce = debounce;
14944     lodash.defaults = defaults;
14945     lodash.defer = defer;
14946     lodash.delay = delay;
14947     lodash.difference = difference;
14948     lodash.filter = filter;
14949     lodash.flatten = flatten;
14950     lodash.forEach = forEach;
14951     lodash.forEachRight = forEachRight;
14952     lodash.forIn = forIn;
14953     lodash.forInRight = forInRight;
14954     lodash.forOwn = forOwn;
14955     lodash.forOwnRight = forOwnRight;
14956     lodash.functions = functions;
14957     lodash.groupBy = groupBy;
14958     lodash.indexBy = indexBy;
14959     lodash.initial = initial;
14960     lodash.intersection = intersection;
14961     lodash.invert = invert;
14962     lodash.invoke = invoke;
14963     lodash.keys = keys;
14964     lodash.map = map;
14965     lodash.max = max;
14966     lodash.memoize = memoize;
14967     lodash.merge = merge;
14968     lodash.min = min;
14969     lodash.omit = omit;
14970     lodash.once = once;
14971     lodash.pairs = pairs;
14972     lodash.partial = partial;
14973     lodash.partialRight = partialRight;
14974     lodash.pick = pick;
14975     lodash.pluck = pluck;
14976     lodash.pull = pull;
14977     lodash.range = range;
14978     lodash.reject = reject;
14979     lodash.remove = remove;
14980     lodash.rest = rest;
14981     lodash.shuffle = shuffle;
14982     lodash.sortBy = sortBy;
14983     lodash.tap = tap;
14984     lodash.throttle = throttle;
14985     lodash.times = times;
14986     lodash.toArray = toArray;
14987     lodash.transform = transform;
14988     lodash.union = union;
14989     lodash.uniq = uniq;
14990     lodash.values = values;
14991     lodash.where = where;
14992     lodash.without = without;
14993     lodash.wrap = wrap;
14994     lodash.zip = zip;
14995     lodash.zipObject = zipObject;
14996
14997     // add aliases
14998     lodash.collect = map;
14999     lodash.drop = rest;
15000     lodash.each = forEach;
15001     lodash.eachRight = forEachRight;
15002     lodash.extend = assign;
15003     lodash.methods = functions;
15004     lodash.object = zipObject;
15005     lodash.select = filter;
15006     lodash.tail = rest;
15007     lodash.unique = uniq;
15008     lodash.unzip = zip;
15009
15010     // add functions to `lodash.prototype`
15011     mixin(lodash);
15012
15013     /*--------------------------------------------------------------------------*/
15014
15015     // add functions that return unwrapped values when chaining
15016     lodash.clone = clone;
15017     lodash.cloneDeep = cloneDeep;
15018     lodash.contains = contains;
15019     lodash.escape = escape;
15020     lodash.every = every;
15021     lodash.find = find;
15022     lodash.findIndex = findIndex;
15023     lodash.findKey = findKey;
15024     lodash.findLast = findLast;
15025     lodash.findLastIndex = findLastIndex;
15026     lodash.findLastKey = findLastKey;
15027     lodash.has = has;
15028     lodash.identity = identity;
15029     lodash.indexOf = indexOf;
15030     lodash.isArguments = isArguments;
15031     lodash.isArray = isArray;
15032     lodash.isBoolean = isBoolean;
15033     lodash.isDate = isDate;
15034     lodash.isElement = isElement;
15035     lodash.isEmpty = isEmpty;
15036     lodash.isEqual = isEqual;
15037     lodash.isFinite = isFinite;
15038     lodash.isFunction = isFunction;
15039     lodash.isNaN = isNaN;
15040     lodash.isNull = isNull;
15041     lodash.isNumber = isNumber;
15042     lodash.isObject = isObject;
15043     lodash.isPlainObject = isPlainObject;
15044     lodash.isRegExp = isRegExp;
15045     lodash.isString = isString;
15046     lodash.isUndefined = isUndefined;
15047     lodash.lastIndexOf = lastIndexOf;
15048     lodash.mixin = mixin;
15049     lodash.noConflict = noConflict;
15050     lodash.parseInt = parseInt;
15051     lodash.random = random;
15052     lodash.reduce = reduce;
15053     lodash.reduceRight = reduceRight;
15054     lodash.result = result;
15055     lodash.runInContext = runInContext;
15056     lodash.size = size;
15057     lodash.some = some;
15058     lodash.sortedIndex = sortedIndex;
15059     lodash.template = template;
15060     lodash.unescape = unescape;
15061     lodash.uniqueId = uniqueId;
15062
15063     // add aliases
15064     lodash.all = every;
15065     lodash.any = some;
15066     lodash.detect = find;
15067     lodash.findWhere = find;
15068     lodash.foldl = reduce;
15069     lodash.foldr = reduceRight;
15070     lodash.include = contains;
15071     lodash.inject = reduce;
15072
15073     forOwn(lodash, function(func, methodName) {
15074       if (!lodash.prototype[methodName]) {
15075         lodash.prototype[methodName] = function() {
15076           var args = [this.__wrapped__],
15077               chainAll = this.__chain__;
15078
15079           push.apply(args, arguments);
15080           var result = func.apply(lodash, args);
15081           return chainAll
15082             ? new lodashWrapper(result, chainAll)
15083             : result;
15084         };
15085       }
15086     });
15087
15088     /*--------------------------------------------------------------------------*/
15089
15090     // add functions capable of returning wrapped and unwrapped values when chaining
15091     lodash.first = first;
15092     lodash.last = last;
15093     lodash.sample = sample;
15094
15095     // add aliases
15096     lodash.take = first;
15097     lodash.head = first;
15098
15099     forOwn(lodash, function(func, methodName) {
15100       var callbackable = methodName !== 'sample';
15101       if (!lodash.prototype[methodName]) {
15102         lodash.prototype[methodName]= function(n, guard) {
15103           var chainAll = this.__chain__,
15104               result = func(this.__wrapped__, n, guard);
15105
15106           return !chainAll && (n == null || (guard && !(callbackable && typeof n == 'function')))
15107             ? result
15108             : new lodashWrapper(result, chainAll);
15109         };
15110       }
15111     });
15112
15113     /*--------------------------------------------------------------------------*/
15114
15115     /**
15116      * The semantic version number.
15117      *
15118      * @static
15119      * @memberOf _
15120      * @type string
15121      */
15122     lodash.VERSION = '2.2.1';
15123
15124     // add "Chaining" functions to the wrapper
15125     lodash.prototype.chain = wrapperChain;
15126     lodash.prototype.toString = wrapperToString;
15127     lodash.prototype.value = wrapperValueOf;
15128     lodash.prototype.valueOf = wrapperValueOf;
15129
15130     // add `Array` functions that return unwrapped values
15131     forEach(['join', 'pop', 'shift'], function(methodName) {
15132       var func = arrayRef[methodName];
15133       lodash.prototype[methodName] = function() {
15134         var chainAll = this.__chain__,
15135             result = func.apply(this.__wrapped__, arguments);
15136
15137         return chainAll
15138           ? new lodashWrapper(result, chainAll)
15139           : result;
15140       };
15141     });
15142
15143     // add `Array` functions that return the wrapped value
15144     forEach(['push', 'reverse', 'sort', 'unshift'], function(methodName) {
15145       var func = arrayRef[methodName];
15146       lodash.prototype[methodName] = function() {
15147         func.apply(this.__wrapped__, arguments);
15148         return this;
15149       };
15150     });
15151
15152     // add `Array` functions that return new wrapped values
15153     forEach(['concat', 'slice', 'splice'], function(methodName) {
15154       var func = arrayRef[methodName];
15155       lodash.prototype[methodName] = function() {
15156         return new lodashWrapper(func.apply(this.__wrapped__, arguments), this.__chain__);
15157       };
15158     });
15159
15160     return lodash;
15161   }
15162
15163   /*--------------------------------------------------------------------------*/
15164
15165   // expose Lo-Dash
15166   var _ = runInContext();
15167
15168   // some AMD build optimizers, like r.js, check for condition patterns like the following:
15169   if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
15170     // Expose Lo-Dash to the global object even when an AMD loader is present in
15171     // case Lo-Dash was injected by a third-party script and not intended to be
15172     // loaded as a module. The global assignment can be reverted in the Lo-Dash
15173     // module by its `noConflict()` method.
15174     root._ = _;
15175
15176     // define as an anonymous module so, through path mapping, it can be
15177     // referenced as the "underscore" module
15178     define(function() {
15179       return _;
15180     });
15181   }
15182   // check for `exports` after `define` in case a build optimizer adds an `exports` object
15183   else if (freeExports && freeModule) {
15184     // in Node.js or RingoJS
15185     if (moduleExports) {
15186       (freeModule.exports = _)._ = _;
15187     }
15188     // in Narwhal or Rhino -require
15189     else {
15190       freeExports._ = _;
15191     }
15192   }
15193   else {
15194     // in a browser or Rhino
15195     root._ = _;
15196   }
15197 }.call(this));
15198
15199 //     Backbone.js 1.0.0
15200
15201 //     (c) 2010-2013 Jeremy Ashkenas, DocumentCloud Inc.
15202 //     Backbone may be freely distributed under the MIT license.
15203 //     For all details and documentation:
15204 //     http://backbonejs.org
15205
15206 (function(){
15207
15208   // Initial Setup
15209   // -------------
15210
15211   // Save a reference to the global object (`window` in the browser, `exports`
15212   // on the server).
15213   var root = this;
15214
15215   // Save the previous value of the `Backbone` variable, so that it can be
15216   // restored later on, if `noConflict` is used.
15217   var previousBackbone = root.Backbone;
15218
15219   // Create local references to array methods we'll want to use later.
15220   var array = [];
15221   var push = array.push;
15222   var slice = array.slice;
15223   var splice = array.splice;
15224
15225   // The top-level namespace. All public Backbone classes and modules will
15226   // be attached to this. Exported for both the browser and the server.
15227   var Backbone;
15228   if (typeof exports !== 'undefined') {
15229     Backbone = exports;
15230   } else {
15231     Backbone = root.Backbone = {};
15232   }
15233
15234   // Current version of the library. Keep in sync with `package.json`.
15235   Backbone.VERSION = '1.0.0';
15236
15237   // Require Underscore, if we're on the server, and it's not already present.
15238   var _ = root._;
15239   if (!_ && (typeof require !== 'undefined')) _ = require('underscore');
15240
15241   // For Backbone's purposes, jQuery, Zepto, Ender, or My Library (kidding) owns
15242   // the `$` variable.
15243   Backbone.$ = root.jQuery || root.Zepto || root.ender || root.$;
15244
15245   // Runs Backbone.js in *noConflict* mode, returning the `Backbone` variable
15246   // to its previous owner. Returns a reference to this Backbone object.
15247   Backbone.noConflict = function() {
15248     root.Backbone = previousBackbone;
15249     return this;
15250   };
15251
15252   // Turn on `emulateHTTP` to support legacy HTTP servers. Setting this option
15253   // will fake `"PUT"` and `"DELETE"` requests via the `_method` parameter and
15254   // set a `X-Http-Method-Override` header.
15255   Backbone.emulateHTTP = false;
15256
15257   // Turn on `emulateJSON` to support legacy servers that can't deal with direct
15258   // `application/json` requests ... will encode the body as
15259   // `application/x-www-form-urlencoded` instead and will send the model in a
15260   // form param named `model`.
15261   Backbone.emulateJSON = false;
15262
15263   // Backbone.Events
15264   // ---------------
15265
15266   // A module that can be mixed in to *any object* in order to provide it with
15267   // custom events. You may bind with `on` or remove with `off` callback
15268   // functions to an event; `trigger`-ing an event fires all callbacks in
15269   // succession.
15270   //
15271   //     var object = {};
15272   //     _.extend(object, Backbone.Events);
15273   //     object.on('expand', function(){ alert('expanded'); });
15274   //     object.trigger('expand');
15275   //
15276   var Events = Backbone.Events = {
15277
15278     // Bind an event to a `callback` function. Passing `"all"` will bind
15279     // the callback to all events fired.
15280     on: function(name, callback, context) {
15281       if (!eventsApi(this, 'on', name, [callback, context]) || !callback) return this;
15282       this._events || (this._events = {});
15283       var events = this._events[name] || (this._events[name] = []);
15284       events.push({callback: callback, context: context, ctx: context || this});
15285       return this;
15286     },
15287
15288     // Bind an event to only be triggered a single time. After the first time
15289     // the callback is invoked, it will be removed.
15290     once: function(name, callback, context) {
15291       if (!eventsApi(this, 'once', name, [callback, context]) || !callback) return this;
15292       var self = this;
15293       var once = _.once(function() {
15294         self.off(name, once);
15295         callback.apply(this, arguments);
15296       });
15297       once._callback = callback;
15298       return this.on(name, once, context);
15299     },
15300
15301     // Remove one or many callbacks. If `context` is null, removes all
15302     // callbacks with that function. If `callback` is null, removes all
15303     // callbacks for the event. If `name` is null, removes all bound
15304     // callbacks for all events.
15305     off: function(name, callback, context) {
15306       var retain, ev, events, names, i, l, j, k;
15307       if (!this._events || !eventsApi(this, 'off', name, [callback, context])) return this;
15308       if (!name && !callback && !context) {
15309         this._events = {};
15310         return this;
15311       }
15312
15313       names = name ? [name] : _.keys(this._events);
15314       for (i = 0, l = names.length; i < l; i++) {
15315         name = names[i];
15316         if (events = this._events[name]) {
15317           this._events[name] = retain = [];
15318           if (callback || context) {
15319             for (j = 0, k = events.length; j < k; j++) {
15320               ev = events[j];
15321               if ((callback && callback !== ev.callback && callback !== ev.callback._callback) ||
15322                   (context && context !== ev.context)) {
15323                 retain.push(ev);
15324               }
15325             }
15326           }
15327           if (!retain.length) delete this._events[name];
15328         }
15329       }
15330
15331       return this;
15332     },
15333
15334     // Trigger one or many events, firing all bound callbacks. Callbacks are
15335     // passed the same arguments as `trigger` is, apart from the event name
15336     // (unless you're listening on `"all"`, which will cause your callback to
15337     // receive the true name of the event as the first argument).
15338     trigger: function(name) {
15339       if (!this._events) return this;
15340       var args = slice.call(arguments, 1);
15341       if (!eventsApi(this, 'trigger', name, args)) return this;
15342       var events = this._events[name];
15343       var allEvents = this._events.all;
15344       if (events) triggerEvents(events, args);
15345       if (allEvents) triggerEvents(allEvents, arguments);
15346       return this;
15347     },
15348
15349     // Tell this object to stop listening to either specific events ... or
15350     // to every object it's currently listening to.
15351     stopListening: function(obj, name, callback) {
15352       var listeners = this._listeners;
15353       if (!listeners) return this;
15354       var deleteListener = !name && !callback;
15355       if (typeof name === 'object') callback = this;
15356       if (obj) (listeners = {})[obj._listenerId] = obj;
15357       for (var id in listeners) {
15358         listeners[id].off(name, callback, this);
15359         if (deleteListener) delete this._listeners[id];
15360       }
15361       return this;
15362     }
15363
15364   };
15365
15366   // Regular expression used to split event strings.
15367   var eventSplitter = /\s+/;
15368
15369   // Implement fancy features of the Events API such as multiple event
15370   // names `"change blur"` and jQuery-style event maps `{change: action}`
15371   // in terms of the existing API.
15372   var eventsApi = function(obj, action, name, rest) {
15373     if (!name) return true;
15374
15375     // Handle event maps.
15376     if (typeof name === 'object') {
15377       for (var key in name) {
15378         obj[action].apply(obj, [key, name[key]].concat(rest));
15379       }
15380       return false;
15381     }
15382
15383     // Handle space separated event names.
15384     if (eventSplitter.test(name)) {
15385       var names = name.split(eventSplitter);
15386       for (var i = 0, l = names.length; i < l; i++) {
15387         obj[action].apply(obj, [names[i]].concat(rest));
15388       }
15389       return false;
15390     }
15391
15392     return true;
15393   };
15394
15395   // A difficult-to-believe, but optimized internal dispatch function for
15396   // triggering events. Tries to keep the usual cases speedy (most internal
15397   // Backbone events have 3 arguments).
15398   var triggerEvents = function(events, args) {
15399     var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2];
15400     switch (args.length) {
15401       case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx); return;
15402       case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1); return;
15403       case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return;
15404       case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return;
15405       default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args);
15406     }
15407   };
15408
15409   var listenMethods = {listenTo: 'on', listenToOnce: 'once'};
15410
15411   // Inversion-of-control versions of `on` and `once`. Tell *this* object to
15412   // listen to an event in another object ... keeping track of what it's
15413   // listening to.
15414   _.each(listenMethods, function(implementation, method) {
15415     Events[method] = function(obj, name, callback) {
15416       var listeners = this._listeners || (this._listeners = {});
15417       var id = obj._listenerId || (obj._listenerId = _.uniqueId('l'));
15418       listeners[id] = obj;
15419       if (typeof name === 'object') callback = this;
15420       obj[implementation](name, callback, this);
15421       return this;
15422     };
15423   });
15424
15425   // Aliases for backwards compatibility.
15426   Events.bind   = Events.on;
15427   Events.unbind = Events.off;
15428
15429   // Allow the `Backbone` object to serve as a global event bus, for folks who
15430   // want global "pubsub" in a convenient place.
15431   _.extend(Backbone, Events);
15432
15433   // Backbone.Model
15434   // --------------
15435
15436   // Backbone **Models** are the basic data object in the framework --
15437   // frequently representing a row in a table in a database on your server.
15438   // A discrete chunk of data and a bunch of useful, related methods for
15439   // performing computations and transformations on that data.
15440
15441   // Create a new model with the specified attributes. A client id (`cid`)
15442   // is automatically generated and assigned for you.
15443   var Model = Backbone.Model = function(attributes, options) {
15444     var defaults;
15445     var attrs = attributes || {};
15446     options || (options = {});
15447     this.cid = _.uniqueId('c');
15448     this.attributes = {};
15449     _.extend(this, _.pick(options, modelOptions));
15450     if (options.parse) attrs = this.parse(attrs, options) || {};
15451     if (defaults = _.result(this, 'defaults')) {
15452       attrs = _.defaults({}, attrs, defaults);
15453     }
15454     this.set(attrs, options);
15455     this.changed = {};
15456     this.initialize.apply(this, arguments);
15457   };
15458
15459   // A list of options to be attached directly to the model, if provided.
15460   var modelOptions = ['url', 'urlRoot', 'collection'];
15461
15462   // Attach all inheritable methods to the Model prototype.
15463   _.extend(Model.prototype, Events, {
15464
15465     // A hash of attributes whose current and previous value differ.
15466     changed: null,
15467
15468     // The value returned during the last failed validation.
15469     validationError: null,
15470
15471     // The default name for the JSON `id` attribute is `"id"`. MongoDB and
15472     // CouchDB users may want to set this to `"_id"`.
15473     idAttribute: 'id',
15474
15475     // Initialize is an empty function by default. Override it with your own
15476     // initialization logic.
15477     initialize: function(){},
15478
15479     // Return a copy of the model's `attributes` object.
15480     toJSON: function(options) {
15481       return _.clone(this.attributes);
15482     },
15483
15484     // Proxy `Backbone.sync` by default -- but override this if you need
15485     // custom syncing semantics for *this* particular model.
15486     sync: function() {
15487       return Backbone.sync.apply(this, arguments);
15488     },
15489
15490     // Get the value of an attribute.
15491     get: function(attr) {
15492       return this.attributes[attr];
15493     },
15494
15495     // Get the HTML-escaped value of an attribute.
15496     escape: function(attr) {
15497       return _.escape(this.get(attr));
15498     },
15499
15500     // Returns `true` if the attribute contains a value that is not null
15501     // or undefined.
15502     has: function(attr) {
15503       return this.get(attr) != null;
15504     },
15505
15506     // Set a hash of model attributes on the object, firing `"change"`. This is
15507     // the core primitive operation of a model, updating the data and notifying
15508     // anyone who needs to know about the change in state. The heart of the beast.
15509     set: function(key, val, options) {
15510       var attr, attrs, unset, changes, silent, changing, prev, current;
15511       if (key == null) return this;
15512
15513       // Handle both `"key", value` and `{key: value}` -style arguments.
15514       if (typeof key === 'object') {
15515         attrs = key;
15516         options = val;
15517       } else {
15518         (attrs = {})[key] = val;
15519       }
15520
15521       options || (options = {});
15522
15523       // Run validation.
15524       if (!this._validate(attrs, options)) return false;
15525
15526       // Extract attributes and options.
15527       unset           = options.unset;
15528       silent          = options.silent;
15529       changes         = [];
15530       changing        = this._changing;
15531       this._changing  = true;
15532
15533       if (!changing) {
15534         this._previousAttributes = _.clone(this.attributes);
15535         this.changed = {};
15536       }
15537       current = this.attributes, prev = this._previousAttributes;
15538
15539       // Check for changes of `id`.
15540       if (this.idAttribute in attrs) this.id = attrs[this.idAttribute];
15541
15542       // For each `set` attribute, update or delete the current value.
15543       for (attr in attrs) {
15544         val = attrs[attr];
15545         if (!_.isEqual(current[attr], val)) changes.push(attr);
15546         if (!_.isEqual(prev[attr], val)) {
15547           this.changed[attr] = val;
15548         } else {
15549           delete this.changed[attr];
15550         }
15551         unset ? delete current[attr] : current[attr] = val;
15552       }
15553
15554       // Trigger all relevant attribute changes.
15555       if (!silent) {
15556         if (changes.length) this._pending = true;
15557         for (var i = 0, l = changes.length; i < l; i++) {
15558           this.trigger('change:' + changes[i], this, current[changes[i]], options);
15559         }
15560       }
15561
15562       // You might be wondering why there's a `while` loop here. Changes can
15563       // be recursively nested within `"change"` events.
15564       if (changing) return this;
15565       if (!silent) {
15566         while (this._pending) {
15567           this._pending = false;
15568           this.trigger('change', this, options);
15569         }
15570       }
15571       this._pending = false;
15572       this._changing = false;
15573       return this;
15574     },
15575
15576     // Remove an attribute from the model, firing `"change"`. `unset` is a noop
15577     // if the attribute doesn't exist.
15578     unset: function(attr, options) {
15579       return this.set(attr, void 0, _.extend({}, options, {unset: true}));
15580     },
15581
15582     // Clear all attributes on the model, firing `"change"`.
15583     clear: function(options) {
15584       var attrs = {};
15585       for (var key in this.attributes) attrs[key] = void 0;
15586       return this.set(attrs, _.extend({}, options, {unset: true}));
15587     },
15588
15589     // Determine if the model has changed since the last `"change"` event.
15590     // If you specify an attribute name, determine if that attribute has changed.
15591     hasChanged: function(attr) {
15592       if (attr == null) return !_.isEmpty(this.changed);
15593       return _.has(this.changed, attr);
15594     },
15595
15596     // Return an object containing all the attributes that have changed, or
15597     // false if there are no changed attributes. Useful for determining what
15598     // parts of a view need to be updated and/or what attributes need to be
15599     // persisted to the server. Unset attributes will be set to undefined.
15600     // You can also pass an attributes object to diff against the model,
15601     // determining if there *would be* a change.
15602     changedAttributes: function(diff) {
15603       if (!diff) return this.hasChanged() ? _.clone(this.changed) : false;
15604       var val, changed = false;
15605       var old = this._changing ? this._previousAttributes : this.attributes;
15606       for (var attr in diff) {
15607         if (_.isEqual(old[attr], (val = diff[attr]))) continue;
15608         (changed || (changed = {}))[attr] = val;
15609       }
15610       return changed;
15611     },
15612
15613     // Get the previous value of an attribute, recorded at the time the last
15614     // `"change"` event was fired.
15615     previous: function(attr) {
15616       if (attr == null || !this._previousAttributes) return null;
15617       return this._previousAttributes[attr];
15618     },
15619
15620     // Get all of the attributes of the model at the time of the previous
15621     // `"change"` event.
15622     previousAttributes: function() {
15623       return _.clone(this._previousAttributes);
15624     },
15625
15626     // Fetch the model from the server. If the server's representation of the
15627     // model differs from its current attributes, they will be overridden,
15628     // triggering a `"change"` event.
15629     fetch: function(options) {
15630       options = options ? _.clone(options) : {};
15631       if (options.parse === void 0) options.parse = true;
15632       var model = this;
15633       var success = options.success;
15634       options.success = function(resp) {
15635         if (!model.set(model.parse(resp, options), options)) return false;
15636         if (success) success(model, resp, options);
15637         model.trigger('sync', model, resp, options);
15638       };
15639       wrapError(this, options);
15640       return this.sync('read', this, options);
15641     },
15642
15643     // Set a hash of model attributes, and sync the model to the server.
15644     // If the server returns an attributes hash that differs, the model's
15645     // state will be `set` again.
15646     save: function(key, val, options) {
15647       var attrs, method, xhr, attributes = this.attributes;
15648
15649       // Handle both `"key", value` and `{key: value}` -style arguments.
15650       if (key == null || typeof key === 'object') {
15651         attrs = key;
15652         options = val;
15653       } else {
15654         (attrs = {})[key] = val;
15655       }
15656
15657       // If we're not waiting and attributes exist, save acts as `set(attr).save(null, opts)`.
15658       if (attrs && (!options || !options.wait) && !this.set(attrs, options)) return false;
15659
15660       options = _.extend({validate: true}, options);
15661
15662       // Do not persist invalid models.
15663       if (!this._validate(attrs, options)) return false;
15664
15665       // Set temporary attributes if `{wait: true}`.
15666       if (attrs && options.wait) {
15667         this.attributes = _.extend({}, attributes, attrs);
15668       }
15669
15670       // After a successful server-side save, the client is (optionally)
15671       // updated with the server-side state.
15672       if (options.parse === void 0) options.parse = true;
15673       var model = this;
15674       var success = options.success;
15675       options.success = function(resp) {
15676         // Ensure attributes are restored during synchronous saves.
15677         model.attributes = attributes;
15678         var serverAttrs = model.parse(resp, options);
15679         if (options.wait) serverAttrs = _.extend(attrs || {}, serverAttrs);
15680         if (_.isObject(serverAttrs) && !model.set(serverAttrs, options)) {
15681           return false;
15682         }
15683         if (success) success(model, resp, options);
15684         model.trigger('sync', model, resp, options);
15685       };
15686       wrapError(this, options);
15687
15688       method = this.isNew() ? 'create' : (options.patch ? 'patch' : 'update');
15689       if (method === 'patch') options.attrs = attrs;
15690       xhr = this.sync(method, this, options);
15691
15692       // Restore attributes.
15693       if (attrs && options.wait) this.attributes = attributes;
15694
15695       return xhr;
15696     },
15697
15698     // Destroy this model on the server if it was already persisted.
15699     // Optimistically removes the model from its collection, if it has one.
15700     // If `wait: true` is passed, waits for the server to respond before removal.
15701     destroy: function(options) {
15702       options = options ? _.clone(options) : {};
15703       var model = this;
15704       var success = options.success;
15705
15706       var destroy = function() {
15707         model.trigger('destroy', model, model.collection, options);
15708       };
15709
15710       options.success = function(resp) {
15711         if (options.wait || model.isNew()) destroy();
15712         if (success) success(model, resp, options);
15713         if (!model.isNew()) model.trigger('sync', model, resp, options);
15714       };
15715
15716       if (this.isNew()) {
15717         options.success();
15718         return false;
15719       }
15720       wrapError(this, options);
15721
15722       var xhr = this.sync('delete', this, options);
15723       if (!options.wait) destroy();
15724       return xhr;
15725     },
15726
15727     // Default URL for the model's representation on the server -- if you're
15728     // using Backbone's restful methods, override this to change the endpoint
15729     // that will be called.
15730     url: function() {
15731       var base = _.result(this, 'urlRoot') || _.result(this.collection, 'url') || urlError();
15732       if (this.isNew()) return base;
15733       return base + (base.charAt(base.length - 1) === '/' ? '' : '/') + encodeURIComponent(this.id);
15734     },
15735
15736     // **parse** converts a response into the hash of attributes to be `set` on
15737     // the model. The default implementation is just to pass the response along.
15738     parse: function(resp, options) {
15739       return resp;
15740     },
15741
15742     // Create a new model with identical attributes to this one.
15743     clone: function() {
15744       return new this.constructor(this.attributes);
15745     },
15746
15747     // A model is new if it has never been saved to the server, and lacks an id.
15748     isNew: function() {
15749       return this.id == null;
15750     },
15751
15752     // Check if the model is currently in a valid state.
15753     isValid: function(options) {
15754       return this._validate({}, _.extend(options || {}, { validate: true }));
15755     },
15756
15757     // Run validation against the next complete set of model attributes,
15758     // returning `true` if all is well. Otherwise, fire an `"invalid"` event.
15759     _validate: function(attrs, options) {
15760       if (!options.validate || !this.validate) return true;
15761       attrs = _.extend({}, this.attributes, attrs);
15762       var error = this.validationError = this.validate(attrs, options) || null;
15763       if (!error) return true;
15764       this.trigger('invalid', this, error, _.extend(options || {}, {validationError: error}));
15765       return false;
15766     }
15767
15768   });
15769
15770   // Underscore methods that we want to implement on the Model.
15771   var modelMethods = ['keys', 'values', 'pairs', 'invert', 'pick', 'omit'];
15772
15773   // Mix in each Underscore method as a proxy to `Model#attributes`.
15774   _.each(modelMethods, function(method) {
15775     Model.prototype[method] = function() {
15776       var args = slice.call(arguments);
15777       args.unshift(this.attributes);
15778       return _[method].apply(_, args);
15779     };
15780   });
15781
15782   // Backbone.Collection
15783   // -------------------
15784
15785   // If models tend to represent a single row of data, a Backbone Collection is
15786   // more analagous to a table full of data ... or a small slice or page of that
15787   // table, or a collection of rows that belong together for a particular reason
15788   // -- all of the messages in this particular folder, all of the documents
15789   // belonging to this particular author, and so on. Collections maintain
15790   // indexes of their models, both in order, and for lookup by `id`.
15791
15792   // Create a new **Collection**, perhaps to contain a specific type of `model`.
15793   // If a `comparator` is specified, the Collection will maintain
15794   // its models in sort order, as they're added and removed.
15795   var Collection = Backbone.Collection = function(models, options) {
15796     options || (options = {});
15797     if (options.url) this.url = options.url;
15798     if (options.model) this.model = options.model;
15799     if (options.comparator !== void 0) this.comparator = options.comparator;
15800     this._reset();
15801     this.initialize.apply(this, arguments);
15802     if (models) this.reset(models, _.extend({silent: true}, options));
15803   };
15804
15805   // Default options for `Collection#set`.
15806   var setOptions = {add: true, remove: true, merge: true};
15807   var addOptions = {add: true, merge: false, remove: false};
15808
15809   // Define the Collection's inheritable methods.
15810   _.extend(Collection.prototype, Events, {
15811
15812     // The default model for a collection is just a **Backbone.Model**.
15813     // This should be overridden in most cases.
15814     model: Model,
15815
15816     // Initialize is an empty function by default. Override it with your own
15817     // initialization logic.
15818     initialize: function(){},
15819
15820     // The JSON representation of a Collection is an array of the
15821     // models' attributes.
15822     toJSON: function(options) {
15823       return this.map(function(model){ return model.toJSON(options); });
15824     },
15825
15826     // Proxy `Backbone.sync` by default.
15827     sync: function() {
15828       return Backbone.sync.apply(this, arguments);
15829     },
15830
15831     // Add a model, or list of models to the set.
15832     add: function(models, options) {
15833       return this.set(models, _.defaults(options || {}, addOptions));
15834     },
15835
15836     // Remove a model, or a list of models from the set.
15837     remove: function(models, options) {
15838       models = _.isArray(models) ? models.slice() : [models];
15839       options || (options = {});
15840       var i, l, index, model;
15841       for (i = 0, l = models.length; i < l; i++) {
15842         model = this.get(models[i]);
15843         if (!model) continue;
15844         delete this._byId[model.id];
15845         delete this._byId[model.cid];
15846         index = this.indexOf(model);
15847         this.models.splice(index, 1);
15848         this.length--;
15849         if (!options.silent) {
15850           options.index = index;
15851           model.trigger('remove', model, this, options);
15852         }
15853         this._removeReference(model);
15854       }
15855       return this;
15856     },
15857
15858     // Update a collection by `set`-ing a new list of models, adding new ones,
15859     // removing models that are no longer present, and merging models that
15860     // already exist in the collection, as necessary. Similar to **Model#set**,
15861     // the core operation for updating the data contained by the collection.
15862     set: function(models, options) {
15863       options = _.defaults(options || {}, setOptions);
15864       if (options.parse) models = this.parse(models, options);
15865       if (!_.isArray(models)) models = models ? [models] : [];
15866       var i, l, model, attrs, existing, sort;
15867       var at = options.at;
15868       var sortable = this.comparator && (at == null) && options.sort !== false;
15869       var sortAttr = _.isString(this.comparator) ? this.comparator : null;
15870       var toAdd = [], toRemove = [], modelMap = {};
15871
15872       // Turn bare objects into model references, and prevent invalid models
15873       // from being added.
15874       for (i = 0, l = models.length; i < l; i++) {
15875         if (!(model = this._prepareModel(models[i], options))) continue;
15876
15877         // If a duplicate is found, prevent it from being added and
15878         // optionally merge it into the existing model.
15879         if (existing = this.get(model)) {
15880           if (options.remove) modelMap[existing.cid] = true;
15881           if (options.merge) {
15882             existing.set(model.attributes, options);
15883             if (sortable && !sort && existing.hasChanged(sortAttr)) sort = true;
15884           }
15885
15886         // This is a new model, push it to the `toAdd` list.
15887         } else if (options.add) {
15888           toAdd.push(model);
15889
15890           // Listen to added models' events, and index models for lookup by
15891           // `id` and by `cid`.
15892           model.on('all', this._onModelEvent, this);
15893           this._byId[model.cid] = model;
15894           if (model.id != null) this._byId[model.id] = model;
15895         }
15896       }
15897
15898       // Remove nonexistent models if appropriate.
15899       if (options.remove) {
15900         for (i = 0, l = this.length; i < l; ++i) {
15901           if (!modelMap[(model = this.models[i]).cid]) toRemove.push(model);
15902         }
15903         if (toRemove.length) this.remove(toRemove, options);
15904       }
15905
15906       // See if sorting is needed, update `length` and splice in new models.
15907       if (toAdd.length) {
15908         if (sortable) sort = true;
15909         this.length += toAdd.length;
15910         if (at != null) {
15911           splice.apply(this.models, [at, 0].concat(toAdd));
15912         } else {
15913           push.apply(this.models, toAdd);
15914         }
15915       }
15916
15917       // Silently sort the collection if appropriate.
15918       if (sort) this.sort({silent: true});
15919
15920       if (options.silent) return this;
15921
15922       // Trigger `add` events.
15923       for (i = 0, l = toAdd.length; i < l; i++) {
15924         (model = toAdd[i]).trigger('add', model, this, options);
15925       }
15926
15927       // Trigger `sort` if the collection was sorted.
15928       if (sort) this.trigger('sort', this, options);
15929       return this;
15930     },
15931
15932     // When you have more items than you want to add or remove individually,
15933     // you can reset the entire set with a new list of models, without firing
15934     // any granular `add` or `remove` events. Fires `reset` when finished.
15935     // Useful for bulk operations and optimizations.
15936     reset: function(models, options) {
15937       options || (options = {});
15938       for (var i = 0, l = this.models.length; i < l; i++) {
15939         this._removeReference(this.models[i]);
15940       }
15941       options.previousModels = this.models;
15942       this._reset();
15943       this.add(models, _.extend({silent: true}, options));
15944       if (!options.silent) this.trigger('reset', this, options);
15945       return this;
15946     },
15947
15948     // Add a model to the end of the collection.
15949     push: function(model, options) {
15950       model = this._prepareModel(model, options);
15951       this.add(model, _.extend({at: this.length}, options));
15952       return model;
15953     },
15954
15955     // Remove a model from the end of the collection.
15956     pop: function(options) {
15957       var model = this.at(this.length - 1);
15958       this.remove(model, options);
15959       return model;
15960     },
15961
15962     // Add a model to the beginning of the collection.
15963     unshift: function(model, options) {
15964       model = this._prepareModel(model, options);
15965       this.add(model, _.extend({at: 0}, options));
15966       return model;
15967     },
15968
15969     // Remove a model from the beginning of the collection.
15970     shift: function(options) {
15971       var model = this.at(0);
15972       this.remove(model, options);
15973       return model;
15974     },
15975
15976     // Slice out a sub-array of models from the collection.
15977     slice: function(begin, end) {
15978       return this.models.slice(begin, end);
15979     },
15980
15981     // Get a model from the set by id.
15982     get: function(obj) {
15983       if (obj == null) return void 0;
15984       return this._byId[obj.id != null ? obj.id : obj.cid || obj];
15985     },
15986
15987     // Get the model at the given index.
15988     at: function(index) {
15989       return this.models[index];
15990     },
15991
15992     // Return models with matching attributes. Useful for simple cases of
15993     // `filter`.
15994     where: function(attrs, first) {
15995       if (_.isEmpty(attrs)) return first ? void 0 : [];
15996       return this[first ? 'find' : 'filter'](function(model) {
15997         for (var key in attrs) {
15998           if (attrs[key] !== model.get(key)) return false;
15999         }
16000         return true;
16001       });
16002     },
16003
16004     // Return the first model with matching attributes. Useful for simple cases
16005     // of `find`.
16006     findWhere: function(attrs) {
16007       return this.where(attrs, true);
16008     },
16009
16010     // Force the collection to re-sort itself. You don't need to call this under
16011     // normal circumstances, as the set will maintain sort order as each item
16012     // is added.
16013     sort: function(options) {
16014       if (!this.comparator) throw new Error('Cannot sort a set without a comparator');
16015       options || (options = {});
16016
16017       // Run sort based on type of `comparator`.
16018       if (_.isString(this.comparator) || this.comparator.length === 1) {
16019         this.models = this.sortBy(this.comparator, this);
16020       } else {
16021         this.models.sort(_.bind(this.comparator, this));
16022       }
16023
16024       if (!options.silent) this.trigger('sort', this, options);
16025       return this;
16026     },
16027
16028     // Figure out the smallest index at which a model should be inserted so as
16029     // to maintain order.
16030     sortedIndex: function(model, value, context) {
16031       value || (value = this.comparator);
16032       var iterator = _.isFunction(value) ? value : function(model) {
16033         return model.get(value);
16034       };
16035       return _.sortedIndex(this.models, model, iterator, context);
16036     },
16037
16038     // Pluck an attribute from each model in the collection.
16039     pluck: function(attr) {
16040       return _.invoke(this.models, 'get', attr);
16041     },
16042
16043     // Fetch the default set of models for this collection, resetting the
16044     // collection when they arrive. If `reset: true` is passed, the response
16045     // data will be passed through the `reset` method instead of `set`.
16046     fetch: function(options) {
16047       options = options ? _.clone(options) : {};
16048       if (options.parse === void 0) options.parse = true;
16049       var success = options.success;
16050       var collection = this;
16051       options.success = function(resp) {
16052         var method = options.reset ? 'reset' : 'set';
16053         collection[method](resp, options);
16054         if (success) success(collection, resp, options);
16055         collection.trigger('sync', collection, resp, options);
16056       };
16057       wrapError(this, options);
16058       return this.sync('read', this, options);
16059     },
16060
16061     // Create a new instance of a model in this collection. Add the model to the
16062     // collection immediately, unless `wait: true` is passed, in which case we
16063     // wait for the server to agree.
16064     create: function(model, options) {
16065       options = options ? _.clone(options) : {};
16066       if (!(model = this._prepareModel(model, options))) return false;
16067       if (!options.wait) this.add(model, options);
16068       var collection = this;
16069       var success = options.success;
16070       options.success = function(resp) {
16071         if (options.wait) collection.add(model, options);
16072         if (success) success(model, resp, options);
16073       };
16074       model.save(null, options);
16075       return model;
16076     },
16077
16078     // **parse** converts a response into a list of models to be added to the
16079     // collection. The default implementation is just to pass it through.
16080     parse: function(resp, options) {
16081       return resp;
16082     },
16083
16084     // Create a new collection with an identical list of models as this one.
16085     clone: function() {
16086       return new this.constructor(this.models);
16087     },
16088
16089     // Private method to reset all internal state. Called when the collection
16090     // is first initialized or reset.
16091     _reset: function() {
16092       this.length = 0;
16093       this.models = [];
16094       this._byId  = {};
16095     },
16096
16097     // Prepare a hash of attributes (or other model) to be added to this
16098     // collection.
16099     _prepareModel: function(attrs, options) {
16100       if (attrs instanceof Model) {
16101         if (!attrs.collection) attrs.collection = this;
16102         return attrs;
16103       }
16104       options || (options = {});
16105       options.collection = this;
16106       var model = new this.model(attrs, options);
16107       if (!model._validate(attrs, options)) {
16108         this.trigger('invalid', this, attrs, options);
16109         return false;
16110       }
16111       return model;
16112     },
16113
16114     // Internal method to sever a model's ties to a collection.
16115     _removeReference: function(model) {
16116       if (this === model.collection) delete model.collection;
16117       model.off('all', this._onModelEvent, this);
16118     },
16119
16120     // Internal method called every time a model in the set fires an event.
16121     // Sets need to update their indexes when models change ids. All other
16122     // events simply proxy through. "add" and "remove" events that originate
16123     // in other collections are ignored.
16124     _onModelEvent: function(event, model, collection, options) {
16125       if ((event === 'add' || event === 'remove') && collection !== this) return;
16126       if (event === 'destroy') this.remove(model, options);
16127       if (model && event === 'change:' + model.idAttribute) {
16128         delete this._byId[model.previous(model.idAttribute)];
16129         if (model.id != null) this._byId[model.id] = model;
16130       }
16131       this.trigger.apply(this, arguments);
16132     }
16133
16134   });
16135
16136   // Underscore methods that we want to implement on the Collection.
16137   // 90% of the core usefulness of Backbone Collections is actually implemented
16138   // right here:
16139   var methods = ['forEach', 'each', 'map', 'collect', 'reduce', 'foldl',
16140     'inject', 'reduceRight', 'foldr', 'find', 'detect', 'filter', 'select',
16141     'reject', 'every', 'all', 'some', 'any', 'include', 'contains', 'invoke',
16142     'max', 'min', 'toArray', 'size', 'first', 'head', 'take', 'initial', 'rest',
16143     'tail', 'drop', 'last', 'without', 'indexOf', 'shuffle', 'lastIndexOf',
16144     'isEmpty', 'chain'];
16145
16146   // Mix in each Underscore method as a proxy to `Collection#models`.
16147   _.each(methods, function(method) {
16148     Collection.prototype[method] = function() {
16149       var args = slice.call(arguments);
16150       args.unshift(this.models);
16151       return _[method].apply(_, args);
16152     };
16153   });
16154
16155   // Underscore methods that take a property name as an argument.
16156   var attributeMethods = ['groupBy', 'countBy', 'sortBy'];
16157
16158   // Use attributes instead of properties.
16159   _.each(attributeMethods, function(method) {
16160     Collection.prototype[method] = function(value, context) {
16161       var iterator = _.isFunction(value) ? value : function(model) {
16162         return model.get(value);
16163       };
16164       return _[method](this.models, iterator, context);
16165     };
16166   });
16167
16168   // Backbone.View
16169   // -------------
16170
16171   // Backbone Views are almost more convention than they are actual code. A View
16172   // is simply a JavaScript object that represents a logical chunk of UI in the
16173   // DOM. This might be a single item, an entire list, a sidebar or panel, or
16174   // even the surrounding frame which wraps your whole app. Defining a chunk of
16175   // UI as a **View** allows you to define your DOM events declaratively, without
16176   // having to worry about render order ... and makes it easy for the view to
16177   // react to specific changes in the state of your models.
16178
16179   // Creating a Backbone.View creates its initial element outside of the DOM,
16180   // if an existing element is not provided...
16181   var View = Backbone.View = function(options) {
16182     this.cid = _.uniqueId('view');
16183     this._configure(options || {});
16184     this._ensureElement();
16185     this.initialize.apply(this, arguments);
16186     this.delegateEvents();
16187   };
16188
16189   // Cached regex to split keys for `delegate`.
16190   var delegateEventSplitter = /^(\S+)\s*(.*)$/;
16191
16192   // List of view options to be merged as properties.
16193   var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName', 'events'];
16194
16195   // Set up all inheritable **Backbone.View** properties and methods.
16196   _.extend(View.prototype, Events, {
16197
16198     // The default `tagName` of a View's element is `"div"`.
16199     tagName: 'div',
16200
16201     // jQuery delegate for element lookup, scoped to DOM elements within the
16202     // current view. This should be prefered to global lookups where possible.
16203     $: function(selector) {
16204       return this.$el.find(selector);
16205     },
16206
16207     // Initialize is an empty function by default. Override it with your own
16208     // initialization logic.
16209     initialize: function(){},
16210
16211     // **render** is the core function that your view should override, in order
16212     // to populate its element (`this.el`), with the appropriate HTML. The
16213     // convention is for **render** to always return `this`.
16214     render: function() {
16215       return this;
16216     },
16217
16218     // Remove this view by taking the element out of the DOM, and removing any
16219     // applicable Backbone.Events listeners.
16220     remove: function() {
16221       this.$el.remove();
16222       this.stopListening();
16223       return this;
16224     },
16225
16226     // Change the view's element (`this.el` property), including event
16227     // re-delegation.
16228     setElement: function(element, delegate) {
16229       if (this.$el) this.undelegateEvents();
16230       this.$el = element instanceof Backbone.$ ? element : Backbone.$(element);
16231       this.el = this.$el[0];
16232       if (delegate !== false) this.delegateEvents();
16233       return this;
16234     },
16235
16236     // Set callbacks, where `this.events` is a hash of
16237     //
16238     // *{"event selector": "callback"}*
16239     //
16240     //     {
16241     //       'mousedown .title':  'edit',
16242     //       'click .button':     'save'
16243     //       'click .open':       function(e) { ... }
16244     //     }
16245     //
16246     // pairs. Callbacks will be bound to the view, with `this` set properly.
16247     // Uses event delegation for efficiency.
16248     // Omitting the selector binds the event to `this.el`.
16249     // This only works for delegate-able events: not `focus`, `blur`, and
16250     // not `change`, `submit`, and `reset` in Internet Explorer.
16251     delegateEvents: function(events) {
16252       if (!(events || (events = _.result(this, 'events')))) return this;
16253       this.undelegateEvents();
16254       for (var key in events) {
16255         var method = events[key];
16256         if (!_.isFunction(method)) method = this[events[key]];
16257         if (!method) continue;
16258
16259         var match = key.match(delegateEventSplitter);
16260         var eventName = match[1], selector = match[2];
16261         method = _.bind(method, this);
16262         eventName += '.delegateEvents' + this.cid;
16263         if (selector === '') {
16264           this.$el.on(eventName, method);
16265         } else {
16266           this.$el.on(eventName, selector, method);
16267         }
16268       }
16269       return this;
16270     },
16271
16272     // Clears all callbacks previously bound to the view with `delegateEvents`.
16273     // You usually don't need to use this, but may wish to if you have multiple
16274     // Backbone views attached to the same DOM element.
16275     undelegateEvents: function() {
16276       this.$el.off('.delegateEvents' + this.cid);
16277       return this;
16278     },
16279
16280     // Performs the initial configuration of a View with a set of options.
16281     // Keys with special meaning *(e.g. model, collection, id, className)* are
16282     // attached directly to the view.  See `viewOptions` for an exhaustive
16283     // list.
16284     _configure: function(options) {
16285       if (this.options) options = _.extend({}, _.result(this, 'options'), options);
16286       _.extend(this, _.pick(options, viewOptions));
16287       this.options = options;
16288     },
16289
16290     // Ensure that the View has a DOM element to render into.
16291     // If `this.el` is a string, pass it through `$()`, take the first
16292     // matching element, and re-assign it to `el`. Otherwise, create
16293     // an element from the `id`, `className` and `tagName` properties.
16294     _ensureElement: function() {
16295       if (!this.el) {
16296         var attrs = _.extend({}, _.result(this, 'attributes'));
16297         if (this.id) attrs.id = _.result(this, 'id');
16298         if (this.className) attrs['class'] = _.result(this, 'className');
16299         var $el = Backbone.$('<' + _.result(this, 'tagName') + '>').attr(attrs);
16300         this.setElement($el, false);
16301       } else {
16302         this.setElement(_.result(this, 'el'), false);
16303       }
16304     }
16305
16306   });
16307
16308   // Backbone.sync
16309   // -------------
16310
16311   // Override this function to change the manner in which Backbone persists
16312   // models to the server. You will be passed the type of request, and the
16313   // model in question. By default, makes a RESTful Ajax request
16314   // to the model's `url()`. Some possible customizations could be:
16315   //
16316   // * Use `setTimeout` to batch rapid-fire updates into a single request.
16317   // * Send up the models as XML instead of JSON.
16318   // * Persist models via WebSockets instead of Ajax.
16319   //
16320   // Turn on `Backbone.emulateHTTP` in order to send `PUT` and `DELETE` requests
16321   // as `POST`, with a `_method` parameter containing the true HTTP method,
16322   // as well as all requests with the body as `application/x-www-form-urlencoded`
16323   // instead of `application/json` with the model in a param named `model`.
16324   // Useful when interfacing with server-side languages like **PHP** that make
16325   // it difficult to read the body of `PUT` requests.
16326   Backbone.sync = function(method, model, options) {
16327     var type = methodMap[method];
16328
16329     // Default options, unless specified.
16330     _.defaults(options || (options = {}), {
16331       emulateHTTP: Backbone.emulateHTTP,
16332       emulateJSON: Backbone.emulateJSON
16333     });
16334
16335     // Default JSON-request options.
16336     var params = {type: type, dataType: 'json'};
16337
16338     // Ensure that we have a URL.
16339     if (!options.url) {
16340       params.url = _.result(model, 'url') || urlError();
16341     }
16342
16343     // Ensure that we have the appropriate request data.
16344     if (options.data == null && model && (method === 'create' || method === 'update' || method === 'patch')) {
16345       params.contentType = 'application/json';
16346       params.data = JSON.stringify(options.attrs || model.toJSON(options));
16347     }
16348
16349     // For older servers, emulate JSON by encoding the request into an HTML-form.
16350     if (options.emulateJSON) {
16351       params.contentType = 'application/x-www-form-urlencoded';
16352       params.data = params.data ? {model: params.data} : {};
16353     }
16354
16355     // For older servers, emulate HTTP by mimicking the HTTP method with `_method`
16356     // And an `X-HTTP-Method-Override` header.
16357     if (options.emulateHTTP && (type === 'PUT' || type === 'DELETE' || type === 'PATCH')) {
16358       params.type = 'POST';
16359       if (options.emulateJSON) params.data._method = type;
16360       var beforeSend = options.beforeSend;
16361       options.beforeSend = function(xhr) {
16362         xhr.setRequestHeader('X-HTTP-Method-Override', type);
16363         if (beforeSend) return beforeSend.apply(this, arguments);
16364       };
16365     }
16366
16367     // Don't process data on a non-GET request.
16368     if (params.type !== 'GET' && !options.emulateJSON) {
16369       params.processData = false;
16370     }
16371
16372     // If we're sending a `PATCH` request, and we're in an old Internet Explorer
16373     // that still has ActiveX enabled by default, override jQuery to use that
16374     // for XHR instead. Remove this line when jQuery supports `PATCH` on IE8.
16375     if (params.type === 'PATCH' && window.ActiveXObject &&
16376           !(window.external && window.external.msActiveXFilteringEnabled)) {
16377       params.xhr = function() {
16378         return new ActiveXObject("Microsoft.XMLHTTP");
16379       };
16380     }
16381
16382     // Make the request, allowing the user to override any Ajax options.
16383     var xhr = options.xhr = Backbone.ajax(_.extend(params, options));
16384     model.trigger('request', model, xhr, options);
16385     return xhr;
16386   };
16387
16388   // Map from CRUD to HTTP for our default `Backbone.sync` implementation.
16389   var methodMap = {
16390     'create': 'POST',
16391     'update': 'PUT',
16392     'patch':  'PATCH',
16393     'delete': 'DELETE',
16394     'read':   'GET'
16395   };
16396
16397   // Set the default implementation of `Backbone.ajax` to proxy through to `$`.
16398   // Override this if you'd like to use a different library.
16399   Backbone.ajax = function() {
16400     return Backbone.$.ajax.apply(Backbone.$, arguments);
16401   };
16402
16403   // Backbone.Router
16404   // ---------------
16405
16406   // Routers map faux-URLs to actions, and fire events when routes are
16407   // matched. Creating a new one sets its `routes` hash, if not set statically.
16408   var Router = Backbone.Router = function(options) {
16409     options || (options = {});
16410     if (options.routes) this.routes = options.routes;
16411     this._bindRoutes();
16412     this.initialize.apply(this, arguments);
16413   };
16414
16415   // Cached regular expressions for matching named param parts and splatted
16416   // parts of route strings.
16417   var optionalParam = /\((.*?)\)/g;
16418   var namedParam    = /(\(\?)?:\w+/g;
16419   var splatParam    = /\*\w+/g;
16420   var escapeRegExp  = /[\-{}\[\]+?.,\\\^$|#\s]/g;
16421
16422   // Set up all inheritable **Backbone.Router** properties and methods.
16423   _.extend(Router.prototype, Events, {
16424
16425     // Initialize is an empty function by default. Override it with your own
16426     // initialization logic.
16427     initialize: function(){},
16428
16429     // Manually bind a single named route to a callback. For example:
16430     //
16431     //     this.route('search/:query/p:num', 'search', function(query, num) {
16432     //       ...
16433     //     });
16434     //
16435     route: function(route, name, callback) {
16436       if (!_.isRegExp(route)) route = this._routeToRegExp(route);
16437       if (_.isFunction(name)) {
16438         callback = name;
16439         name = '';
16440       }
16441       if (!callback) callback = this[name];
16442       var router = this;
16443       Backbone.history.route(route, function(fragment) {
16444         var args = router._extractParameters(route, fragment);
16445         callback && callback.apply(router, args);
16446         router.trigger.apply(router, ['route:' + name].concat(args));
16447         router.trigger('route', name, args);
16448         Backbone.history.trigger('route', router, name, args);
16449       });
16450       return this;
16451     },
16452
16453     // Simple proxy to `Backbone.history` to save a fragment into the history.
16454     navigate: function(fragment, options) {
16455       Backbone.history.navigate(fragment, options);
16456       return this;
16457     },
16458
16459     // Bind all defined routes to `Backbone.history`. We have to reverse the
16460     // order of the routes here to support behavior where the most general
16461     // routes can be defined at the bottom of the route map.
16462     _bindRoutes: function() {
16463       if (!this.routes) return;
16464       this.routes = _.result(this, 'routes');
16465       var route, routes = _.keys(this.routes);
16466       while ((route = routes.pop()) != null) {
16467         this.route(route, this.routes[route]);
16468       }
16469     },
16470
16471     // Convert a route string into a regular expression, suitable for matching
16472     // against the current location hash.
16473     _routeToRegExp: function(route) {
16474       route = route.replace(escapeRegExp, '\\$&')
16475                    .replace(optionalParam, '(?:$1)?')
16476                    .replace(namedParam, function(match, optional){
16477                      return optional ? match : '([^\/]+)';
16478                    })
16479                    .replace(splatParam, '(.*?)');
16480       return new RegExp('^' + route + '$');
16481     },
16482
16483     // Given a route, and a URL fragment that it matches, return the array of
16484     // extracted decoded parameters. Empty or unmatched parameters will be
16485     // treated as `null` to normalize cross-browser behavior.
16486     _extractParameters: function(route, fragment) {
16487       var params = route.exec(fragment).slice(1);
16488       return _.map(params, function(param) {
16489         return param ? decodeURIComponent(param) : null;
16490       });
16491     }
16492
16493   });
16494
16495   // Backbone.History
16496   // ----------------
16497
16498   // Handles cross-browser history management, based on either
16499   // [pushState](http://diveintohtml5.info/history.html) and real URLs, or
16500   // [onhashchange](https://developer.mozilla.org/en-US/docs/DOM/window.onhashchange)
16501   // and URL fragments. If the browser supports neither (old IE, natch),
16502   // falls back to polling.
16503   var History = Backbone.History = function() {
16504     this.handlers = [];
16505     _.bindAll(this, 'checkUrl');
16506
16507     // Ensure that `History` can be used outside of the browser.
16508     if (typeof window !== 'undefined') {
16509       this.location = window.location;
16510       this.history = window.history;
16511     }
16512   };
16513
16514   // Cached regex for stripping a leading hash/slash and trailing space.
16515   var routeStripper = /^[#\/]|\s+$/g;
16516
16517   // Cached regex for stripping leading and trailing slashes.
16518   var rootStripper = /^\/+|\/+$/g;
16519
16520   // Cached regex for detecting MSIE.
16521   var isExplorer = /msie [\w.]+/;
16522
16523   // Cached regex for removing a trailing slash.
16524   var trailingSlash = /\/$/;
16525
16526   // Has the history handling already been started?
16527   History.started = false;
16528
16529   // Set up all inheritable **Backbone.History** properties and methods.
16530   _.extend(History.prototype, Events, {
16531
16532     // The default interval to poll for hash changes, if necessary, is
16533     // twenty times a second.
16534     interval: 50,
16535
16536     // Gets the true hash value. Cannot use location.hash directly due to bug
16537     // in Firefox where location.hash will always be decoded.
16538     getHash: function(window) {
16539       var match = (window || this).location.href.match(/#(.*)$/);
16540       return match ? match[1] : '';
16541     },
16542
16543     // Get the cross-browser normalized URL fragment, either from the URL,
16544     // the hash, or the override.
16545     getFragment: function(fragment, forcePushState) {
16546       if (fragment == null) {
16547         if (this._hasPushState || !this._wantsHashChange || forcePushState) {
16548           fragment = this.location.pathname;
16549           var root = this.root.replace(trailingSlash, '');
16550           if (!fragment.indexOf(root)) fragment = fragment.substr(root.length);
16551         } else {
16552           fragment = this.getHash();
16553         }
16554       }
16555       return fragment.replace(routeStripper, '');
16556     },
16557
16558     // Start the hash change handling, returning `true` if the current URL matches
16559     // an existing route, and `false` otherwise.
16560     start: function(options) {
16561       if (History.started) throw new Error("Backbone.history has already been started");
16562       History.started = true;
16563
16564       // Figure out the initial configuration. Do we need an iframe?
16565       // Is pushState desired ... is it available?
16566       this.options          = _.extend({}, {root: '/'}, this.options, options);
16567       this.root             = this.options.root;
16568       this._wantsHashChange = this.options.hashChange !== false;
16569       this._wantsPushState  = !!this.options.pushState;
16570       this._hasPushState    = !!(this.options.pushState && this.history && this.history.pushState);
16571       var fragment          = this.getFragment();
16572       var docMode           = document.documentMode;
16573       var oldIE             = (isExplorer.exec(navigator.userAgent.toLowerCase()) && (!docMode || docMode <= 7));
16574
16575       // Normalize root to always include a leading and trailing slash.
16576       this.root = ('/' + this.root + '/').replace(rootStripper, '/');
16577
16578       if (oldIE && this._wantsHashChange) {
16579         this.iframe = Backbone.$('<iframe src="javascript:0" tabindex="-1" />').hide().appendTo('body')[0].contentWindow;
16580         this.navigate(fragment);
16581       }
16582
16583       // Depending on whether we're using pushState or hashes, and whether
16584       // 'onhashchange' is supported, determine how we check the URL state.
16585       if (this._hasPushState) {
16586         Backbone.$(window).on('popstate', this.checkUrl);
16587       } else if (this._wantsHashChange && ('onhashchange' in window) && !oldIE) {
16588         Backbone.$(window).on('hashchange', this.checkUrl);
16589       } else if (this._wantsHashChange) {
16590         this._checkUrlInterval = setInterval(this.checkUrl, this.interval);
16591       }
16592
16593       // Determine if we need to change the base url, for a pushState link
16594       // opened by a non-pushState browser.
16595       this.fragment = fragment;
16596       var loc = this.location;
16597       var atRoot = loc.pathname.replace(/[^\/]$/, '$&/') === this.root;
16598
16599       // If we've started off with a route from a `pushState`-enabled browser,
16600       // but we're currently in a browser that doesn't support it...
16601       if (this._wantsHashChange && this._wantsPushState && !this._hasPushState && !atRoot) {
16602         this.fragment = this.getFragment(null, true);
16603         this.location.replace(this.root + this.location.search + '#' + this.fragment);
16604         // Return immediately as browser will do redirect to new url
16605         return true;
16606
16607       // Or if we've started out with a hash-based route, but we're currently
16608       // in a browser where it could be `pushState`-based instead...
16609       } else if (this._wantsPushState && this._hasPushState && atRoot && loc.hash) {
16610         this.fragment = this.getHash().replace(routeStripper, '');
16611         this.history.replaceState({}, document.title, this.root + this.fragment + loc.search);
16612       }
16613
16614       if (!this.options.silent) return this.loadUrl();
16615     },
16616
16617     // Disable Backbone.history, perhaps temporarily. Not useful in a real app,
16618     // but possibly useful for unit testing Routers.
16619     stop: function() {
16620       Backbone.$(window).off('popstate', this.checkUrl).off('hashchange', this.checkUrl);
16621       clearInterval(this._checkUrlInterval);
16622       History.started = false;
16623     },
16624
16625     // Add a route to be tested when the fragment changes. Routes added later
16626     // may override previous routes.
16627     route: function(route, callback) {
16628       this.handlers.unshift({route: route, callback: callback});
16629     },
16630
16631     // Checks the current URL to see if it has changed, and if it has,
16632     // calls `loadUrl`, normalizing across the hidden iframe.
16633     checkUrl: function(e) {
16634       var current = this.getFragment();
16635       if (current === this.fragment && this.iframe) {
16636         current = this.getFragment(this.getHash(this.iframe));
16637       }
16638       if (current === this.fragment) return false;
16639       if (this.iframe) this.navigate(current);
16640       this.loadUrl() || this.loadUrl(this.getHash());
16641     },
16642
16643     // Attempt to load the current URL fragment. If a route succeeds with a
16644     // match, returns `true`. If no defined routes matches the fragment,
16645     // returns `false`.
16646     loadUrl: function(fragmentOverride) {
16647       var fragment = this.fragment = this.getFragment(fragmentOverride);
16648       var matched = _.any(this.handlers, function(handler) {
16649         if (handler.route.test(fragment)) {
16650           handler.callback(fragment);
16651           return true;
16652         }
16653       });
16654       return matched;
16655     },
16656
16657     // Save a fragment into the hash history, or replace the URL state if the
16658     // 'replace' option is passed. You are responsible for properly URL-encoding
16659     // the fragment in advance.
16660     //
16661     // The options object can contain `trigger: true` if you wish to have the
16662     // route callback be fired (not usually desirable), or `replace: true`, if
16663     // you wish to modify the current URL without adding an entry to the history.
16664     navigate: function(fragment, options) {
16665       if (!History.started) return false;
16666       if (!options || options === true) options = {trigger: options};
16667       fragment = this.getFragment(fragment || '');
16668       if (this.fragment === fragment) return;
16669       this.fragment = fragment;
16670       var url = this.root + fragment;
16671
16672       // If pushState is available, we use it to set the fragment as a real URL.
16673       if (this._hasPushState) {
16674         this.history[options.replace ? 'replaceState' : 'pushState']({}, document.title, url);
16675
16676       // If hash changes haven't been explicitly disabled, update the hash
16677       // fragment to store history.
16678       } else if (this._wantsHashChange) {
16679         this._updateHash(this.location, fragment, options.replace);
16680         if (this.iframe && (fragment !== this.getFragment(this.getHash(this.iframe)))) {
16681           // Opening and closing the iframe tricks IE7 and earlier to push a
16682           // history entry on hash-tag change.  When replace is true, we don't
16683           // want this.
16684           if(!options.replace) this.iframe.document.open().close();
16685           this._updateHash(this.iframe.location, fragment, options.replace);
16686         }
16687
16688       // If you've told us that you explicitly don't want fallback hashchange-
16689       // based history, then `navigate` becomes a page refresh.
16690       } else {
16691         return this.location.assign(url);
16692       }
16693       if (options.trigger) this.loadUrl(fragment);
16694     },
16695
16696     // Update the hash location, either replacing the current entry, or adding
16697     // a new one to the browser history.
16698     _updateHash: function(location, fragment, replace) {
16699       if (replace) {
16700         var href = location.href.replace(/(javascript:|#).*$/, '');
16701         location.replace(href + '#' + fragment);
16702       } else {
16703         // Some browsers require that `hash` contains a leading #.
16704         location.hash = '#' + fragment;
16705       }
16706     }
16707
16708   });
16709
16710   // Create the default Backbone.history.
16711   Backbone.history = new History;
16712
16713   // Helpers
16714   // -------
16715
16716   // Helper function to correctly set up the prototype chain, for subclasses.
16717   // Similar to `goog.inherits`, but uses a hash of prototype properties and
16718   // class properties to be extended.
16719   var extend = function(protoProps, staticProps) {
16720     var parent = this;
16721     var child;
16722
16723     // The constructor function for the new subclass is either defined by you
16724     // (the "constructor" property in your `extend` definition), or defaulted
16725     // by us to simply call the parent's constructor.
16726     if (protoProps && _.has(protoProps, 'constructor')) {
16727       child = protoProps.constructor;
16728     } else {
16729       child = function(){ return parent.apply(this, arguments); };
16730     }
16731
16732     // Add static properties to the constructor function, if supplied.
16733     _.extend(child, parent, staticProps);
16734
16735     // Set the prototype chain to inherit from `parent`, without calling
16736     // `parent`'s constructor function.
16737     var Surrogate = function(){ this.constructor = child; };
16738     Surrogate.prototype = parent.prototype;
16739     child.prototype = new Surrogate;
16740
16741     // Add prototype properties (instance properties) to the subclass,
16742     // if supplied.
16743     if (protoProps) _.extend(child.prototype, protoProps);
16744
16745     // Set a convenience property in case the parent's prototype is needed
16746     // later.
16747     child.__super__ = parent.prototype;
16748
16749     return child;
16750   };
16751
16752   // Set up inheritance for the model, collection, router, view and history.
16753   Model.extend = Collection.extend = Router.extend = View.extend = History.extend = extend;
16754
16755   // Throw an error when a URL is needed, and none is supplied.
16756   var urlError = function() {
16757     throw new Error('A "url" property or function must be specified');
16758   };
16759
16760   // Wrap an optional error callback with a fallback error event.
16761   var wrapError = function (model, options) {
16762     var error = options.error;
16763     options.error = function(resp) {
16764       if (error) error(model, resp, options);
16765       model.trigger('error', model, resp, options);
16766     };
16767   };
16768
16769 }).call(this);
16770
16771 // Vectorizer.
16772 // -----------
16773
16774 // A tiny library for making your live easier when dealing with SVG.
16775
16776 // Copyright Â© 2012 - 2014 client IO (http://client.io)
16777
16778 (function(root, factory) {
16779
16780     if (typeof define === 'function' && define.amd) {
16781         // AMD. Register as an anonymous module.
16782         define([], factory);
16783         
16784     } else {
16785         // Browser globals.
16786         root.Vectorizer = root.V = factory();
16787     }
16788
16789 }(this, function() {
16790
16791     // Well, if SVG is not supported, this library is useless.
16792     var SVGsupported = !!(window.SVGAngle || document.implementation.hasFeature('http://www.w3.org/TR/SVG11/feature#BasicStructure', '1.1'));
16793
16794     // XML namespaces.
16795     var ns = {
16796         xmlns: 'http://www.w3.org/2000/svg',
16797         xlink: 'http://www.w3.org/1999/xlink'
16798     };
16799     // SVG version.
16800     var SVGversion = '1.1';
16801
16802     // A function returning a unique identifier for this client session with every call.
16803     var idCounter = 0;
16804     function uniqueId() {
16805         var id = ++idCounter + '';
16806         return 'v-' + id;
16807     }
16808
16809     // Create SVG element.
16810     // -------------------
16811
16812     function createElement(el, attrs, children) {
16813
16814         if (!el) return undefined;
16815         
16816         // If `el` is an object, it is probably a native SVG element. Wrap it to VElement.
16817         if (typeof el === 'object') {
16818             return new VElement(el);
16819         }
16820         attrs = attrs || {};
16821
16822         // If `el` is a `'svg'` or `'SVG'` string, create a new SVG canvas.
16823         if (el.toLowerCase() === 'svg') {
16824             
16825             attrs.xmlns = ns.xmlns;
16826             attrs['xmlns:xlink'] = ns.xlink;
16827             attrs.version = SVGversion;
16828             
16829         } else if (el[0] === '<') {
16830             // Create element from an SVG string.
16831             // Allows constructs of type: `document.appendChild(Vectorizer('<rect></rect>').node)`.
16832             
16833             var svg = '<svg xmlns="' + ns.xmlns + '" xmlns:xlink="' + ns.xlink + '" version="' + SVGversion + '">' + el + '</svg>';
16834             var parser = new DOMParser();
16835             parser.async = false;
16836             var svgDoc = parser.parseFromString(svg, 'text/xml').documentElement;
16837
16838             // Note that `createElement()` might also return an array should the SVG string passed as
16839             // the first argument contain more then one root element.
16840             if (svgDoc.childNodes.length > 1) {
16841
16842                 // Map child nodes to `VElement`s.
16843                 var ret = [];
16844                 for (var i = 0, len = svgDoc.childNodes.length; i < len; i++) {
16845
16846                     var childNode = svgDoc.childNodes[i];
16847                     ret.push(new VElement(document.importNode(childNode, true)));
16848                 }
16849                 return ret;
16850             }
16851             
16852             return new VElement(document.importNode(svgDoc.firstChild, true));
16853         }
16854         
16855         el = document.createElementNS(ns.xmlns, el);
16856
16857         // Set attributes.
16858         for (var key in attrs) {
16859
16860             setAttribute(el, key, attrs[key]);
16861         }
16862         
16863         // Normalize `children` array.
16864         if (Object.prototype.toString.call(children) != '[object Array]') children = [children];
16865
16866         // Append children if they are specified.
16867         var i = 0, len = (children[0] && children.length) || 0, child;
16868         for (; i < len; i++) {
16869             child = children[i];
16870             el.appendChild(child instanceof VElement ? child.node : child);
16871         }
16872         
16873         return new VElement(el);
16874     }
16875
16876     function setAttribute(el, name, value) {
16877         
16878         if (name.indexOf(':') > -1) {
16879             // Attribute names can be namespaced. E.g. `image` elements
16880             // have a `xlink:href` attribute to set the source of the image.
16881             var combinedKey = name.split(':');
16882             el.setAttributeNS(ns[combinedKey[0]], combinedKey[1], value);
16883         } else if (name === 'id') {
16884             el.id = value;
16885         } else {
16886             el.setAttribute(name, value);
16887         }
16888     }
16889
16890     function parseTransformString(transform) {
16891         var translate,
16892             rotate,
16893             scale;
16894         
16895         if (transform) {
16896             var translateMatch = transform.match(/translate\((.*)\)/);
16897             if (translateMatch) {
16898                 translate = translateMatch[1].split(',');
16899             }
16900             var rotateMatch = transform.match(/rotate\((.*)\)/);
16901             if (rotateMatch) {
16902                 rotate = rotateMatch[1].split(',');
16903             }
16904             var scaleMatch = transform.match(/scale\((.*)\)/);
16905             if (scaleMatch) {
16906                 scale = scaleMatch[1].split(',');
16907             }
16908         }
16909
16910         var sx = (scale && scale[0]) ? parseFloat(scale[0]) : 1;
16911         
16912         return {
16913             translate: {
16914                 tx: (translate && translate[0]) ? parseInt(translate[0], 10) : 0,
16915                 ty: (translate && translate[1]) ? parseInt(translate[1], 10) : 0
16916             },
16917             rotate: {
16918                 angle: (rotate && rotate[0]) ? parseInt(rotate[0], 10) : 0,
16919                 cx: (rotate && rotate[1]) ? parseInt(rotate[1], 10) : undefined,
16920                 cy: (rotate && rotate[2]) ? parseInt(rotate[2], 10) : undefined
16921             },
16922             scale: {
16923                 sx: sx,
16924                 sy: (scale && scale[1]) ? parseFloat(scale[1]) : sx
16925             }
16926         };
16927     }
16928
16929
16930     // Matrix decomposition.
16931     // ---------------------
16932
16933     function deltaTransformPoint(matrix, point)  {
16934         
16935         var dx = point.x * matrix.a + point.y * matrix.c + 0;
16936         var dy = point.x * matrix.b + point.y * matrix.d + 0;
16937         return { x: dx, y: dy };
16938     }
16939
16940     function decomposeMatrix(matrix) {
16941
16942         // @see https://gist.github.com/2052247
16943         
16944         // calculate delta transform point
16945         var px = deltaTransformPoint(matrix, { x: 0, y: 1 });
16946         var py = deltaTransformPoint(matrix, { x: 1, y: 0 });
16947         
16948         // calculate skew
16949         var skewX = ((180 / Math.PI) * Math.atan2(px.y, px.x) - 90);
16950         var skewY = ((180 / Math.PI) * Math.atan2(py.y, py.x));
16951         
16952         return {
16953             
16954             translateX: matrix.e,
16955             translateY: matrix.f,
16956             scaleX: Math.sqrt(matrix.a * matrix.a + matrix.b * matrix.b),
16957             scaleY: Math.sqrt(matrix.c * matrix.c + matrix.d * matrix.d),
16958             skewX: skewX,
16959             skewY: skewY,
16960             rotation: skewX // rotation is the same as skew x
16961         };
16962     }
16963     
16964     // VElement.
16965     // ---------
16966
16967     function VElement(el) {
16968         this.node = el;
16969         if (!this.node.id) {
16970             this.node.id = uniqueId();
16971         }
16972     }
16973
16974     // VElement public API.
16975     // --------------------
16976
16977     VElement.prototype = {
16978         
16979         translate: function(tx, ty) {
16980             ty = ty || 0;
16981             
16982             var transformAttr = this.attr('transform') || '',
16983                 transform = parseTransformString(transformAttr);
16984
16985             // Is it a getter?
16986             if (typeof tx === 'undefined') {
16987                 return transform.translate;
16988             }
16989             
16990             transformAttr = transformAttr.replace(/translate\([^\)]*\)/g, '').trim();
16991
16992             var newTx = transform.translate.tx + tx,
16993                 newTy = transform.translate.ty + ty;
16994
16995             // Note that `translate()` is always the first transformation. This is
16996             // usually the desired case.
16997             this.attr('transform', 'translate(' + newTx + ',' + newTy + ') ' + transformAttr);
16998             return this;
16999         },
17000
17001         rotate: function(angle, cx, cy) {
17002             var transformAttr = this.attr('transform') || '',
17003                 transform = parseTransformString(transformAttr);
17004
17005             // Is it a getter?
17006             if (typeof angle === 'undefined') {
17007                 return transform.rotate;
17008             }
17009             
17010             transformAttr = transformAttr.replace(/rotate\([^\)]*\)/g, '').trim();
17011
17012             var newAngle = transform.rotate.angle + angle % 360,
17013                 newOrigin = (cx !== undefined && cy !== undefined) ? ',' + cx + ',' + cy : '';
17014             
17015             this.attr('transform', transformAttr + ' rotate(' + newAngle + newOrigin + ')');
17016             return this;
17017         },
17018
17019         // Note that `scale` as the only transformation does not combine with previous values.
17020         scale: function(sx, sy) {
17021             sy = (typeof sy === 'undefined') ? sx : sy;
17022             
17023             var transformAttr = this.attr('transform') || '',
17024                 transform = parseTransformString(transformAttr);
17025
17026             // Is it a getter?
17027             if (typeof sx === 'undefined') {
17028                 return transform.scale;
17029             }
17030             
17031             transformAttr = transformAttr.replace(/scale\([^\)]*\)/g, '').trim();
17032
17033             this.attr('transform', transformAttr + ' scale(' + sx + ',' + sy + ')');
17034             return this;
17035         },
17036
17037         // Get SVGRect that contains coordinates and dimension of the real bounding box,
17038         // i.e. after transformations are applied.
17039         // If `target` is specified, bounding box will be computed relatively to `target` element.
17040         bbox: function(withoutTransformations, target) {
17041
17042             // If the element is not in the live DOM, it does not have a bounding box defined and
17043             // so fall back to 'zero' dimension element.
17044             if (!this.node.ownerSVGElement) return { x: 0, y: 0, width: 0, height: 0 };
17045             
17046             var box;
17047             try {
17048
17049                 box = this.node.getBBox();
17050
17051                 // Opera returns infinite values in some cases.
17052                 // Note that Infinity | 0 produces 0 as opposed to Infinity || 0.
17053                 // We also have to create new object as the standard says that you can't
17054                 // modify the attributes of a bbox.
17055                 box = { x: box.x | 0, y: box.y | 0, width: box.width | 0, height: box.height | 0};
17056
17057             } catch (e) {
17058
17059                 // Fallback for IE.
17060                 box = {
17061                     x: this.node.clientLeft,
17062                     y: this.node.clientTop,
17063                     width: this.node.clientWidth,
17064                     height: this.node.clientHeight
17065                 };
17066             }
17067
17068             if (withoutTransformations) {
17069
17070                 return box;
17071             }
17072
17073             var matrix = this.node.getTransformToElement(target || this.node.ownerSVGElement);
17074             var corners = [];
17075             var point = this.node.ownerSVGElement.createSVGPoint();
17076
17077
17078             point.x = box.x;
17079             point.y = box.y;
17080             corners.push(point.matrixTransform(matrix));
17081             
17082             point.x = box.x + box.width;
17083             point.y = box.y;
17084             corners.push(point.matrixTransform(matrix));
17085             
17086             point.x = box.x + box.width;
17087             point.y = box.y + box.height;
17088             corners.push(point.matrixTransform(matrix));
17089             
17090             point.x = box.x;
17091             point.y = box.y + box.height;
17092             corners.push(point.matrixTransform(matrix));
17093
17094             var minX = corners[0].x;
17095             var maxX = minX;
17096             var minY = corners[0].y;
17097             var maxY = minY;
17098             
17099             for (var i = 1, len = corners.length; i < len; i++) {
17100                 
17101                 var x = corners[i].x;
17102                 var y = corners[i].y;
17103
17104                 if (x < minX) {
17105                     minX = x;
17106                 } else if (x > maxX) {
17107                     maxX = x;
17108                 }
17109                 
17110                 if (y < minY) {
17111                     minY = y;
17112                 } else if (y > maxY) {
17113                     maxY = y;
17114                 }
17115             }
17116
17117             return {
17118                 x: minX,
17119                 y: minY,
17120                 width: maxX - minX,
17121                 height: maxY - minY
17122             };
17123         },
17124
17125         text: function(content) {
17126             var lines = content.split('\n'), i = 0,
17127                 tspan;
17128
17129             // `alignment-baseline` does not work in Firefox.
17130             // Setting `dominant-baseline` on the `<text>` element doesn't work in IE9.
17131             // In order to have the 0,0 coordinate of the `<text>` element (or the first `<tspan>`)
17132             // in the top left corner we translate the `<text>` element by `0.8em`.
17133             // See `http://www.w3.org/Graphics/SVG/WG/wiki/How_to_determine_dominant_baseline`.
17134             // See also `http://apike.ca/prog_svg_text_style.html`.
17135             this.attr('y', '0.8em');
17136
17137             // An empty text gets rendered into the DOM in webkit-based browsers.
17138             // In order to unify this behaviour across all browsers
17139             // we rather hide the text element when it's empty.
17140             this.attr('display', content ? null : 'none');
17141             
17142             if (lines.length === 1) {
17143                 this.node.textContent = content;
17144                 return this;
17145             }
17146             // Easy way to erase all `<tspan>` children;
17147             this.node.textContent = '';
17148             
17149             for (; i < lines.length; i++) {
17150
17151                 // Shift all the <tspan> but first by one line (`1em`)
17152                 tspan = V('tspan', { dy: (i == 0 ? '0em' : '1em'), x: this.attr('x') || 0});
17153                 tspan.node.textContent = lines[i];
17154                 
17155                 this.append(tspan);
17156             }
17157             return this;
17158         },
17159         
17160         attr: function(name, value) {
17161             
17162             if (typeof name === 'string' && typeof value === 'undefined') {
17163                 return this.node.getAttribute(name);
17164             }
17165             
17166             if (typeof name === 'object') {
17167
17168                 for (var attrName in name) {
17169                     if (name.hasOwnProperty(attrName)) {
17170                         setAttribute(this.node, attrName, name[attrName]);
17171                     }
17172                 }
17173                 
17174             } else {
17175
17176                 setAttribute(this.node, name, value);
17177             }
17178
17179             return this;
17180         },
17181
17182         remove: function() {
17183             if (this.node.parentNode) {
17184                 this.node.parentNode.removeChild(this.node);
17185             }
17186         },
17187
17188         append: function(el) {
17189
17190             var els = el;
17191             
17192             if (Object.prototype.toString.call(el) !== '[object Array]') {
17193                 
17194                 els = [el];
17195             }
17196
17197             for (var i = 0, len = els.length; i < len; i++) {
17198                 el = els[i];
17199                 this.node.appendChild(el instanceof VElement ? el.node : el);
17200             }
17201             
17202             return this;
17203         },
17204
17205         prepend: function(el) {
17206             this.node.insertBefore(el instanceof VElement ? el.node : el, this.node.firstChild);
17207         },
17208
17209         svg: function() {
17210
17211             return this.node instanceof window.SVGSVGElement ? this : V(this.node.ownerSVGElement);
17212         },
17213
17214         defs: function() {
17215
17216             var defs = this.svg().node.getElementsByTagName('defs');
17217             
17218             return (defs && defs.length) ? V(defs[0]) : undefined;
17219         },
17220
17221         clone: function() {
17222             var clone = V(this.node.cloneNode(true));
17223             // Note that clone inherits also ID. Therefore, we need to change it here.
17224             clone.node.id = uniqueId();
17225             return clone;
17226         },
17227
17228         findOne: function(selector) {
17229
17230             var found = this.node.querySelector(selector);
17231             return found ? V(found) : undefined;
17232         },
17233
17234         find: function(selector) {
17235
17236             var nodes = this.node.querySelectorAll(selector);
17237
17238             // Map DOM elements to `VElement`s.
17239             for (var i = 0, len = nodes.length; i < len; i++) {
17240                 nodes[i] = V(nodes[i]);
17241             }
17242             return nodes;
17243         },
17244         
17245         // Convert global point into the coordinate space of this element.
17246         toLocalPoint: function(x, y) {
17247
17248             var svg = this.svg().node;
17249             
17250             var p = svg.createSVGPoint();
17251             p.x = x;
17252             p.y = y;
17253
17254             try {
17255
17256                 var globalPoint = p.matrixTransform(svg.getScreenCTM().inverse());
17257                 var globalToLocalMatrix = this.node.getTransformToElement(svg).inverse();
17258
17259             } catch(e) {
17260                 // IE9 throws an exception in odd cases. (`Unexpected call to method or property access`)
17261                 // We have to make do with the original coordianates.
17262                 return p;
17263             }
17264
17265             return globalPoint.matrixTransform(globalToLocalMatrix);
17266         },
17267
17268         translateCenterToPoint: function(p) {
17269
17270             var bbox = this.bbox();
17271             var center = g.rect(bbox).center();
17272
17273             this.translate(p.x - center.x, p.y - center.y);
17274         },
17275
17276         // Efficiently auto-orient an element. This basically implements the orient=auto attribute
17277         // of markers. The easiest way of understanding on what this does is to imagine the element is an
17278         // arrowhead. Calling this method on the arrowhead makes it point to the `position` point while
17279         // being auto-oriented (properly rotated) towards the `reference` point.
17280         // `target` is the element relative to which the transformations are applied. Usually a viewport.
17281         translateAndAutoOrient: function(position, reference, target) {
17282
17283             // Clean-up previously set transformations except the scale. If we didn't clean up the
17284             // previous transformations then they'd add up with the old ones. Scale is an exception as
17285             // it doesn't add up, consider: `this.scale(2).scale(2).scale(2)`. The result is that the
17286             // element is scaled by the factor 2, not 8.
17287
17288             var s = this.scale();
17289             this.attr('transform', '');
17290             this.scale(s.sx, s.sy);
17291
17292             var svg = this.svg().node;
17293             var bbox = this.bbox(false, target);
17294
17295             // 1. Translate to origin.
17296             var translateToOrigin = svg.createSVGTransform();
17297             translateToOrigin.setTranslate(-bbox.x - bbox.width/2, -bbox.y - bbox.height/2);
17298
17299             // 2. Rotate around origin.
17300             var rotateAroundOrigin = svg.createSVGTransform();
17301             var angle = g.point(position).changeInAngle(position.x - reference.x, position.y - reference.y, reference);
17302             rotateAroundOrigin.setRotate(angle, 0, 0);
17303
17304             // 3. Translate to the `position` + the offset (half my width) towards the `reference` point.
17305             var translateFinal = svg.createSVGTransform();
17306             var finalPosition = g.point(position).move(reference, bbox.width/2);
17307             translateFinal.setTranslate(position.x + (position.x - finalPosition.x), position.y + (position.y - finalPosition.y));
17308
17309             // 4. Apply transformations.
17310             var ctm = this.node.getTransformToElement(target);
17311             var transform = svg.createSVGTransform();
17312             transform.setMatrix(
17313                 translateFinal.matrix.multiply(
17314                     rotateAroundOrigin.matrix.multiply(
17315                         translateToOrigin.matrix.multiply(
17316                             ctm)))
17317             );
17318
17319             // Instead of directly setting the `matrix()` transform on the element, first, decompose
17320             // the matrix into separate transforms. This allows us to use normal Vectorizer methods
17321             // as they don't work on matrices. An example of this is to retrieve a scale of an element.
17322             // this.node.transform.baseVal.initialize(transform);
17323
17324             var decomposition = decomposeMatrix(transform.matrix);
17325
17326             this.translate(decomposition.translateX, decomposition.translateY);
17327             this.rotate(decomposition.rotation);
17328             // Note that scale has been already applied, hence the following line stays commented. (it's here just for reference).
17329             //this.scale(decomposition.scaleX, decomposition.scaleY);
17330
17331             return this;
17332         },
17333
17334         animateAlongPath: function(attrs, path) {
17335
17336             var animateMotion = V('animateMotion', attrs);
17337             var mpath = V('mpath', { 'xlink:href': '#' + V(path).node.id });
17338
17339             animateMotion.append(mpath);
17340
17341             this.append(animateMotion);
17342             try {
17343                 animateMotion.node.beginElement();
17344             } catch (e) {
17345                 // Fallback for IE 9.
17346                 // Run the animation programatically if FakeSmile (`http://leunen.me/fakesmile/`) present 
17347                 if (document.documentElement.getAttribute('smiling') === 'fake') {
17348
17349                     // Register the animation. (See `https://answers.launchpad.net/smil/+question/203333`)
17350                     var animation = animateMotion.node;
17351                     animation.animators = [];
17352
17353                     var animationID = animation.getAttribute('id');
17354                     if (animationID) id2anim[animationID] = animation;
17355
17356                     var targets = getTargets(animation);
17357                     for (var i = 0, len = targets.length; i < len; i++) {
17358                         var target = targets[i];
17359                         var animator = new Animator(animation, target, i);
17360                         animators.push(animator);
17361                         animation.animators[i] = animator;
17362                         animator.register();
17363                     }
17364                 }
17365             }
17366         },
17367
17368         hasClass: function(className) {
17369
17370             return new RegExp('(\\s|^)' + className + '(\\s|$)').test(this.node.getAttribute('class'));
17371         },
17372
17373         addClass: function(className) {
17374
17375             if (!this.hasClass(className)) {
17376                 this.node.setAttribute('class', this.node.getAttribute('class') + ' ' + className);
17377             }
17378
17379             return this;
17380         },
17381
17382         removeClass: function(className) {
17383
17384             var removedClass = this.node.getAttribute('class').replace(new RegExp('(\\s|^)' + className + '(\\s|$)', 'g'), '$2');
17385
17386             if (this.hasClass(className)) {
17387                 this.node.setAttribute('class', removedClass);
17388             }
17389
17390             return this;
17391         },
17392
17393         toggleClass: function(className, toAdd) {
17394
17395             var toRemove = typeof toAdd === 'undefined' ? this.hasClass(className) : !toAdd;
17396
17397             if (toRemove) {
17398                 this.removeClass(className);
17399             } else {
17400                 this.addClass(className);
17401             }
17402
17403             return this;
17404         }
17405     };
17406
17407     // Convert a rectangle to SVG path commands. `r` is an object of the form:
17408     // `{ x: [number], y: [number], width: [number], height: [number], top-ry: [number], top-ry: [number], bottom-rx: [number], bottom-ry: [number] }`,
17409     // where `x, y, width, height` are the usual rectangle attributes and [top-/bottom-]rx/ry allows for
17410     // specifying radius of the rectangle for all its sides (as opposed to the built-in SVG rectangle
17411     // that has only `rx` and `ry` attributes).
17412     function rectToPath(r) {
17413
17414         var topRx = r.rx || r['top-rx'] || 0;
17415         var bottomRx = r.rx || r['bottom-rx'] || 0;
17416         var topRy = r.ry || r['top-ry'] || 0;
17417         var bottomRy = r.ry || r['bottom-ry'] || 0;
17418
17419         return [
17420             'M', r.x, r.y + topRy,
17421             'v', r.height - topRy - bottomRy,
17422             'a', bottomRx, bottomRy, 0, 0, 0, bottomRx, bottomRy,
17423             'h', r.width - 2 * bottomRx,
17424             'a', bottomRx, bottomRy, 0, 0, 0, bottomRx, -bottomRy,
17425             'v', -(r.height - bottomRy - topRy),
17426             'a', topRx, topRy, 0, 0, 0, -topRx, -topRy,
17427             'h', -(r.width - 2 * topRx),
17428             'a', topRx, topRy, 0, 0, 0, -topRx, topRy
17429         ].join(' ');
17430     }
17431
17432     var V = createElement;
17433
17434     V.decomposeMatrix = decomposeMatrix;
17435     V.rectToPath = rectToPath;
17436
17437     var svgDocument = V('svg').node;
17438     
17439     V.createSVGMatrix = function(m) {
17440
17441         var svgMatrix = svgDocument.createSVGMatrix();
17442         for (var component in m) {
17443             svgMatrix[component] = m[component];
17444         }
17445         
17446         return svgMatrix;
17447     };
17448
17449     V.createSVGTransform = function() {
17450
17451         return svgDocument.createSVGTransform();
17452     };
17453
17454     V.createSVGPoint = function(x, y) {
17455
17456         var p = svgDocument.createSVGPoint();
17457         p.x = x;
17458         p.y = y;
17459         return p;
17460     };
17461
17462     return V;
17463
17464 }));
17465
17466
17467 //      Geometry library.
17468 //      (c) 2011-2013 client IO
17469
17470
17471 (function(root, factory) {
17472
17473     if (typeof define === 'function' && define.amd) {
17474         // AMD. Register as an anonymous module.
17475         define([], factory);
17476         
17477     } else if (typeof exports === 'object') {
17478         // Node. Does not work with strict CommonJS, but
17479         // only CommonJS-like environments that support module.exports,
17480         // like Node.
17481         module.exports = factory();
17482         
17483     } else {
17484         // Browser globals.
17485         root.g = factory();
17486     }
17487
17488 }(this, function() {
17489
17490
17491     // Declare shorthands to the most used math functions.
17492     var math = Math;
17493     var abs = math.abs;
17494     var cos = math.cos;
17495     var sin = math.sin;
17496     var sqrt = math.sqrt;
17497     var mmin = math.min;
17498     var mmax = math.max;
17499     var atan = math.atan;
17500     var atan2 = math.atan2;
17501     var acos = math.acos;
17502     var round = math.round;
17503     var floor = math.floor;
17504     var PI = math.PI;
17505     var random = math.random;
17506     var toDeg = function(rad) { return (180*rad / PI) % 360; };
17507     var toRad = function(deg) { return (deg % 360) * PI / 180; };
17508     var snapToGrid = function(val, gridSize) { return gridSize * Math.round(val/gridSize); };
17509     var normalizeAngle = function(angle) { return (angle % 360) + (angle < 0 ? 360 : 0); };
17510
17511     // Point
17512     // -----
17513
17514     // Point is the most basic object consisting of x/y coordinate,.
17515
17516     // Possible instantiations are:
17517
17518     // * `point(10, 20)`
17519     // * `new point(10, 20)`
17520     // * `point('10 20')`
17521     // * `point(point(10, 20))`
17522     function point(x, y) {
17523         if (!(this instanceof point))
17524             return new point(x, y);
17525         var xy;
17526         if (y === undefined && Object(x) !== x) {
17527             xy = x.split(x.indexOf('@') === -1 ? ' ' : '@');
17528             this.x = parseInt(xy[0], 10);
17529             this.y = parseInt(xy[1], 10);
17530         } else if (Object(x) === x) {
17531             this.x = x.x;
17532             this.y = x.y;
17533         } else {
17534             this.x = x;
17535             this.y = y;
17536         }
17537     }
17538
17539     point.prototype = {
17540         toString: function() {
17541             return this.x + "@" + this.y;
17542         },
17543         // If point lies outside rectangle `r`, return the nearest point on the boundary of rect `r`,
17544         // otherwise return point itself.
17545         // (see Squeak Smalltalk, Point>>adhereTo:)
17546         adhereToRect: function(r) {
17547             if (r.containsPoint(this)){
17548                 return this;
17549             }
17550             this.x = mmin(mmax(this.x, r.x), r.x + r.width);
17551             this.y = mmin(mmax(this.y, r.y), r.y + r.height);
17552             return this;
17553         },
17554         // Compute the angle between me and `p` and the x axis.
17555         // (cartesian-to-polar coordinates conversion)
17556         // Return theta angle in degrees.
17557         theta: function(p) {
17558             p = point(p);
17559             // Invert the y-axis.
17560             var y = -(p.y - this.y);
17561             var x = p.x - this.x;
17562             // Makes sure that the comparison with zero takes rounding errors into account.
17563             var PRECISION = 10;
17564             // Note that `atan2` is not defined for `x`, `y` both equal zero.
17565             var rad = (y.toFixed(PRECISION) == 0 && x.toFixed(PRECISION) == 0) ? 0 : atan2(y, x); 
17566
17567             // Correction for III. and IV. quadrant.
17568             if (rad < 0) { 
17569                 rad = 2*PI + rad;
17570             }
17571             return 180*rad / PI;
17572         },
17573         // Returns distance between me and point `p`.
17574         distance: function(p) {
17575             return line(this, p).length();
17576         },
17577         // Returns a manhattan (taxi-cab) distance between me and point `p`.
17578         manhattanDistance: function(p) {
17579             return abs(p.x - this.x) + abs(p.y - this.y);
17580         },
17581         // Offset me by the specified amount.
17582         offset: function(dx, dy) {
17583             this.x += dx || 0;
17584             this.y += dy || 0;
17585             return this;
17586         },
17587         magnitude: function() {
17588             return sqrt((this.x*this.x) + (this.y*this.y)) || 0.01;
17589         },
17590         update: function(x, y) {
17591             this.x = x || 0;
17592             this.y = y || 0;
17593             return this;
17594         },
17595         round: function(decimals) {
17596             this.x = decimals ? this.x.toFixed(decimals) : round(this.x);
17597             this.y = decimals ? this.y.toFixed(decimals) : round(this.y);
17598             return this;
17599         },
17600         // Scale the line segment between (0,0) and me to have a length of len.
17601         normalize: function(len) {
17602             var s = (len || 1) / this.magnitude();
17603             this.x = s * this.x;
17604             this.y = s * this.y;
17605             return this;
17606         },
17607         difference: function(p) {
17608             return point(this.x - p.x, this.y - p.y);
17609         },
17610         // Return the bearing between me and point `p`.
17611         bearing: function(p) {
17612             return line(this, p).bearing();
17613         },        
17614         // Converts rectangular to polar coordinates.
17615         // An origin can be specified, otherwise it's 0@0.
17616         toPolar: function(o) {
17617             o = (o && point(o)) || point(0,0);
17618             var x = this.x;
17619             var y = this.y;
17620             this.x = sqrt((x-o.x)*(x-o.x) + (y-o.y)*(y-o.y));   // r
17621             this.y = toRad(o.theta(point(x,y)));
17622             return this;
17623         },
17624         // Rotate point by angle around origin o.
17625         rotate: function(o, angle) {
17626             angle = (angle + 360) % 360;
17627             this.toPolar(o);
17628             this.y += toRad(angle);
17629             var p = point.fromPolar(this.x, this.y, o);
17630             this.x = p.x;
17631             this.y = p.y;
17632             return this;
17633         },
17634         // Move point on line starting from ref ending at me by
17635         // distance distance.
17636         move: function(ref, distance) {
17637             var theta = toRad(point(ref).theta(this));
17638             return this.offset(cos(theta) * distance, -sin(theta) * distance);
17639         },
17640         // Returns change in angle from my previous position (-dx, -dy) to my new position
17641         // relative to ref point.
17642         changeInAngle: function(dx, dy, ref) {
17643             // Revert the translation and measure the change in angle around x-axis.
17644             return point(this).offset(-dx, -dy).theta(ref) - this.theta(ref);
17645         },
17646         equals: function(p) {
17647             return this.x === p.x && this.y === p.y;
17648         },
17649         snapToGrid: function(gx, gy) {
17650             this.x = snapToGrid(this.x, gx)
17651             this.y = snapToGrid(this.y, gy || gx)
17652             return this;
17653         }
17654     };
17655     // Alternative constructor, from polar coordinates.
17656     // @param {number} r Distance.
17657     // @param {number} angle Angle in radians.
17658     // @param {point} [optional] o Origin.
17659     point.fromPolar = function(r, angle, o) {
17660         o = (o && point(o)) || point(0,0);
17661         var x = abs(r * cos(angle));
17662         var y = abs(r * sin(angle));
17663         var deg = normalizeAngle(toDeg(angle));
17664
17665         if (deg < 90) y = -y;
17666         else if (deg < 180) { x = -x; y = -y; }
17667         else if (deg < 270) x = -x;
17668         
17669         return point(o.x + x, o.y + y);
17670     };
17671
17672     // Create a point with random coordinates that fall into the range `[x1, x2]` and `[y1, y2]`.
17673     point.random = function(x1, x2, y1, y2) {
17674         return point(floor(random() * (x2 - x1 + 1) + x1), floor(random() * (y2 - y1 + 1) + y1));
17675     };
17676
17677     // Line.
17678     // -----
17679     function line(p1, p2) {
17680         if (!(this instanceof line))
17681             return new line(p1, p2);
17682         this.start = point(p1);
17683         this.end = point(p2);
17684     }
17685     
17686     line.prototype = {
17687         toString: function() {
17688             return this.start.toString() + ' ' + this.end.toString();
17689         },
17690         // @return {double} length of the line
17691         length: function() {
17692             return sqrt(this.squaredLength());
17693         },
17694         // @return {integer} length without sqrt
17695         // @note for applications where the exact length is not necessary (e.g. compare only)
17696         squaredLength: function() {
17697             var x0 = this.start.x;
17698             var y0 = this.start.y;
17699             var x1 = this.end.x;
17700             var y1 = this.end.y;
17701             return (x0 -= x1)*x0 + (y0 -= y1)*y0;
17702         },
17703         // @return {point} my midpoint
17704         midpoint: function() {
17705             return point((this.start.x + this.end.x) / 2,
17706                          (this.start.y + this.end.y) / 2);
17707         },
17708         // @return {point} Point where I'm intersecting l.
17709         // @see Squeak Smalltalk, LineSegment>>intersectionWith:
17710         intersection: function(l) {
17711             var pt1Dir = point(this.end.x - this.start.x, this.end.y - this.start.y);
17712             var pt2Dir = point(l.end.x - l.start.x, l.end.y - l.start.y);
17713             var det = (pt1Dir.x * pt2Dir.y) - (pt1Dir.y * pt2Dir.x);
17714             var deltaPt = point(l.start.x - this.start.x, l.start.y - this.start.y);
17715             var alpha = (deltaPt.x * pt2Dir.y) - (deltaPt.y * pt2Dir.x);
17716             var beta = (deltaPt.x * pt1Dir.y) - (deltaPt.y * pt1Dir.x);
17717
17718             if (det === 0 ||
17719                 alpha * det < 0 ||
17720                 beta * det < 0) {
17721                 // No intersection found.
17722                 return null;    
17723             }
17724             if (det > 0){
17725                 if (alpha > det || beta > det){
17726                     return null;
17727                 }
17728             } else {
17729                 if (alpha < det || beta < det){
17730                     return null;
17731                 }
17732             }
17733             return point(this.start.x + (alpha * pt1Dir.x / det),
17734                          this.start.y + (alpha * pt1Dir.y / det));
17735         },
17736         
17737         // @return the bearing (cardinal direction) of the line. For example N, W, or SE.
17738         // @returns {String} One of the following bearings : NE, E, SE, S, SW, W, NW, N.
17739         bearing: function() {
17740             
17741             var lat1 = toRad(this.start.y);
17742             var lat2 = toRad(this.end.y);
17743             var lon1 = this.start.x;
17744             var lon2 = this.end.x;
17745             var dLon = toRad(lon2 - lon1);
17746             var y = sin(dLon) * cos(lat2);
17747             var x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dLon);
17748             var brng = toDeg(atan2(y, x));
17749
17750             var bearings = ['NE', 'E', 'SE', 'S', 'SW', 'W', 'NW', 'N'];
17751
17752             var index = brng - 22.5;
17753             if (index < 0)
17754                 index += 360;
17755             index = parseInt(index / 45);
17756
17757             return bearings[index];
17758         }
17759     };
17760
17761     // Rectangle.
17762     // ----------
17763     function rect(x, y, w, h) {
17764         if (!(this instanceof rect))
17765             return new rect(x, y, w, h);
17766         if (y === undefined) {
17767             y = x.y;
17768             w = x.width;
17769             h = x.height;
17770             x = x.x;        
17771         }
17772         this.x = x;
17773         this.y = y;
17774         this.width = w;
17775         this.height = h;
17776     }
17777     
17778     rect.prototype = {
17779         toString: function() {
17780             return this.origin().toString() + ' ' + this.corner().toString();
17781         },
17782         origin: function() {
17783             return point(this.x, this.y);
17784         },
17785         corner: function() {
17786             return point(this.x + this.width, this.y + this.height);
17787         },
17788         topRight: function() {
17789             return point(this.x + this.width, this.y);
17790         },
17791         bottomLeft: function() {
17792             return point(this.x, this.y + this.height);
17793         },
17794         center: function() {
17795             return point(this.x + this.width/2, this.y + this.height/2);
17796         },
17797         // @return {boolean} true if rectangles intersect
17798         intersect: function(r) {
17799             var myOrigin = this.origin();
17800             var myCorner = this.corner();
17801             var rOrigin = r.origin();
17802             var rCorner = r.corner();
17803             
17804             if (rCorner.x <= myOrigin.x ||
17805                 rCorner.y <= myOrigin.y ||
17806                 rOrigin.x >= myCorner.x ||
17807                 rOrigin.y >= myCorner.y) return false;
17808             return true;
17809         },
17810         // @return {string} (left|right|top|bottom) side which is nearest to point
17811         // @see Squeak Smalltalk, Rectangle>>sideNearestTo:
17812         sideNearestToPoint: function(p) {
17813             p = point(p);
17814             var distToLeft = p.x - this.x;
17815             var distToRight = (this.x + this.width) - p.x;
17816             var distToTop = p.y - this.y;
17817             var distToBottom = (this.y + this.height) - p.y;
17818             var closest = distToLeft;
17819             var side = 'left';
17820             
17821             if (distToRight < closest) {
17822                 closest = distToRight;
17823                 side = 'right';
17824             }
17825             if (distToTop < closest) {
17826                 closest = distToTop;
17827                 side = 'top';
17828             }
17829             if (distToBottom < closest) {
17830                 closest = distToBottom;
17831                 side = 'bottom';
17832             }
17833             return side;
17834         },
17835         // @return {bool} true if point p is insight me
17836         containsPoint: function(p) {
17837             p = point(p);
17838             if (p.x >= this.x && p.x <= this.x + this.width &&
17839                 p.y >= this.y && p.y <= this.y + this.height) {
17840                 return true;
17841             }
17842             return false;
17843         },
17844         // Algorithm ported from java.awt.Rectangle from OpenJDK.
17845         // @return {bool} true if rectangle `r` is inside me.
17846         containsRect: function(r) {
17847             var nr = rect(r).normalize();
17848             var W = nr.width;
17849             var H = nr.height;
17850             var X = nr.x;
17851             var Y = nr.y;
17852             var w = this.width;
17853             var h = this.height;
17854             if ((w | h | W | H) < 0) {
17855                 // At least one of the dimensions is negative...
17856                 return false;
17857             }
17858             // Note: if any dimension is zero, tests below must return false...
17859             var x = this.x;
17860             var y = this.y;
17861             if (X < x || Y < y) {
17862                 return false;
17863             }
17864             w += x;
17865             W += X;
17866             if (W <= X) {
17867                 // X+W overflowed or W was zero, return false if...
17868                 // either original w or W was zero or
17869                 // x+w did not overflow or
17870                 // the overflowed x+w is smaller than the overflowed X+W
17871                 if (w >= x || W > w) return false;
17872             } else {
17873                 // X+W did not overflow and W was not zero, return false if...
17874                 // original w was zero or
17875                 // x+w did not overflow and x+w is smaller than X+W
17876                 if (w >= x && W > w) return false;
17877             }
17878             h += y;
17879             H += Y;
17880             if (H <= Y) {
17881                 if (h >= y || H > h) return false;
17882             } else {
17883                 if (h >= y && H > h) return false;
17884             }
17885             return true;
17886         },        
17887         // @return {point} a point on my boundary nearest to p
17888         // @see Squeak Smalltalk, Rectangle>>pointNearestTo:
17889         pointNearestToPoint: function(p) {
17890             p = point(p);
17891             if (this.containsPoint(p)) {
17892                 var side = this.sideNearestToPoint(p);
17893                 switch (side){
17894                   case "right": return point(this.x + this.width, p.y);
17895                   case "left": return point(this.x, p.y);
17896                   case "bottom": return point(p.x, this.y + this.height);
17897                   case "top": return point(p.x, this.y);
17898                 }
17899             }
17900             return p.adhereToRect(this);
17901         },
17902         // Find point on my boundary where line starting
17903         // from my center ending in point p intersects me.
17904         // @param {number} angle If angle is specified, intersection with rotated rectangle is computed.
17905         intersectionWithLineFromCenterToPoint: function(p, angle) {
17906             p = point(p);
17907             var center = point(this.x + this.width/2, this.y + this.height/2);
17908             var result;
17909             if (angle) p.rotate(center, angle);
17910             
17911             // (clockwise, starting from the top side)
17912             var sides = [
17913                 line(this.origin(), this.topRight()),
17914                 line(this.topRight(), this.corner()),
17915                 line(this.corner(), this.bottomLeft()),
17916                 line(this.bottomLeft(), this.origin())
17917             ];
17918             var connector = line(center, p);
17919             
17920             for (var i = sides.length - 1; i >= 0; --i){
17921                 var intersection = sides[i].intersection(connector);
17922                 if (intersection !== null){
17923                     result = intersection;
17924                     break;
17925                 }
17926             }
17927             if (result && angle) result.rotate(center, -angle);
17928             return result;
17929         },
17930         // Move and expand me.
17931         // @param r {rectangle} representing deltas
17932         moveAndExpand: function(r) {
17933             this.x += r.x;
17934             this.y += r.y;
17935             this.width += r.width;
17936             this.height += r.height;
17937             return this;
17938         },
17939         round: function(decimals) {
17940             this.x = decimals ? this.x.toFixed(decimals) : round(this.x);
17941             this.y = decimals ? this.y.toFixed(decimals) : round(this.y);
17942             this.width = decimals ? this.width.toFixed(decimals) : round(this.width);
17943             this.height = decimals ? this.height.toFixed(decimals) : round(this.height);
17944             return this;
17945         },
17946         // Normalize the rectangle; i.e., make it so that it has a non-negative width and height.
17947         // If width < 0 the function swaps the left and right corners,
17948         // and it swaps the top and bottom corners if height < 0
17949         // like in http://qt-project.org/doc/qt-4.8/qrectf.html#normalized
17950         normalize: function() {
17951             var newx = this.x;
17952             var newy = this.y;
17953             var newwidth = this.width;
17954             var newheight = this.height;
17955             if (this.width < 0) {
17956                 newx = this.x + this.width;
17957                 newwidth = -this.width;
17958             }
17959             if (this.height < 0) {
17960                 newy = this.y + this.height;
17961                 newheight = -this.height;
17962             }
17963             this.x = newx;
17964             this.y = newy;
17965             this.width = newwidth;
17966             this.height = newheight;
17967             return this;
17968         }        
17969     };
17970
17971     // Ellipse.
17972     // --------
17973     function ellipse(c, a, b) {
17974         if (!(this instanceof ellipse))
17975             return new ellipse(c, a, b);
17976         c = point(c);
17977         this.x = c.x;
17978         this.y = c.y;
17979         this.a = a;
17980         this.b = b;
17981     }
17982
17983     ellipse.prototype = {
17984         toString: function() {
17985             return point(this.x, this.y).toString() + ' ' + this.a + ' ' + this.b;
17986         },
17987         bbox: function() {
17988                 return rect(this.x - this.a, this.y - this.b, 2*this.a, 2*this.b);
17989         },
17990         // Find point on me where line from my center to
17991         // point p intersects my boundary.
17992         // @param {number} angle If angle is specified, intersection with rotated ellipse is computed.
17993         intersectionWithLineFromCenterToPoint: function(p, angle) {
17994             p = point(p);
17995             if (angle) p.rotate(point(this.x, this.y), angle);
17996             var dx = p.x - this.x;
17997             var dy = p.y - this.y;
17998             var result;
17999             if (dx === 0) {
18000                 result = this.bbox().pointNearestToPoint(p);
18001                 if (angle) return result.rotate(point(this.x, this.y), -angle);
18002                 return result;
18003             }
18004             var m = dy / dx;
18005             var mSquared = m * m;
18006             var aSquared = this.a * this.a;
18007             var bSquared = this.b * this.b;
18008             var x = sqrt(1 / ((1 / aSquared) + (mSquared / bSquared)));
18009
18010             x = dx < 0 ? -x : x;
18011             var y = m * x;
18012             result = point(this.x + x, this.y + y);
18013             if (angle) return result.rotate(point(this.x, this.y), -angle);
18014             return result;
18015         }
18016     };
18017
18018     // Bezier curve.
18019     // -------------
18020     var bezier = {
18021         // Cubic Bezier curve path through points.
18022         // Ported from C# implementation by Oleg V. Polikarpotchkin and Peter Lee (http://www.codeproject.com/KB/graphics/BezierSpline.aspx).
18023         // @param {array} points Array of points through which the smooth line will go.
18024         // @return {array} SVG Path commands as an array
18025         curveThroughPoints: function(points) {
18026             var controlPoints = this.getCurveControlPoints(points);
18027             var path = ['M', points[0].x, points[0].y];
18028
18029             for (var i = 0; i < controlPoints[0].length; i++) {
18030                 path.push('C', controlPoints[0][i].x, controlPoints[0][i].y, controlPoints[1][i].x, controlPoints[1][i].y, points[i+1].x, points[i+1].y);        
18031             }
18032             return path;
18033         },
18034         
18035         // Get open-ended Bezier Spline Control Points.
18036         // @param knots Input Knot Bezier spline points (At least two points!).
18037         // @param firstControlPoints Output First Control points. Array of knots.length - 1 length.
18038         //  @param secondControlPoints Output Second Control points. Array of knots.length - 1 length.
18039         getCurveControlPoints: function(knots) {
18040             var firstControlPoints = [];
18041             var secondControlPoints = [];
18042             var n = knots.length - 1;
18043             var i;
18044
18045             // Special case: Bezier curve should be a straight line.
18046             if (n == 1) { 
18047                 // 3P1 = 2P0 + P3
18048                 firstControlPoints[0] = point((2 * knots[0].x + knots[1].x) / 3,
18049                                               (2 * knots[0].y + knots[1].y) / 3);
18050                 // P2 = 2P1 â€“ P0
18051                 secondControlPoints[0] = point(2 * firstControlPoints[0].x - knots[0].x,
18052                                                2 * firstControlPoints[0].y - knots[0].y);
18053                 return [firstControlPoints, secondControlPoints];
18054             }
18055             
18056                 // Calculate first Bezier control points.
18057             // Right hand side vector.
18058             var rhs = [];
18059             
18060             // Set right hand side X values.
18061             for (i = 1; i < n - 1; i++) {
18062                 rhs[i] = 4 * knots[i].x + 2 * knots[i + 1].x;
18063             }
18064             rhs[0] = knots[0].x + 2 * knots[1].x;
18065             rhs[n - 1] = (8 * knots[n - 1].x + knots[n].x) / 2.0;
18066             // Get first control points X-values.
18067             var x = this.getFirstControlPoints(rhs);
18068             
18069             // Set right hand side Y values.
18070             for (i = 1; i < n - 1; ++i) {
18071                 rhs[i] = 4 * knots[i].y + 2 * knots[i + 1].y;
18072             }
18073             rhs[0] = knots[0].y + 2 * knots[1].y;
18074             rhs[n - 1] = (8 * knots[n - 1].y + knots[n].y) / 2.0;
18075             // Get first control points Y-values.
18076             var y = this.getFirstControlPoints(rhs);
18077             
18078             // Fill output arrays.
18079             for (i = 0; i < n; i++) {
18080                 // First control point.
18081                 firstControlPoints.push(point(x[i], y[i]));
18082                 // Second control point.
18083                 if (i < n - 1) {
18084                     secondControlPoints.push(point(2 * knots [i + 1].x - x[i + 1],
18085                                                    2 * knots[i + 1].y - y[i + 1]));
18086                 } else {
18087                     secondControlPoints.push(point((knots[n].x + x[n - 1]) / 2,
18088                                                    (knots[n].y + y[n - 1]) / 2));
18089                 }
18090             }
18091             return [firstControlPoints, secondControlPoints];
18092         },
18093
18094         // Solves a tridiagonal system for one of coordinates (x or y) of first Bezier control points.
18095         // @param rhs Right hand side vector.
18096         // @return Solution vector.
18097         getFirstControlPoints: function(rhs) {
18098             var n = rhs.length;
18099             // `x` is a solution vector.
18100             var x = [];
18101             var tmp = [];
18102             var b = 2.0;
18103             
18104             x[0] = rhs[0] / b;
18105             // Decomposition and forward substitution.
18106             for (var i = 1; i < n; i++) { 
18107                 tmp[i] = 1 / b;
18108                 b = (i < n - 1 ? 4.0 : 3.5) - tmp[i];
18109                 x[i] = (rhs[i] - x[i - 1]) / b;
18110             }
18111             for (i = 1; i < n; i++) {
18112                 // Backsubstitution.
18113                 x[n - i - 1] -= tmp[n - i] * x[n - i]; 
18114             }
18115             return x;
18116         }
18117     };
18118
18119     // Scale.
18120     var scale = {
18121
18122         // Return the `value` from the `domain` interval scaled to the `range` interval.
18123         linear: function(domain, range, value) {
18124
18125             var domainSpan = domain[1] - domain[0];
18126             var rangeSpan = range[1] - range[0];
18127             return (((value - domain[0]) / domainSpan) * rangeSpan + range[0]) || 0;
18128         }
18129     };
18130
18131     return {
18132
18133         toDeg: toDeg,
18134         toRad: toRad,
18135         snapToGrid: snapToGrid,
18136         normalizeAngle: normalizeAngle,
18137         point: point,
18138         line: line,
18139         rect: rect,
18140         ellipse: ellipse,
18141         bezier: bezier,
18142         scale: scale
18143     }
18144 }));
18145
18146 //      JointJS library.
18147 //      (c) 2011-2013 client IO
18148
18149 if (typeof exports === 'object') {
18150
18151     var _ = require('lodash');
18152 }
18153
18154
18155 // Global namespace.
18156
18157 var joint = {
18158
18159     // `joint.dia` namespace.
18160     dia: {},
18161
18162     // `joint.ui` namespace.
18163     ui: {},
18164
18165     // `joint.layout` namespace.
18166     layout: {},
18167
18168     // `joint.shapes` namespace.
18169     shapes: {},
18170
18171     // `joint.format` namespace.
18172     format: {},
18173
18174     // `joint.connectors` namespace.
18175     connectors: {},
18176
18177     // `joint.routers` namespace.
18178     routers: {},
18179
18180     util: {
18181
18182         // Return a simple hash code from a string. See http://werxltd.com/wp/2010/05/13/javascript-implementation-of-javas-string-hashcode-method/.
18183         hashCode: function(str) {
18184
18185             var hash = 0;
18186             if (str.length == 0) return hash;
18187             for (var i = 0; i < str.length; i++) {
18188                 var c = str.charCodeAt(i);
18189                 hash = ((hash << 5) - hash) + c;
18190                 hash = hash & hash; // Convert to 32bit integer
18191             }
18192             return hash;
18193         },
18194
18195         getByPath: function(obj, path, delim) {
18196             
18197             delim = delim || '.';
18198             var keys = path.split(delim);
18199             var key;
18200             
18201             while (keys.length) {
18202                 key = keys.shift();
18203                 if (key in obj) {
18204                     obj = obj[key];
18205                 } else {
18206                     return undefined;
18207                 }
18208             }
18209             return obj;
18210         },
18211
18212         setByPath: function(obj, path, value, delim) {
18213
18214             delim = delim || '.';
18215
18216             var keys = path.split(delim);
18217             var diver = obj;
18218             var i = 0;
18219
18220             if (path.indexOf(delim) > -1) {
18221
18222                 for (var len = keys.length; i < len - 1; i++) {
18223                     // diver creates an empty object if there is no nested object under such a key.
18224                     // This means that one can populate an empty nested object with setByPath().
18225                     diver = diver[keys[i]] || (diver[keys[i]] = {});
18226                 }
18227                 diver[keys[len - 1]] = value;
18228             } else {
18229                 obj[path] = value;
18230             }
18231             return obj;
18232         },
18233
18234         unsetByPath: function(obj, path, delim) {
18235
18236             delim = delim || '.';
18237
18238             // index of the last delimiter
18239             var i = path.lastIndexOf(delim);
18240
18241             if (i > -1) {
18242
18243                 // unsetting a nested attribute
18244                 var parent = joint.util.getByPath(obj, path.substr(0, i), delim);
18245
18246                 if (parent) {
18247
18248                     delete parent[path.slice(i + 1)];
18249                 }
18250
18251             } else {
18252
18253                 // unsetting a primitive attribute
18254                 delete obj[path];
18255             }
18256
18257             return obj;
18258         },
18259
18260         flattenObject: function(obj, delim, stop) {
18261             
18262             delim = delim || '.';
18263             var ret = {};
18264             
18265             for (var key in obj) {
18266                 if (!obj.hasOwnProperty(key)) continue;
18267
18268                 var shouldGoDeeper = typeof obj[key] === 'object';
18269                 if (shouldGoDeeper && stop && stop(obj[key])) {
18270                     shouldGoDeeper = false;
18271                 }
18272                 
18273                 if (shouldGoDeeper) {
18274                     var flatObject = this.flattenObject(obj[key], delim, stop);
18275                     for (var flatKey in flatObject) {
18276                         if (!flatObject.hasOwnProperty(flatKey)) continue;
18277                         
18278                         ret[key + delim + flatKey] = flatObject[flatKey];
18279                     }
18280                 } else {
18281                     ret[key] = obj[key];
18282                 }
18283             }
18284             return ret;
18285         },
18286
18287         uuid: function() {
18288
18289             // credit: http://stackoverflow.com/posts/2117523/revisions
18290             
18291             return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
18292                 var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
18293                 return v.toString(16);
18294             });
18295         },
18296
18297         // Generate global unique id for obj and store it as a property of the object.
18298         guid: function(obj) {
18299             
18300             this.guid.id = this.guid.id || 1;
18301             obj.id = (obj.id === undefined ? 'j_' + this.guid.id++ : obj.id);
18302             return obj.id;
18303         },
18304
18305         // Copy all the properties to the first argument from the following arguments.
18306         // All the properties will be overwritten by the properties from the following
18307         // arguments. Inherited properties are ignored.
18308         mixin: function() {
18309             
18310             var target = arguments[0];
18311             
18312             for (var i = 1, l = arguments.length; i < l; i++) {
18313                 
18314                 var extension = arguments[i];
18315                 
18316                 // Only functions and objects can be mixined.
18317
18318                 if ((Object(extension) !== extension) &&
18319                     !_.isFunction(extension) &&
18320                     (extension === null || extension === undefined)) {
18321
18322                     continue;
18323                 }
18324
18325                 _.each(extension, function(copy, key) {
18326                     
18327                     if (this.mixin.deep && (Object(copy) === copy)) {
18328
18329                         if (!target[key]) {
18330
18331                             target[key] = _.isArray(copy) ? [] : {};
18332                         }
18333                         
18334                         this.mixin(target[key], copy);
18335                         return;
18336                     }
18337                     
18338                     if (target[key] !== copy) {
18339                         
18340                         if (!this.mixin.supplement || !target.hasOwnProperty(key)) {
18341                             
18342                             target[key] = copy;
18343                         }
18344
18345                     }
18346                     
18347                 }, this);
18348             }
18349             
18350             return target;
18351         },
18352
18353         // Copy all properties to the first argument from the following
18354         // arguments only in case if they don't exists in the first argument.
18355         // All the function propererties in the first argument will get
18356         // additional property base pointing to the extenders same named
18357         // property function's call method.
18358         supplement: function() {
18359
18360             this.mixin.supplement = true;
18361             var ret = this.mixin.apply(this, arguments);
18362             this.mixin.supplement = false;
18363             return ret;
18364         },
18365
18366         // Same as `mixin()` but deep version.
18367         deepMixin: function() {
18368             
18369             this.mixin.deep = true;
18370             var ret = this.mixin.apply(this, arguments);
18371             this.mixin.deep = false;
18372             return ret;
18373         },
18374
18375         // Same as `supplement()` but deep version.
18376         deepSupplement: function() {
18377             
18378             this.mixin.deep = this.mixin.supplement = true;
18379             var ret = this.mixin.apply(this, arguments);
18380             this.mixin.deep = this.mixin.supplement = false;
18381             return ret;
18382         },
18383
18384         normalizeEvent: function(evt) {
18385
18386             return (evt.originalEvent && evt.originalEvent.changedTouches && evt.originalEvent.changedTouches.length) ? evt.originalEvent.changedTouches[0] : evt;
18387         },
18388
18389         nextFrame:(function() {
18390
18391             var raf;
18392             var client = typeof window != 'undefined';
18393
18394             if (client) {
18395
18396                 raf = window.requestAnimationFrame       ||
18397                       window.webkitRequestAnimationFrame ||
18398                       window.mozRequestAnimationFrame    ||
18399                       window.oRequestAnimationFrame      ||
18400                       window.msRequestAnimationFrame;
18401
18402             }
18403
18404             if (!raf) {
18405
18406                 var lastTime = 0;
18407
18408                 raf = function(callback) {
18409
18410                     var currTime = new Date().getTime();
18411                     var timeToCall = Math.max(0, 16 - (currTime - lastTime));
18412                     var id = setTimeout(function() { callback(currTime + timeToCall); }, timeToCall);
18413                     lastTime = currTime + timeToCall;
18414                     return id;
18415
18416                 };
18417             }
18418
18419             return client ? _.bind(raf, window) : raf;
18420         })(),
18421
18422         cancelFrame: (function() {
18423
18424             var caf;
18425             var client = typeof window != 'undefined';
18426
18427             if (client) {
18428
18429                 caf = window.cancelAnimationFrame              ||
18430                       window.webkitCancelAnimationFrame        ||
18431                       window.webkitCancelRequestAnimationFrame ||
18432                       window.msCancelAnimationFrame            ||
18433                       window.msCancelRequestAnimationFrame     ||
18434                       window.oCancelAnimationFrame             ||
18435                       window.oCancelRequestAnimationFrame      ||
18436                       window.mozCancelAnimationFrame           ||
18437                       window.mozCancelRequestAnimationFrame;
18438
18439             }
18440
18441             caf = caf || clearTimeout;
18442
18443             return client ? _.bind(caf, window) : caf;
18444         })(),
18445
18446         breakText: function(text, size, styles, opt) {
18447
18448             opt = opt || {};
18449
18450             var width = size.width;
18451             var height = size.height;
18452
18453             var svgDocument = opt.svgDocument || V('svg').node;
18454             var textElement = V('<text><tspan></tspan></text>').attr(styles || {}).node;
18455             var textSpan = textElement.firstChild;
18456             var textNode = document.createTextNode('');
18457
18458             textSpan.appendChild(textNode);
18459
18460             svgDocument.appendChild(textElement);
18461
18462             if (!opt.svgDocument) {
18463
18464                 document.body.appendChild(svgDocument);
18465             }
18466
18467             var words = text.split(' ');
18468             var full = [];
18469             var lines = [];
18470             var p;
18471
18472             for (var i = 0, l = 0, len = words.length; i < len; i++) {
18473
18474                 var word = words[i];
18475
18476                 textNode.data = lines[l] ? lines[l] + ' ' + word : word;
18477
18478                 if (textSpan.getComputedTextLength() <= width) {
18479
18480                     // the current line fits
18481                     lines[l] = textNode.data;
18482
18483                     if (p) {
18484                         // We were partitioning. Put rest of the word onto next line
18485                         full[l++] = true;
18486
18487                         // cancel partitioning
18488                         p = 0;
18489                     }
18490
18491                 } else {
18492
18493                     if (!lines[l] || p) {
18494
18495                         var partition = !!p;
18496
18497                         p = word.length - 1;
18498
18499                         if (partition || !p) {
18500
18501                             // word has only one character.
18502                             if (!p) {
18503
18504                                 if (!lines[l]) {
18505
18506                                     // we won't fit this text within our rect
18507                                     lines = [];
18508
18509                                     break;
18510                                 }
18511
18512                                 // partitioning didn't help on the non-empty line
18513                                 // try again, but this time start with a new line
18514
18515                                 // cancel partitions created
18516                                 words.splice(i,2, word + words[i+1]);
18517
18518                                 // adjust word length
18519                                 len--;
18520
18521                                 full[l++] = true;
18522                                 i--;
18523
18524                                 continue;
18525                             }
18526
18527                             // move last letter to the beginning of the next word
18528                             words[i] = word.substring(0,p);
18529                             words[i+1] = word.substring(p) + words[i+1];
18530
18531                         } else {
18532
18533                             // We initiate partitioning
18534                             // split the long word into two words
18535                             words.splice(i, 1, word.substring(0,p), word.substring(p));
18536
18537                             // adjust words length
18538                             len++;
18539
18540                             if (l && !full[l-1]) {
18541                                 // if the previous line is not full, try to fit max part of
18542                                 // the current word there
18543                                 l--;
18544                             }
18545                         }
18546
18547                         i--;
18548
18549                         continue;
18550                     }
18551
18552                     l++;
18553                     i--;
18554                 }
18555
18556                 // if size.height is defined we have to check whether the height of the entire
18557                 // text exceeds the rect height
18558                 if (typeof height !== 'undefined') {
18559
18560                     // get line height as text height / 0.8 (as text height is approx. 0.8em
18561                     // and line height is 1em. See vectorizer.text())
18562                     var lh = lh || textElement.getBBox().height * 1.25;
18563
18564                     if (lh * lines.length > height) {
18565
18566                         // remove overflowing lines
18567                         lines.splice(Math.floor(height / lh));
18568
18569                         break;
18570                     }
18571                 }
18572             }
18573
18574             if (opt.svgDocument) {
18575
18576                 // svg document was provided, remove the text element only
18577                 svgDocument.removeChild(textElement);
18578
18579             } else {
18580
18581                 // clean svg document
18582                 document.body.removeChild(svgDocument);
18583             }
18584
18585             return lines.join('\n');
18586         },
18587
18588         timing: {
18589
18590             linear: function(t) {
18591                 return t;
18592             },
18593
18594             quad: function(t) {
18595                 return t * t;
18596             },
18597
18598             cubic: function(t) {
18599                 return t * t * t;
18600             },
18601
18602             inout: function(t) {
18603                 if (t <= 0) return 0;
18604                 if (t >= 1) return 1;
18605                 var t2 = t * t, t3 = t2 * t;
18606                 return 4 * (t < .5 ? t3 : 3 * (t - t2) + t3 - .75);
18607             },
18608
18609             exponential: function(t) {
18610                 return Math.pow(2, 10 * (t - 1));
18611             },
18612
18613             bounce: function(t) {
18614                 for(var a = 0, b = 1; 1; a += b, b /= 2) {
18615                     if (t >= (7 - 4 * a) / 11) {
18616                         var q = (11 - 6 * a - 11 * t) / 4;
18617                         return -q * q + b * b;
18618                     }
18619                 }
18620             },
18621
18622             reverse: function(f) {
18623                 return function(t) {
18624                     return 1 - f(1 - t)
18625                 }
18626             },
18627
18628             reflect: function(f) {
18629                 return function(t) {
18630                     return .5 * (t < .5 ? f(2 * t) : (2 - f(2 - 2 * t)));
18631                 };
18632             },
18633
18634             clamp: function(f,n,x) {
18635                 n = n || 0;
18636                 x = x || 1;
18637                 return function(t) {
18638                     var r = f(t);
18639                     return r < n ? n : r > x ? x : r;
18640                 }
18641             },
18642
18643             back: function(s) {
18644                 if (!s) s = 1.70158;
18645                 return function(t) {
18646                     return t * t * ((s + 1) * t - s);
18647                 };
18648             },
18649
18650             elastic: function(x) {
18651                 if (!x) x = 1.5;
18652                 return function(t) {
18653                     return Math.pow(2, 10 * (t - 1)) * Math.cos(20*Math.PI*x/3*t);
18654                 }
18655             }
18656
18657         },
18658
18659         interpolate: {
18660
18661             number: function(a, b) {
18662                 var d = b - a;
18663                 return function(t) { return a + d * t; };
18664             },
18665
18666             object: function(a, b) {
18667                 var s = _.keys(a);
18668                 return function(t) {
18669                     var i, p, r = {};
18670                     for (i = s.length - 1; i != -1; i--) {
18671                         p = s[i];
18672                         r[p] = a[p] + (b[p] - a[p]) * t;
18673                     }
18674                     return  r;
18675                 }
18676             },
18677
18678             hexColor: function(a, b) {
18679
18680                 var ca = parseInt(a.slice(1), 16), cb = parseInt(b.slice(1), 16);
18681
18682                 var ra = ca & 0x0000ff, rd = (cb & 0x0000ff) - ra;
18683                 var ga = ca & 0x00ff00, gd = (cb & 0x00ff00) - ga;
18684                 var ba = ca & 0xff0000, bd = (cb & 0xff0000) - ba;
18685
18686                 return function(t) {
18687                     var r = (ra + rd * t) & 0x000000ff;
18688                     var g = (ga + gd * t) & 0x0000ff00;
18689                     var b = (ba + bd * t) & 0x00ff0000;
18690                     return '#' + (1 << 24 | r | g | b ).toString(16).slice(1);
18691                 };
18692             },
18693
18694             unit: function(a, b) {
18695
18696                 var r = /(-?[0-9]*.[0-9]*)(px|em|cm|mm|in|pt|pc|%)/;
18697
18698                 var ma = r.exec(a), mb = r.exec(b);
18699                 var p = mb[1].indexOf('.'), f = p > 0 ? mb[1].length - p - 1 : 0;
18700                 var a = +ma[1], d = +mb[1] - a, u = ma[2];
18701
18702                 return function(t) {
18703                     return (a + d * t).toFixed(f) + u;
18704                 }
18705             }
18706         },
18707
18708         // SVG filters.
18709         filter: {
18710
18711             // `x` ... horizontal blur
18712             // `y` ... vertical blur (optional)
18713             blur: function(args) {
18714                 
18715                 var x = _.isFinite(args.x) ? args.x : 2;
18716
18717                 return _.template('<filter><feGaussianBlur stdDeviation="${stdDeviation}"/></filter>', {
18718                     stdDeviation: _.isFinite(args.y) ? [x, args.y] : x
18719                 });
18720             },
18721
18722             // `dx` ... horizontal shift
18723             // `dy` ... vertical shift
18724             // `blur` ... blur
18725             // `color` ... color
18726             // `opacity` ... opacity
18727             dropShadow: function(args) {
18728
18729                 var tpl = 'SVGFEDropShadowElement' in window
18730                     ? '<filter><feDropShadow stdDeviation="${blur}" dx="${dx}" dy="${dy}" flood-color="${color}" flood-opacity="${opacity}"/></filter>'
18731                     : '<filter><feGaussianBlur in="SourceAlpha" stdDeviation="${blur}"/><feOffset dx="${dx}" dy="${dy}" result="offsetblur"/><feFlood flood-color="${color}"/><feComposite in2="offsetblur" operator="in"/><feComponentTransfer><feFuncA type="linear" slope="${opacity}"/></feComponentTransfer><feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge></filter>';
18732
18733                 return _.template(tpl, {
18734                     dx: args.dx || 0,
18735                     dy: args.dy || 0,
18736                     opacity: _.isFinite(args.opacity) ? args.opacity : 1,
18737                     color: args.color || 'black',
18738                     blur: _.isFinite(args.blur) ? args.blur : 4
18739                 });
18740             },
18741
18742             // `amount` ... the proportion of the conversion. A value of 1 is completely grayscale. A value of 0 leaves the input unchanged.
18743             grayscale: function(args) {
18744
18745                 var amount = _.isFinite(args.amount) ? args.amount : 1;
18746                 
18747                 return _.template('<filter><feColorMatrix type="matrix" values="${a} ${b} ${c} 0 0 ${d} ${e} ${f} 0 0 ${g} ${b} ${h} 0 0 0 0 0 1 0"/></filter>', {
18748                     a: 0.2126 + 0.7874 * (1 - amount),
18749                     b: 0.7152 - 0.7152 * (1 - amount),
18750                     c: 0.0722 - 0.0722 * (1 - amount),
18751                     d: 0.2126 - 0.2126 * (1 - amount),
18752                     e: 0.7152 + 0.2848 * (1 - amount),
18753                     f: 0.0722 - 0.0722 * (1 - amount),
18754                     g: 0.2126 - 0.2126 * (1 - amount),
18755                     h: 0.0722 + 0.9278 * (1 - amount)
18756                 });
18757             },
18758
18759             // `amount` ... the proportion of the conversion. A value of 1 is completely sepia. A value of 0 leaves the input unchanged.
18760             sepia: function(args) {
18761
18762                 var amount = _.isFinite(args.amount) ? args.amount : 1;
18763
18764                 return _.template('<filter><feColorMatrix type="matrix" values="${a} ${b} ${c} 0 0 ${d} ${e} ${f} 0 0 ${g} ${h} ${i} 0 0 0 0 0 1 0"/></filter>', {
18765                     a: 0.393 + 0.607 * (1 - amount),
18766                     b: 0.769 - 0.769 * (1 - amount),
18767                     c: 0.189 - 0.189 * (1 - amount),
18768                     d: 0.349 - 0.349 * (1 - amount),
18769                     e: 0.686 + 0.314 * (1 - amount),
18770                     f: 0.168 - 0.168 * (1 - amount),
18771                     g: 0.272 - 0.272 * (1 - amount),
18772                     h: 0.534 - 0.534 * (1 - amount),
18773                     i: 0.131 + 0.869 * (1 - amount)
18774                 });
18775             },
18776
18777             // `amount` ... the proportion of the conversion. A value of 0 is completely un-saturated. A value of 1 leaves the input unchanged.
18778             saturate: function(args) {
18779
18780                 var amount = _.isFinite(args.amount) ? args.amount : 1;
18781
18782                 return _.template('<filter><feColorMatrix type="saturate" values="${amount}"/></filter>', {
18783                     amount: 1 - amount
18784                 });
18785             },
18786
18787             // `angle` ...  the number of degrees around the color circle the input samples will be adjusted.
18788             hueRotate: function(args) {
18789
18790                 return _.template('<filter><feColorMatrix type="hueRotate" values="${angle}"/></filter>', {
18791                     angle: args.angle || 0
18792                 });
18793             },
18794
18795             // `amount` ... the proportion of the conversion. A value of 1 is completely inverted. A value of 0 leaves the input unchanged.
18796             invert: function(args) {
18797
18798                 var amount = _.isFinite(args.amount) ? args.amount : 1;
18799                 
18800                 return _.template('<filter><feComponentTransfer><feFuncR type="table" tableValues="${amount} ${amount2}"/><feFuncG type="table" tableValues="${amount} ${amount2}"/><feFuncB type="table" tableValues="${amount} ${amount2}"/></feComponentTransfer></filter>', {
18801                     amount: amount,
18802                     amount2: 1 - amount
18803                 });
18804             },
18805
18806             // `amount` ... proportion of the conversion. A value of 0 will create an image that is completely black. A value of 1 leaves the input unchanged.
18807             brightness: function(args) {
18808
18809                 return _.template('<filter><feComponentTransfer><feFuncR type="linear" slope="${amount}"/><feFuncG type="linear" slope="${amount}"/><feFuncB type="linear" slope="${amount}"/></feComponentTransfer></filter>', {
18810                     amount: _.isFinite(args.amount) ? args.amount : 1
18811                 });
18812             },
18813
18814             // `amount` ... proportion of the conversion. A value of 0 will create an image that is completely black. A value of 1 leaves the input unchanged.
18815             contrast: function(args) {
18816
18817                 var amount = _.isFinite(args.amount) ? args.amount : 1;
18818                 
18819                 return _.template('<filter><feComponentTransfer><feFuncR type="linear" slope="${amount}" intercept="${amount2}"/><feFuncG type="linear" slope="${amount}" intercept="${amount2}"/><feFuncB type="linear" slope="${amount}" intercept="${amount2}"/></feComponentTransfer></filter>', {
18820                     amount: amount,
18821                     amount2: .5 - amount / 2
18822                 });
18823             }
18824         },
18825
18826         format: {
18827
18828             // Formatting numbers via the Python Format Specification Mini-language.
18829             // See http://docs.python.org/release/3.1.3/library/string.html#format-specification-mini-language.
18830             // Heavilly inspired by the D3.js library implementation.
18831             number: function(specifier, value, locale) {
18832
18833                 locale = locale || {
18834
18835                     currency: ['$', ''],
18836                     decimal: '.',
18837                     thousands: ',',
18838                     grouping: [3]
18839                 };
18840                 
18841                 // See Python format specification mini-language: http://docs.python.org/release/3.1.3/library/string.html#format-specification-mini-language.
18842                 // [[fill]align][sign][symbol][0][width][,][.precision][type]
18843                 var re = /(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i;
18844
18845                 var match = re.exec(specifier);
18846                 var fill = match[1] || ' ';
18847                 var align = match[2] || '>';
18848                 var sign = match[3] || '';
18849                 var symbol = match[4] || '';
18850                 var zfill = match[5];
18851                 var width = +match[6];
18852                 var comma = match[7];
18853                 var precision = match[8];
18854                 var type = match[9];
18855                 var scale = 1;
18856                 var prefix = '';
18857                 var suffix = '';
18858                 var integer = false;
18859
18860                 if (precision) precision = +precision.substring(1);
18861                 
18862                 if (zfill || fill === '0' && align === '=') {
18863                     zfill = fill = '0';
18864                     align = '=';
18865                     if (comma) width -= Math.floor((width - 1) / 4);
18866                 }
18867
18868                 switch (type) {
18869                   case 'n': comma = true; type = 'g'; break;
18870                   case '%': scale = 100; suffix = '%'; type = 'f'; break;
18871                   case 'p': scale = 100; suffix = '%'; type = 'r'; break;
18872                   case 'b':
18873                   case 'o':
18874                   case 'x':
18875                   case 'X': if (symbol === '#') prefix = '0' + type.toLowerCase();
18876                   case 'c':
18877                   case 'd': integer = true; precision = 0; break;
18878                   case 's': scale = -1; type = 'r'; break;
18879                 }
18880
18881                 if (symbol === '$') {
18882                     prefix = locale.currency[0];
18883                     suffix = locale.currency[1];
18884                 }
18885
18886                 // If no precision is specified for `'r'`, fallback to general notation.
18887                 if (type == 'r' && !precision) type = 'g';
18888
18889                 // Ensure that the requested precision is in the supported range.
18890                 if (precision != null) {
18891                     if (type == 'g') precision = Math.max(1, Math.min(21, precision));
18892                     else if (type == 'e' || type == 'f') precision = Math.max(0, Math.min(20, precision));
18893                 }
18894
18895                 var zcomma = zfill && comma;
18896
18897                 // Return the empty string for floats formatted as ints.
18898                 if (integer && (value % 1)) return '';
18899
18900                 // Convert negative to positive, and record the sign prefix.
18901                 var negative = value < 0 || value === 0 && 1 / value < 0 ? (value = -value, '-') : sign;
18902
18903                 var fullSuffix = suffix;
18904                 
18905                 // Apply the scale, computing it from the value's exponent for si format.
18906                 // Preserve the existing suffix, if any, such as the currency symbol.
18907                 if (scale < 0) {
18908                     var unit = this.prefix(value, precision);
18909                     value = unit.scale(value);
18910                     fullSuffix = unit.symbol + suffix;
18911                 } else {
18912                     value *= scale;
18913                 }
18914
18915                 // Convert to the desired precision.
18916                 value = this.convert(type, value, precision);
18917
18918                 // Break the value into the integer part (before) and decimal part (after).
18919                 var i = value.lastIndexOf('.');
18920                 var before = i < 0 ? value : value.substring(0, i);
18921                 var after = i < 0 ? '' : locale.decimal + value.substring(i + 1);
18922
18923                 function formatGroup(value) {
18924                     
18925                     var i = value.length;
18926                     var t = [];
18927                     var j = 0;
18928                     var g = locale.grouping[0];
18929                     while (i > 0 && g > 0) {
18930                         t.push(value.substring(i -= g, i + g));
18931                         g = locale.grouping[j = (j + 1) % locale.grouping.length];
18932                     }
18933                     return t.reverse().join(locale.thousands);
18934                 }
18935                 
18936                 // If the fill character is not `'0'`, grouping is applied before padding.
18937                 if (!zfill && comma && locale.grouping) {
18938
18939                     before = formatGroup(before);
18940                 }
18941
18942                 var length = prefix.length + before.length + after.length + (zcomma ? 0 : negative.length);
18943                 var padding = length < width ? new Array(length = width - length + 1).join(fill) : '';
18944
18945                 // If the fill character is `'0'`, grouping is applied after padding.
18946                 if (zcomma) before = formatGroup(padding + before);
18947
18948                 // Apply prefix.
18949                 negative += prefix;
18950
18951                 // Rejoin integer and decimal parts.
18952                 value = before + after;
18953
18954                 return (align === '<' ? negative + value + padding
18955                         : align === '>' ? padding + negative + value
18956                         : align === '^' ? padding.substring(0, length >>= 1) + negative + value + padding.substring(length)
18957                         : negative + (zcomma ? value : padding + value)) + fullSuffix;
18958             },
18959
18960             convert: function(type, value, precision) {
18961
18962                 switch (type) {
18963                   case 'b': return value.toString(2);
18964                   case 'c': return String.fromCharCode(value);
18965                   case 'o': return value.toString(8);
18966                   case 'x': return value.toString(16);
18967                   case 'X': return value.toString(16).toUpperCase();
18968                   case 'g': return value.toPrecision(precision);
18969                   case 'e': return value.toExponential(precision);
18970                   case 'f': return value.toFixed(precision);
18971                   case 'r': return (value = this.round(value, this.precision(value, precision))).toFixed(Math.max(0, Math.min(20, this.precision(value * (1 + 1e-15), precision))));
18972                 default: return value + '';
18973                 }
18974             },
18975
18976             round: function(value, precision) {
18977
18978                 return precision
18979                     ? Math.round(value * (precision = Math.pow(10, precision))) / precision
18980                     : Math.round(value);
18981             },
18982
18983             precision: function(value, precision) {
18984                 
18985                 return precision - (value ? Math.ceil(Math.log(value) / Math.LN10) : 1);
18986             },
18987
18988             prefix: function(value, precision) {
18989
18990                 var prefixes = _.map(['y','z','a','f','p','n','µ','m','','k','M','G','T','P','E','Z','Y'], function(d, i) {
18991                     var k = Math.pow(10, abs(8 - i) * 3);
18992                     return {
18993                         scale: i > 8 ? function(d) { return d / k; } : function(d) { return d * k; },
18994                         symbol: d
18995                     };
18996                 });
18997                 
18998                 var i = 0;
18999                 if (value) {
19000                     if (value < 0) value *= -1;
19001                     if (precision) value = d3.round(value, this.precision(value, precision));
19002                     i = 1 + Math.floor(1e-12 + Math.log(value) / Math.LN10);
19003                     i = Math.max(-24, Math.min(24, Math.floor((i <= 0 ? i + 1 : i - 1) / 3) * 3));
19004                 }
19005                 return prefixes[8 + i / 3];
19006             }
19007         }
19008     }
19009 };
19010
19011 if (typeof exports === 'object') {
19012
19013     module.exports = joint;
19014 }
19015
19016 //      JointJS, the JavaScript diagramming library.
19017 //      (c) 2011-2013 client IO
19018
19019
19020 if (typeof exports === 'object') {
19021
19022     var joint = {
19023         dia: {
19024             Link: require('./joint.dia.link').Link,
19025             Element: require('./joint.dia.element').Element
19026         },
19027         shapes: require('../plugins/shapes')
19028     };
19029     var Backbone = require('backbone');
19030     var _ = require('lodash');
19031     var g = require('./geometry');
19032 }
19033
19034
19035
19036 joint.dia.GraphCells = Backbone.Collection.extend({
19037
19038     initialize: function() {
19039         
19040         // Backbone automatically doesn't trigger re-sort if models attributes are changed later when
19041         // they're already in the collection. Therefore, we're triggering sort manually here.
19042         this.on('change:z', this.sort, this);
19043     },
19044
19045     model: function(attrs, options) {
19046
19047         if (attrs.type === 'link') {
19048
19049             return new joint.dia.Link(attrs, options);
19050         }
19051
19052         var module = attrs.type.split('.')[0];
19053         var entity = attrs.type.split('.')[1];
19054
19055         if (joint.shapes[module] && joint.shapes[module][entity]) {
19056
19057             return new joint.shapes[module][entity](attrs, options);
19058         }
19059         
19060         return new joint.dia.Element(attrs, options);
19061     },
19062
19063     // `comparator` makes it easy to sort cells based on their `z` index.
19064     comparator: function(model) {
19065
19066         return model.get('z') || 0;
19067     },
19068
19069     // Get all inbound and outbound links connected to the cell `model`.
19070     getConnectedLinks: function(model, opt) {
19071
19072         opt = opt || {};
19073
19074         if (_.isUndefined(opt.inbound) && _.isUndefined(opt.outbound)) {
19075             opt.inbound = opt.outbound = true;
19076         }
19077
19078         var links = [];
19079         
19080         this.each(function(cell) {
19081
19082             var source = cell.get('source');
19083             var target = cell.get('target');
19084
19085             if (source && source.id === model.id && opt.outbound) {
19086                 
19087                 links.push(cell);
19088             }
19089
19090             if (target && target.id === model.id && opt.inbound) {
19091
19092                 links.push(cell);
19093             }
19094         });
19095
19096         return links;
19097     }
19098 });
19099
19100
19101 joint.dia.Graph = Backbone.Model.extend({
19102
19103     initialize: function() {
19104
19105         this.set('cells', new joint.dia.GraphCells);
19106
19107         // Make all the events fired in the `cells` collection available.
19108         // to the outside world.
19109         this.get('cells').on('all', this.trigger, this);
19110         
19111         this.get('cells').on('remove', this.removeCell, this);
19112     },
19113
19114     toJSON: function() {
19115
19116         // Backbone does not recursively call `toJSON()` on attributes that are themselves models/collections.
19117         // It just clones the attributes. Therefore, we must call `toJSON()` on the cells collection explicitely.
19118         var json = Backbone.Model.prototype.toJSON.apply(this, arguments);
19119         json.cells = this.get('cells').toJSON();
19120         return json;
19121     },
19122
19123     fromJSON: function(json) {
19124
19125         if (!json.cells) {
19126
19127             throw new Error('Graph JSON must contain cells array.');
19128         }
19129
19130         var attrs = json;
19131
19132         // Cells are the only attribute that is being set differently, using `cells.add()`.
19133         var cells = json.cells;
19134         delete attrs.cells;
19135         
19136         this.set(attrs);
19137         
19138         this.resetCells(cells);
19139     },
19140
19141     clear: function() {
19142
19143         this.trigger('batch:start');
19144         this.get('cells').remove(this.get('cells').models);
19145         this.trigger('batch:stop');
19146     },
19147
19148     _prepareCell: function(cell) {
19149
19150         if (cell instanceof Backbone.Model && _.isUndefined(cell.get('z'))) {
19151
19152             cell.set('z', this.maxZIndex() + 1, { silent: true });
19153             
19154         } else if (_.isUndefined(cell.z)) {
19155
19156             cell.z = this.maxZIndex() + 1;
19157         }
19158
19159         return cell;
19160     },
19161
19162     maxZIndex: function() {
19163
19164         var lastCell = this.get('cells').last();
19165         return lastCell ? (lastCell.get('z') || 0) : 0;
19166     },
19167
19168     addCell: function(cell, options) {
19169
19170         if (_.isArray(cell)) {
19171
19172             return this.addCells(cell, options);
19173         }
19174
19175         this.get('cells').add(this._prepareCell(cell), options || {});
19176
19177         return this;
19178     },
19179
19180     addCells: function(cells, options) {
19181
19182         _.each(cells, function(cell) { this.addCell(cell, options); }, this);
19183
19184         return this;
19185     },
19186
19187     // When adding a lot of cells, it is much more efficient to
19188     // reset the entire cells collection in one go.
19189     // Useful for bulk operations and optimizations.
19190     resetCells: function(cells) {
19191         
19192         this.get('cells').reset(_.map(cells, this._prepareCell, this));
19193
19194         return this;
19195     },
19196
19197     removeCell: function(cell, collection, options) {
19198
19199         // Applications might provide a `disconnectLinks` option set to `true` in order to
19200         // disconnect links when a cell is removed rather then removing them. The default
19201         // is to remove all the associated links.
19202         if (options && options.disconnectLinks) {
19203             
19204             this.disconnectLinks(cell);
19205
19206         } else {
19207
19208             this.removeLinks(cell);
19209         }
19210
19211         // Silently remove the cell from the cells collection. Silently, because
19212         // `joint.dia.Cell.prototype.remove` already triggers the `remove` event which is
19213         // then propagated to the graph model. If we didn't remove the cell silently, two `remove` events
19214         // would be triggered on the graph model.
19215         this.get('cells').remove(cell, { silent: true });
19216     },
19217
19218     // Get a cell by `id`.
19219     getCell: function(id) {
19220
19221         return this.get('cells').get(id);
19222     },
19223
19224     getElements: function() {
19225
19226         return this.get('cells').filter(function(cell) {
19227
19228             return cell instanceof joint.dia.Element;
19229         });
19230     },
19231     
19232     getLinks: function() {
19233
19234         return this.get('cells').filter(function(cell) {
19235
19236             return cell instanceof joint.dia.Link;
19237         });
19238     },
19239
19240     // Get all inbound and outbound links connected to the cell `model`.
19241     getConnectedLinks: function(model, opt) {
19242
19243         return this.get('cells').getConnectedLinks(model, opt);
19244     },
19245
19246     getNeighbors: function(el) {
19247
19248         var links = this.getConnectedLinks(el);
19249         var neighbors = [];
19250         var cells = this.get('cells');
19251         
19252         _.each(links, function(link) {
19253
19254             var source = link.get('source');
19255             var target = link.get('target');
19256
19257             // Discard if it is a point.
19258             if (!source.x) {
19259                 var sourceElement = cells.get(source.id);
19260                 if (sourceElement !== el) {
19261
19262                     neighbors.push(sourceElement);
19263                 }
19264             }
19265             if (!target.x) {
19266                 var targetElement = cells.get(target.id);
19267                 if (targetElement !== el) {
19268
19269                     neighbors.push(targetElement);
19270                 }
19271             }
19272         });
19273
19274         return neighbors;
19275     },
19276     
19277     // Disconnect links connected to the cell `model`.
19278     disconnectLinks: function(model) {
19279
19280         _.each(this.getConnectedLinks(model), function(link) {
19281
19282             link.set(link.get('source').id === model.id ? 'source' : 'target', g.point(0, 0));
19283         });
19284     },
19285
19286     // Remove links connected to the cell `model` completely.
19287     removeLinks: function(model) {
19288
19289         _.invoke(this.getConnectedLinks(model), 'remove');
19290     },
19291
19292     // Find all views at given point
19293     findModelsFromPoint: function(p) {
19294
19295         return _.filter(this.getElements(), function(el) {
19296             return el.getBBox().containsPoint(p);
19297         });
19298     },
19299
19300
19301     // Find all views in given area
19302     findModelsInArea: function(r) {
19303
19304         return _.filter(this.getElements(), function(el) {
19305             return el.getBBox().intersect(r);
19306         });
19307     }
19308
19309 });
19310
19311
19312 if (typeof exports === 'object') {
19313
19314     module.exports.Graph = joint.dia.Graph;
19315 }
19316 //      JointJS.
19317 //      (c) 2011-2013 client IO
19318
19319
19320 if (typeof exports === 'object') {
19321
19322     var joint = {
19323         util: require('./core').util,
19324         dia: {
19325             Link: require('./joint.dia.link').Link
19326         }
19327     };
19328     var Backbone = require('backbone');
19329     var _ = require('lodash');
19330 }
19331
19332
19333 // joint.dia.Cell base model.
19334 // --------------------------
19335
19336 joint.dia.Cell = Backbone.Model.extend({
19337
19338     // This is the same as Backbone.Model with the only difference that is uses _.merge
19339     // instead of just _.extend. The reason is that we want to mixin attributes set in upper classes.
19340     constructor: function(attributes, options) {
19341
19342         var defaults;
19343         var attrs = attributes || {};
19344         this.cid = _.uniqueId('c');
19345         this.attributes = {};
19346         if (options && options.collection) this.collection = options.collection;
19347         if (options && options.parse) attrs = this.parse(attrs, options) || {};
19348         if (defaults = _.result(this, 'defaults')) {
19349             //<custom code>
19350             // Replaced the call to _.defaults with _.merge.
19351             attrs = _.merge({}, defaults, attrs);
19352             //</custom code>
19353         }
19354         this.set(attrs, options);
19355         this.changed = {};
19356         this.initialize.apply(this, arguments);
19357     },
19358
19359     toJSON: function() {
19360
19361         var defaultAttrs = this.constructor.prototype.defaults.attrs || {};
19362         var attrs = this.attributes.attrs;
19363         var finalAttrs = {};
19364
19365         // Loop through all the attributes and
19366         // omit the default attributes as they are implicitly reconstructable by the cell 'type'.
19367         _.each(attrs, function(attr, selector) {
19368
19369             var defaultAttr = defaultAttrs[selector];
19370
19371             _.each(attr, function(value, name) {
19372                 
19373                 // attr is mainly flat though it might have one more level (consider the `style` attribute).
19374                 // Check if the `value` is object and if yes, go one level deep.
19375                 if (_.isObject(value) && !_.isArray(value)) {
19376                     
19377                     _.each(value, function(value2, name2) {
19378
19379                         if (!defaultAttr || !defaultAttr[name] || !_.isEqual(defaultAttr[name][name2], value2)) {
19380
19381                             finalAttrs[selector] = finalAttrs[selector] || {};
19382                             (finalAttrs[selector][name] || (finalAttrs[selector][name] = {}))[name2] = value2;
19383                         }
19384                     });
19385
19386                 } else if (!defaultAttr || !_.isEqual(defaultAttr[name], value)) {
19387                     // `value` is not an object, default attribute for such a selector does not exist
19388                     // or it is different than the attribute value set on the model.
19389
19390                     finalAttrs[selector] = finalAttrs[selector] || {};
19391                     finalAttrs[selector][name] = value;
19392                 }
19393             });
19394         });
19395
19396         var attributes = _.cloneDeep(_.omit(this.attributes, 'attrs'));
19397         //var attributes = JSON.parse(JSON.stringify(_.omit(this.attributes, 'attrs')));
19398         attributes.attrs = finalAttrs;
19399
19400         return attributes;
19401     },
19402
19403     initialize: function(options) {
19404
19405         if (!options || !options.id) {
19406
19407             this.set('id', joint.util.uuid(), { silent: true });
19408         }
19409
19410         this._transitionIds = {};
19411
19412         // Collect ports defined in `attrs` and keep collecting whenever `attrs` object changes.
19413         this.processPorts();
19414         this.on('change:attrs', this.processPorts, this);
19415     },
19416
19417     processPorts: function() {
19418
19419         // Whenever `attrs` changes, we extract ports from the `attrs` object and store it
19420         // in a more accessible way. Also, if any port got removed and there were links that had `target`/`source`
19421         // set to that port, we remove those links as well (to follow the same behaviour as
19422         // with a removed element).
19423
19424         var previousPorts = this.ports;
19425
19426         // Collect ports from the `attrs` object.
19427         var ports = {};
19428         _.each(this.get('attrs'), function(attrs, selector) {
19429
19430             if (attrs && attrs.port) {
19431
19432                 // `port` can either be directly an `id` or an object containing an `id` (and potentially other data).
19433                 if (!_.isUndefined(attrs.port.id)) {
19434                     ports[attrs.port.id] = attrs.port;
19435                 } else {
19436                     ports[attrs.port] = { id: attrs.port };
19437                 }
19438             }
19439         });
19440
19441         // Collect ports that have been removed (compared to the previous ports) - if any.
19442         // Use hash table for quick lookup.
19443         var removedPorts = {};
19444         _.each(previousPorts, function(port, id) {
19445
19446             if (!ports[id]) removedPorts[id] = true;
19447         });
19448
19449         // Remove all the incoming/outgoing links that have source/target port set to any of the removed ports.
19450         if (this.collection && !_.isEmpty(removedPorts)) {
19451             
19452             var inboundLinks = this.collection.getConnectedLinks(this, { inbound: true });
19453             _.each(inboundLinks, function(link) {
19454
19455                 if (removedPorts[link.get('target').port]) link.remove();
19456             });
19457
19458             var outboundLinks = this.collection.getConnectedLinks(this, { outbound: true });
19459             _.each(outboundLinks, function(link) {
19460
19461                 if (removedPorts[link.get('source').port]) link.remove();
19462             });
19463         }
19464
19465         // Update the `ports` object.
19466         this.ports = ports;
19467     },
19468
19469     remove: function(options) {
19470
19471         var collection = this.collection;
19472
19473         if (collection) {
19474             collection.trigger('batch:start');
19475         }
19476
19477         // First, unembed this cell from its parent cell if there is one.
19478         var parentCellId = this.get('parent');
19479         if (parentCellId) {
19480             
19481             var parentCell = this.collection && this.collection.get(parentCellId);
19482             parentCell.unembed(this);
19483         }
19484         
19485         _.invoke(this.getEmbeddedCells(), 'remove', options);
19486         
19487         this.trigger('remove', this, this.collection, options);
19488
19489         if (collection) {
19490             collection.trigger('batch:stop');
19491         }
19492     },
19493
19494     toFront: function() {
19495
19496         if (this.collection) {
19497
19498             this.set('z', (this.collection.last().get('z') || 0) + 1);
19499         }
19500     },
19501     
19502     toBack: function() {
19503
19504         if (this.collection) {
19505             
19506             this.set('z', (this.collection.first().get('z') || 0) - 1);
19507         }
19508     },
19509
19510     embed: function(cell) {
19511
19512         if (this.get('parent') == cell.id) {
19513
19514             throw new Error('Recursive embedding not allowed.');
19515
19516         } else {
19517
19518             this.trigger('batch:start');
19519
19520             cell.set('parent', this.id);
19521             this.set('embeds', _.uniq((this.get('embeds') || []).concat([cell.id])));
19522
19523             this.trigger('batch:stop');
19524         }
19525     },
19526
19527     unembed: function(cell) {
19528
19529         this.trigger('batch:start');
19530
19531         var cellId = cell.id;
19532         cell.unset('parent');
19533
19534         this.set('embeds', _.without(this.get('embeds'), cellId));
19535
19536         this.trigger('batch:stop');
19537     },
19538
19539     getEmbeddedCells: function() {
19540
19541         // Cell models can only be retrieved when this element is part of a collection.
19542         // There is no way this element knows about other cells otherwise.
19543         // This also means that calling e.g. `translate()` on an element with embeds before
19544         // adding it to a graph does not translate its embeds.
19545         if (this.collection) {
19546
19547             return _.map(this.get('embeds') || [], function(cellId) {
19548
19549                 return this.collection.get(cellId);
19550                 
19551             }, this);
19552         }
19553         return [];
19554     },
19555
19556     clone: function(opt) {
19557
19558         opt = opt || {};
19559
19560         var clone = Backbone.Model.prototype.clone.apply(this, arguments);
19561         
19562         // We don't want the clone to have the same ID as the original.
19563         clone.set('id', joint.util.uuid(), { silent: true });
19564         clone.set('embeds', '');
19565
19566         if (!opt.deep) return clone;
19567
19568         // The rest of the `clone()` method deals with embeds. If `deep` option is set to `true`,
19569         // the return value is an array of all the embedded clones created.
19570
19571         var embeds = this.getEmbeddedCells();
19572
19573         var clones = [clone];
19574
19575         // This mapping stores cloned links under the `id`s of they originals.
19576         // This prevents cloning a link more then once. Consider a link 'self loop' for example.
19577         var linkCloneMapping = {};
19578         
19579         _.each(embeds, function(embed) {
19580
19581             var embedClones = embed.clone({ deep: true });
19582
19583             // Embed the first clone returned from `clone({ deep: true })` above. The first
19584             // cell is always the clone of the cell that called the `clone()` method, i.e. clone of `embed` in this case.
19585             clone.embed(embedClones[0]);
19586
19587             _.each(embedClones, function(embedClone) {
19588
19589                 clones.push(embedClone);
19590
19591                 // Skip links. Inbound/outbound links are not relevant for them.
19592                 if (embedClone instanceof joint.dia.Link) {
19593
19594                     return;
19595                 }
19596
19597                 // Collect all inbound links, clone them (if not done already) and set their target to the `embedClone.id`.
19598                 var inboundLinks = this.collection.getConnectedLinks(embed, { inbound: true });
19599
19600                 _.each(inboundLinks, function(link) {
19601
19602                     var linkClone = linkCloneMapping[link.id] || link.clone();
19603
19604                     // Make sure we don't clone a link more then once.
19605                     linkCloneMapping[link.id] = linkClone;
19606
19607                     var target = _.clone(linkClone.get('target'));
19608                     target.id = embedClone.id;
19609                     linkClone.set('target', target);
19610                 });
19611
19612                 // Collect all inbound links, clone them (if not done already) and set their source to the `embedClone.id`.
19613                 var outboundLinks = this.collection.getConnectedLinks(embed, { outbound: true });
19614
19615                 _.each(outboundLinks, function(link) {
19616
19617                     var linkClone = linkCloneMapping[link.id] || link.clone();
19618
19619                     // Make sure we don't clone a link more then once.
19620                     linkCloneMapping[link.id] = linkClone;
19621
19622                     var source = _.clone(linkClone.get('source'));
19623                     source.id = embedClone.id;
19624                     linkClone.set('source', source);
19625                 });
19626
19627             }, this);
19628             
19629         }, this);
19630
19631         // Add link clones to the array of all the new clones.
19632         clones = clones.concat(_.values(linkCloneMapping));
19633
19634         return clones;
19635     },
19636
19637     // A convenient way to set nested attributes.
19638     attr: function(attrs, value, opt) {
19639
19640         var currentAttrs = this.get('attrs');
19641         var delim = '/';
19642         
19643         if (_.isString(attrs)) {
19644             // Get/set an attribute by a special path syntax that delimits
19645             // nested objects by the colon character.
19646
19647             if (typeof value != 'undefined') {
19648
19649                 var attr = {};
19650                 joint.util.setByPath(attr, attrs, value, delim);
19651                 return this.set('attrs', _.merge({}, currentAttrs, attr), opt);
19652                 
19653             } else {
19654                 
19655                 return joint.util.getByPath(currentAttrs, attrs, delim);
19656             }
19657         }
19658         
19659         return this.set('attrs', _.merge({}, currentAttrs, attrs), value, opt);
19660     },
19661
19662     // A convenient way to unset nested attributes
19663     removeAttr: function(path, opt) {
19664
19665         if (_.isArray(path)) {
19666             _.each(path, function(p) { this.removeAttr(p, opt); }, this);
19667             return this;
19668         }
19669         
19670         var attrs = joint.util.unsetByPath(_.merge({}, this.get('attrs')), path, '/');
19671
19672         return this.set('attrs', attrs, _.extend({ dirty: true }, opt));
19673     },
19674
19675     transition: function(path, value, opt, delim) {
19676
19677         delim = delim || '/';
19678
19679         var defaults = {
19680             duration: 100,
19681             delay: 10,
19682             timingFunction: joint.util.timing.linear,
19683             valueFunction: joint.util.interpolate.number
19684         };
19685
19686         opt = _.extend(defaults, opt);
19687
19688         var pathArray = path.split(delim);
19689         var property = pathArray[0];
19690         var isPropertyNested = pathArray.length > 1;
19691         var firstFrameTime = 0;
19692         var interpolatingFunction;
19693
19694         var setter = _.bind(function(runtime) {
19695
19696             var id, progress, propertyValue, status;
19697
19698             firstFrameTime = firstFrameTime || runtime;
19699             runtime -= firstFrameTime;
19700             progress = runtime / opt.duration;
19701
19702             if (progress < 1) {
19703                 this._transitionIds[path] = id = joint.util.nextFrame(setter);
19704             } else {
19705                 progress = 1;
19706                 delete this._transitionIds[path];
19707             }
19708
19709             propertyValue = interpolatingFunction(opt.timingFunction(progress));
19710
19711             if (isPropertyNested) {
19712                 var nestedPropertyValue = joint.util.setByPath({}, path, propertyValue, delim)[property];
19713                 propertyValue = _.merge({}, this.get(property), nestedPropertyValue);
19714             }
19715
19716             opt.transitionId = id;
19717
19718             this.set(property, propertyValue, opt);
19719
19720             if (!id) this.trigger('transition:end', this, path);
19721
19722         }, this);
19723
19724         var initiator =_.bind(function(callback) {
19725
19726             this.stopTransitions(path);
19727
19728             interpolatingFunction = opt.valueFunction(joint.util.getByPath(this.attributes, path, delim), value);
19729
19730             this._transitionIds[path] = joint.util.nextFrame(callback);
19731
19732             this.trigger('transition:start', this, path);
19733
19734         }, this);
19735
19736         return _.delay(initiator, opt.delay, setter);
19737     },
19738
19739     getTransitions: function() {
19740         return _.keys(this._transitionIds);
19741     },
19742
19743     stopTransitions: function(path, delim) {
19744
19745         delim = delim || '/';
19746
19747         var pathArray = path && path.split(delim);
19748
19749         _(this._transitionIds).keys().filter(pathArray && function(key) {
19750
19751             return _.isEqual(pathArray, key.split(delim).slice(0, pathArray.length));
19752
19753         }).each(function(key) {
19754
19755             joint.util.cancelFrame(this._transitionIds[key]);
19756
19757             delete this._transitionIds[key];
19758
19759             this.trigger('transition:end', this, key);
19760
19761         }, this);
19762     }
19763 });
19764
19765 // joint.dia.CellView base view and controller.
19766 // --------------------------------------------
19767
19768 // This is the base view and controller for `joint.dia.ElementView` and `joint.dia.LinkView`.
19769
19770 joint.dia.CellView = Backbone.View.extend({
19771
19772     tagName: 'g',
19773
19774     attributes: function() {
19775
19776         return { 'model-id': this.model.id }
19777     },
19778
19779     initialize: function() {
19780
19781         _.bindAll(this, 'remove', 'update');
19782
19783         // Store reference to this to the <g> DOM element so that the view is accessible through the DOM tree.
19784         this.$el.data('view', this);
19785
19786         this.listenTo(this.model, 'remove', this.remove);
19787         this.listenTo(this.model, 'change:attrs', this.onChangeAttrs);
19788     },
19789
19790     onChangeAttrs: function(cell, attrs, opt) {
19791
19792         if (opt.dirty) {
19793
19794             // dirty flag could be set when a model attribute was removed and it needs to be cleared
19795             // also from the DOM element. See cell.removeAttr().
19796             return this.render();
19797         }
19798
19799         return this.update();
19800     },
19801
19802     _configure: function(options) {
19803
19804         // Make sure a global unique id is assigned to this view. Store this id also to the properties object.
19805         // The global unique id makes sure that the same view can be rendered on e.g. different machines and
19806         // still be associated to the same object among all those clients. This is necessary for real-time
19807         // collaboration mechanism.
19808         options.id = options.id || joint.util.guid(this);
19809         
19810         Backbone.View.prototype._configure.apply(this, arguments);
19811     },
19812
19813     // Override the Backbone `_ensureElement()` method in order to create a `<g>` node that wraps
19814     // all the nodes of the Cell view.
19815     _ensureElement: function() {
19816
19817         var el;
19818
19819         if (!this.el) {
19820
19821             var attrs = _.extend({ id: this.id }, _.result(this, 'attributes'));
19822             if (this.className) attrs['class'] = _.result(this, 'className');
19823             el = V(_.result(this, 'tagName'), attrs).node;
19824
19825         } else {
19826
19827             el = _.result(this, 'el')
19828         }
19829
19830         this.setElement(el, false);
19831     },
19832     
19833     findBySelector: function(selector) {
19834
19835         // These are either descendants of `this.$el` of `this.$el` itself. 
19836        // `.` is a special selector used to select the wrapping `<g>` element.
19837         var $selected = selector === '.' ? this.$el : this.$el.find(selector);
19838         return $selected;
19839     },
19840
19841     notify: function(evt) {
19842
19843         if (this.paper) {
19844
19845             var args = Array.prototype.slice.call(arguments, 1);
19846
19847             // Trigger the event on both the element itself and also on the paper.
19848             this.trigger.apply(this, [evt].concat(args));
19849             
19850             // Paper event handlers receive the view object as the first argument.
19851             this.paper.trigger.apply(this.paper, [evt, this].concat(args));
19852         }
19853     },
19854
19855     getStrokeBBox: function(el) {
19856         // Return a bounding box rectangle that takes into account stroke.
19857         // Note that this is a naive and ad-hoc implementation that does not
19858         // works only in certain cases and should be replaced as soon as browsers will
19859         // start supporting the getStrokeBBox() SVG method.
19860         // @TODO any better solution is very welcome!
19861
19862         var isMagnet = !!el;
19863         
19864         el = el || this.el;
19865         var bbox = V(el).bbox(false, this.paper.viewport);
19866
19867         var strokeWidth;
19868         if (isMagnet) {
19869
19870             strokeWidth = V(el).attr('stroke-width');
19871             
19872         } else {
19873
19874             strokeWidth = this.model.attr('rect/stroke-width') || this.model.attr('circle/stroke-width') || this.model.attr('ellipse/stroke-width') || this.model.attr('path/stroke-width');
19875         }
19876
19877         strokeWidth = parseFloat(strokeWidth) || 0;
19878
19879         return g.rect(bbox).moveAndExpand({ x: -strokeWidth/2, y: -strokeWidth/2, width: strokeWidth, height: strokeWidth });
19880     },
19881     
19882     getBBox: function() {
19883
19884         return V(this.el).bbox();
19885     },
19886
19887     highlight: function(el) {
19888
19889         el = !el ? this.el : this.$(el)[0] || this.el;
19890
19891         V(el).addClass('highlighted');
19892     },
19893
19894     unhighlight: function(el) {
19895
19896         el = !el ? this.el : this.$(el)[0] || this.el;
19897
19898         V(el).removeClass('highlighted');
19899     },
19900
19901     // Find the closest element that has the `magnet` attribute set to `true`. If there was not such
19902     // an element found, return the root element of the cell view.
19903     findMagnet: function(el) {
19904
19905         var $el = this.$(el);
19906
19907         if ($el.length === 0 || $el[0] === this.el) {
19908
19909             // If the overall cell has set `magnet === false`, then return `undefined` to
19910             // announce there is no magnet found for this cell.
19911             // This is especially useful to set on cells that have 'ports'. In this case,
19912             // only the ports have set `magnet === true` and the overall element has `magnet === false`.
19913             var attrs = this.model.get('attrs') || {};
19914             if (attrs['.'] && attrs['.']['magnet'] === false) {
19915                 return undefined;
19916             }
19917
19918             return this.el;
19919         }
19920
19921         if ($el.attr('magnet')) {
19922
19923             return $el[0];
19924         }
19925
19926         return this.findMagnet($el.parent());
19927     },
19928
19929     // `selector` is a CSS selector or `'.'`. `filter` must be in the special JointJS filter format:
19930     // `{ name: <name of the filter>, args: { <arguments>, ... }`.
19931     // An example is: `{ filter: { name: 'blur', args: { radius: 5 } } }`.
19932     applyFilter: function(selector, filter) {
19933
19934         var $selected = this.findBySelector(selector);
19935
19936         // Generate a hash code from the stringified filter definition. This gives us
19937         // a unique filter ID for different definitions.
19938         var filterId = filter.name + this.paper.svg.id + joint.util.hashCode(JSON.stringify(filter));
19939
19940         // If the filter already exists in the document,
19941         // we're done and we can just use it (reference it using `url()`).
19942         // If not, create one.
19943         if (!this.paper.svg.getElementById(filterId)) {
19944
19945             var filterSVGString = joint.util.filter[filter.name] && joint.util.filter[filter.name](filter.args || {});
19946             if (!filterSVGString) {
19947                 throw new Error('Non-existing filter ' + filter.name);
19948             }
19949             var filterElement = V(filterSVGString);
19950             filterElement.attr('filterUnits', 'userSpaceOnUse');
19951             if (filter.attrs) filterElement.attr(filter.attrs);
19952             filterElement.node.id = filterId;
19953             V(this.paper.svg).defs().append(filterElement);
19954         }
19955
19956         $selected.each(function() {
19957             
19958             V(this).attr('filter', 'url(#' + filterId + ')');
19959         });
19960     },
19961
19962     // `selector` is a CSS selector or `'.'`. `attr` is either a `'fill'` or `'stroke'`.
19963     // `gradient` must be in the special JointJS gradient format:
19964     // `{ type: <linearGradient|radialGradient>, stops: [ { offset: <offset>, color: <color> }, ... ]`.
19965     // An example is: `{ fill: { type: 'linearGradient', stops: [ { offset: '10%', color: 'green' }, { offset: '50%', color: 'blue' } ] } }`.
19966     applyGradient: function(selector, attr, gradient) {
19967
19968         var $selected = this.findBySelector(selector);
19969
19970         // Generate a hash code from the stringified filter definition. This gives us
19971         // a unique filter ID for different definitions.
19972         var gradientId = gradient.type + this.paper.svg.id + joint.util.hashCode(JSON.stringify(gradient));
19973
19974         // If the gradient already exists in the document,
19975         // we're done and we can just use it (reference it using `url()`).
19976         // If not, create one.
19977         if (!this.paper.svg.getElementById(gradientId)) {
19978
19979             var gradientSVGString = [
19980                 '<' + gradient.type + '>',
19981                 _.map(gradient.stops, function(stop) {
19982                     return '<stop offset="' + stop.offset + '" stop-color="' + stop.color + '" stop-opacity="' + (_.isFinite(stop.opacity) ? stop.opacity : 1) + '" />'
19983                 }).join(''),
19984                 '</' + gradient.type + '>'
19985             ].join('');
19986             
19987             var gradientElement = V(gradientSVGString);
19988             if (gradient.attrs) { gradientElement.attr(gradient.attrs); }
19989             gradientElement.node.id = gradientId;
19990             V(this.paper.svg).defs().append(gradientElement);
19991         }
19992
19993         $selected.each(function() {
19994             
19995             V(this).attr(attr, 'url(#' + gradientId + ')');
19996         });
19997     },
19998
19999     // Construct a unique selector for the `el` element within this view.
20000     // `selector` is being collected through the recursive call. No value for `selector` is expected when using this method.
20001     getSelector: function(el, selector) {
20002
20003         if (el === this.el) {
20004
20005             return selector;
20006         }
20007
20008         var index = $(el).index();
20009
20010         selector = el.tagName + ':nth-child(' + (index + 1) + ')' + ' ' + (selector || '');
20011
20012         return this.getSelector($(el).parent()[0], selector + ' ');
20013     },
20014
20015     // Interaction. The controller part.
20016     // ---------------------------------
20017
20018     // Interaction is handled by the paper and delegated to the view in interest.
20019     // `x` & `y` parameters passed to these functions represent the coordinates already snapped to the paper grid.
20020     // If necessary, real coordinates can be obtained from the `evt` event object.
20021
20022     // These functions are supposed to be overriden by the views that inherit from `joint.dia.Cell`,
20023     // i.e. `joint.dia.Element` and `joint.dia.Link`.
20024
20025     pointerdblclick: function(evt, x, y) {
20026
20027         this.notify('cell:pointerdblclick', evt, x, y);
20028     },
20029
20030     pointerclick: function(evt, x, y) {
20031
20032         this.notify('cell:pointerclick', evt, x, y);
20033     },
20034     
20035     pointerdown: function(evt, x, y) {
20036
20037         if (this.model.collection) {
20038             this.model.trigger('batch:start');
20039             this._collection = this.model.collection;
20040         }
20041
20042         this.notify('cell:pointerdown', evt, x, y);
20043     },
20044     
20045     pointermove: function(evt, x, y) {
20046
20047         this.notify('cell:pointermove', evt, x, y);
20048     },
20049     
20050     pointerup: function(evt, x, y) {
20051
20052         this.notify('cell:pointerup', evt, x, y);
20053
20054         if (this._collection) {
20055             // we don't want to trigger event on model as model doesn't
20056             // need to be member of collection anymore (remove)
20057             this._collection.trigger('batch:stop');
20058             delete this._collection;
20059         }
20060
20061     }
20062 });
20063
20064
20065 if (typeof exports === 'object') {
20066
20067     module.exports.Cell = joint.dia.Cell;
20068     module.exports.CellView = joint.dia.CellView;
20069 }
20070
20071 //      JointJS library.
20072 //      (c) 2011-2013 client IO
20073
20074
20075 if (typeof exports === 'object') {
20076
20077     var joint = {
20078         util: require('./core').util,
20079         dia: {
20080             Cell: require('./joint.dia.cell').Cell,
20081             CellView: require('./joint.dia.cell').CellView
20082         }
20083     };
20084     var Backbone = require('backbone');
20085     var _ = require('lodash');
20086 }
20087
20088
20089 // joint.dia.Element base model.
20090 // -----------------------------
20091
20092 joint.dia.Element = joint.dia.Cell.extend({
20093
20094     defaults: {
20095         position: { x: 0, y: 0 },
20096         size: { width: 1, height: 1 },
20097         angle: 0
20098     },
20099
20100     position: function(x, y) {
20101
20102         this.set('position', { x: x, y: y });
20103     },
20104     
20105     translate: function(tx, ty, opt) {
20106
20107         ty = ty || 0;
20108
20109         if (tx === 0 && ty === 0) {
20110             // Like nothing has happened.
20111             return this;
20112         }
20113
20114         var position = this.get('position') || { x: 0, y: 0 };
20115         var translatedPosition = { x: position.x + tx || 0, y: position.y + ty || 0 };
20116
20117         if (opt && opt.transition) {
20118
20119             if (!_.isObject(opt.transition)) opt.transition = {};
20120
20121             this.transition('position', translatedPosition, _.extend({}, opt.transition, {
20122                 valueFunction: joint.util.interpolate.object
20123             }));
20124
20125         } else {
20126
20127             this.set('position', translatedPosition, opt);
20128
20129             // Recursively call `translate()` on all the embeds cells.
20130             _.invoke(this.getEmbeddedCells(), 'translate', tx, ty, opt);
20131         }
20132
20133         return this;
20134     },
20135
20136     resize: function(width, height) {
20137
20138         this.trigger('batch:start');
20139         this.set('size', { width: width, height: height });
20140         this.trigger('batch:stop');
20141
20142         return this;
20143     },
20144
20145     rotate: function(angle, absolute) {
20146
20147         return this.set('angle', absolute ? angle : ((this.get('angle') || 0) + angle) % 360);
20148     },
20149
20150     getBBox: function() {
20151
20152         var position = this.get('position');
20153         var size = this.get('size');
20154
20155         return g.rect(position.x, position.y, size.width, size.height);
20156     }
20157 });
20158
20159 // joint.dia.Element base view and controller.
20160 // -------------------------------------------
20161
20162 joint.dia.ElementView = joint.dia.CellView.extend({
20163
20164     className: function() {
20165         return 'element ' + this.model.get('type').split('.').join(' ');
20166     },
20167
20168     initialize: function() {
20169
20170         _.bindAll(this, 'translate', 'resize', 'rotate');
20171
20172         joint.dia.CellView.prototype.initialize.apply(this, arguments);
20173         
20174         this.listenTo(this.model, 'change:position', this.translate);
20175         this.listenTo(this.model, 'change:size', this.resize);
20176         this.listenTo(this.model, 'change:angle', this.rotate);
20177     },
20178
20179     // Default is to process the `attrs` object and set attributes on subelements based on the selectors.
20180     update: function(cell, renderingOnlyAttrs) {
20181
20182         var allAttrs = this.model.get('attrs');
20183
20184         var rotatable = V(this.$('.rotatable')[0]);
20185         if (rotatable) {
20186
20187             var rotation = rotatable.attr('transform');
20188             rotatable.attr('transform', '');
20189         }
20190         
20191         var relativelyPositioned = [];
20192
20193         _.each(renderingOnlyAttrs || allAttrs, function(attrs, selector) {
20194
20195             // Elements that should be updated.
20196             var $selected = this.findBySelector(selector);
20197
20198             // No element matched by the `selector` was found. We're done then.
20199             if ($selected.length === 0) return;
20200
20201             // Special attributes are treated by JointJS, not by SVG.
20202             var specialAttributes = ['style', 'text', 'html', 'ref-x', 'ref-y', 'ref-dx', 'ref-dy', 'ref-width', 'ref-height', 'ref', 'x-alignment', 'y-alignment', 'port'];
20203
20204             // If the `filter` attribute is an object, it is in the special JointJS filter format and so
20205             // it becomes a special attribute and is treated separately.
20206             if (_.isObject(attrs.filter)) {
20207
20208                 specialAttributes.push('filter');
20209                 this.applyFilter(selector, attrs.filter);
20210             }
20211
20212             // If the `fill` or `stroke` attribute is an object, it is in the special JointJS gradient format and so
20213             // it becomes a special attribute and is treated separately.
20214             if (_.isObject(attrs.fill)) {
20215
20216                 specialAttributes.push('fill');
20217                 this.applyGradient(selector, 'fill', attrs.fill);
20218             }
20219             if (_.isObject(attrs.stroke)) {
20220
20221                 specialAttributes.push('stroke');
20222                 this.applyGradient(selector, 'stroke', attrs.stroke);
20223             }
20224
20225             // Make special case for `text` attribute. So that we can set text content of the `<text>` element
20226             // via the `attrs` object as well.
20227             // Note that it's important to set text before applying the rest of the final attributes.
20228             // Vectorizer `text()` method sets on the element its own attributes and it has to be possible
20229             // to rewrite them, if needed. (i.e display: 'none')
20230             if (!_.isUndefined(attrs.text)) {
20231
20232                 $selected.each(function() {
20233
20234                     V(this).text(attrs.text + '');
20235                 });
20236             }
20237
20238             // Set regular attributes on the `$selected` subelement. Note that we cannot use the jQuery attr()
20239             // method as some of the attributes might be namespaced (e.g. xlink:href) which fails with jQuery attr().
20240             var finalAttributes = _.omit(attrs, specialAttributes);
20241             
20242             $selected.each(function() {
20243                 
20244                 V(this).attr(finalAttributes);
20245             });
20246
20247             // `port` attribute contains the `id` of the port that the underlying magnet represents.
20248             if (attrs.port) {
20249
20250                 $selected.attr('port', _.isUndefined(attrs.port.id) ? attrs.port : attrs.port.id);
20251             }
20252
20253             // `style` attribute is special in the sense that it sets the CSS style of the subelement.
20254             if (attrs.style) {
20255
20256                 $selected.css(attrs.style);
20257             }
20258             
20259             if (!_.isUndefined(attrs.html)) {
20260
20261                 $selected.each(function() {
20262
20263                     $(this).html(attrs.html + '');
20264                 });
20265             }
20266             
20267             // Special `ref-x` and `ref-y` attributes make it possible to set both absolute or
20268             // relative positioning of subelements.
20269             if (!_.isUndefined(attrs['ref-x']) ||
20270                 !_.isUndefined(attrs['ref-y']) ||
20271                 !_.isUndefined(attrs['ref-dx']) ||
20272                 !_.isUndefined(attrs['ref-dy']) ||
20273                 !_.isUndefined(attrs['x-alignment']) ||
20274                 !_.isUndefined(attrs['y-alignment']) ||
20275                 !_.isUndefined(attrs['ref-width']) ||
20276                 !_.isUndefined(attrs['ref-height'])
20277                ) {
20278
20279                    _.each($selected, function(el, index, list) {
20280                        var $el = $(el);
20281                        // copy original list selector to the element
20282                        $el.selector = list.selector;
20283                        relativelyPositioned.push($el);
20284                    });
20285             }
20286             
20287         }, this);
20288
20289         // We don't want the sub elements to affect the bounding box of the root element when
20290         // positioning the sub elements relatively to the bounding box.
20291         //_.invoke(relativelyPositioned, 'hide');
20292         //_.invoke(relativelyPositioned, 'show');
20293
20294         // Note that we're using the bounding box without transformation because we are already inside
20295         // a transformed coordinate system.
20296         var bbox = this.el.getBBox();        
20297
20298         renderingOnlyAttrs = renderingOnlyAttrs || {};
20299
20300         _.each(relativelyPositioned, function($el) {
20301
20302             // if there was a special attribute affecting the position amongst renderingOnlyAttributes
20303             // we have to merge it with rest of the element's attributes as they are necessary
20304             // to update the position relatively (i.e `ref`)
20305             var renderingOnlyElAttrs = renderingOnlyAttrs[$el.selector];
20306             var elAttrs = renderingOnlyElAttrs
20307                 ? _.merge({}, allAttrs[$el.selector], renderingOnlyElAttrs)
20308                 : allAttrs[$el.selector];
20309
20310             this.positionRelative($el, bbox, elAttrs);
20311             
20312         }, this);
20313
20314         if (rotatable) {
20315
20316             rotatable.attr('transform', rotation || '');
20317         }
20318     },
20319
20320     positionRelative: function($el, bbox, elAttrs) {
20321
20322         var ref = elAttrs['ref'];
20323         var refX = parseFloat(elAttrs['ref-x']);
20324         var refY = parseFloat(elAttrs['ref-y']);
20325         var refDx = parseFloat(elAttrs['ref-dx']);
20326         var refDy = parseFloat(elAttrs['ref-dy']);
20327         var yAlignment = elAttrs['y-alignment'];
20328         var xAlignment = elAttrs['x-alignment'];
20329         var refWidth = parseFloat(elAttrs['ref-width']);
20330         var refHeight = parseFloat(elAttrs['ref-height']);
20331
20332         // `ref` is the selector of the reference element. If no `ref` is passed, reference
20333         // element is the root element.
20334
20335         var isScalable = _.contains(_.pluck(_.pluck($el.parents('g'), 'className'), 'baseVal'), 'scalable');
20336
20337         if (ref) {
20338
20339             // Get the bounding box of the reference element relative to the root `<g>` element.
20340             bbox = V(this.findBySelector(ref)[0]).bbox(false, this.el);
20341         }
20342
20343         var vel = V($el[0]);
20344
20345         // Remove the previous translate() from the transform attribute and translate the element
20346         // relative to the root bounding box following the `ref-x` and `ref-y` attributes.
20347         if (vel.attr('transform')) {
20348
20349             vel.attr('transform', vel.attr('transform').replace(/translate\([^)]*\)/g, '') || '');
20350         }
20351
20352         function isDefined(x) {
20353             return _.isNumber(x) && !_.isNaN(x);
20354         }
20355
20356         // The final translation of the subelement.
20357         var tx = 0;
20358         var ty = 0;
20359
20360         // 'ref-width'/'ref-height' defines the width/height of the subelement relatively to
20361         // the reference element size
20362         // val in 0..1         ref-width = 0.75 sets the width to 75% of the ref. el. width
20363         // val < 0 || val > 1  ref-height = -20 sets the height to the the ref. el. height shorter by 20
20364
20365         if (isDefined(refWidth)) {
20366
20367             if (refWidth >= 0 && refWidth <= 1) {
20368
20369                 vel.attr('width', refWidth * bbox.width);
20370
20371             } else {
20372
20373                 vel.attr('width', Math.max(refWidth + bbox.width, 0));
20374             }
20375         }
20376
20377         if (isDefined(refHeight)) {
20378
20379             if (refHeight >= 0 && refHeight <= 1) {
20380
20381                 vel.attr('height', refHeight * bbox.height);
20382
20383             } else {
20384
20385                 vel.attr('height', Math.max(refHeight + bbox.height, 0));
20386             }
20387         }
20388
20389         // `ref-dx` and `ref-dy` define the offset of the subelement relative to the right and/or bottom
20390         // coordinate of the reference element.
20391         if (isDefined(refDx)) {
20392
20393             if (isScalable) {
20394
20395                 // Compensate for the scale grid in case the elemnt is in the scalable group.
20396                 var scale = V(this.$('.scalable')[0]).scale();
20397                 tx = bbox.x + bbox.width + refDx / scale.sx;
20398                 
20399             } else {
20400                 
20401                 tx = bbox.x + bbox.width + refDx;
20402             }
20403         }
20404         if (isDefined(refDy)) {
20405
20406             if (isScalable) {
20407                 
20408                 // Compensate for the scale grid in case the elemnt is in the scalable group.
20409                 var scale = V(this.$('.scalable')[0]).scale();
20410                 ty = bbox.y + bbox.height + refDy / scale.sy;
20411             } else {
20412                 
20413                 ty = bbox.y + bbox.height + refDy;
20414             }
20415         }
20416
20417         // if `refX` is in [0, 1] then `refX` is a fraction of bounding box width
20418         // if `refX` is < 0 then `refX`'s absolute values is the right coordinate of the bounding box
20419         // otherwise, `refX` is the left coordinate of the bounding box
20420         // Analogical rules apply for `refY`.
20421         if (isDefined(refX)) {
20422
20423             if (refX > 0 && refX < 1) {
20424
20425                 tx = bbox.x + bbox.width * refX;
20426
20427             } else if (isScalable) {
20428
20429                 // Compensate for the scale grid in case the elemnt is in the scalable group.
20430                 var scale = V(this.$('.scalable')[0]).scale();
20431                 tx = bbox.x + refX / scale.sx;
20432                 
20433             } else {
20434
20435                 tx = bbox.x + refX;
20436             }
20437         }
20438         if (isDefined(refY)) {
20439
20440             if (refY > 0 && refY < 1) {
20441                 
20442                 ty = bbox.y + bbox.height * refY;
20443                 
20444             } else if (isScalable) {
20445
20446                 // Compensate for the scale grid in case the elemnt is in the scalable group.
20447                 var scale = V(this.$('.scalable')[0]).scale();
20448                 ty = bbox.y + refY / scale.sy;
20449                 
20450             } else {
20451
20452                 ty = bbox.y + refY;
20453             }
20454         }
20455
20456         var velbbox = vel.bbox(false, this.paper.viewport);
20457         // `y-alignment` when set to `middle` causes centering of the subelement around its new y coordinate.
20458         if (yAlignment === 'middle') {
20459
20460             ty -= velbbox.height/2;
20461             
20462         } else if (isDefined(yAlignment)) {
20463
20464             ty += (yAlignment > -1 && yAlignment < 1) ?  velbbox.height * yAlignment : yAlignment;
20465         }
20466
20467         // `x-alignment` when set to `middle` causes centering of the subelement around its new x coordinate.
20468         if (xAlignment === 'middle') {
20469             
20470             tx -= velbbox.width/2;
20471             
20472         } else if (isDefined(xAlignment)) {
20473
20474             tx += (xAlignment > -1 && xAlignment < 1) ?  velbbox.width * xAlignment : xAlignment;
20475         }
20476
20477         vel.translate(tx, ty);
20478     },
20479
20480     // `prototype.markup` is rendered by default. Set the `markup` attribute on the model if the
20481     // default markup is not desirable.
20482     renderMarkup: function() {
20483         
20484         var markup = this.model.markup || this.model.get('markup');
20485         
20486         if (markup) {
20487
20488             var nodes = V(markup);
20489             V(this.el).append(nodes);
20490             
20491         } else {
20492
20493             throw new Error('properties.markup is missing while the default render() implementation is used.');
20494         }
20495     },
20496
20497     render: function() {
20498
20499         this.$el.empty();
20500
20501         this.renderMarkup();
20502
20503         this.update();
20504
20505         this.resize();
20506         this.rotate();
20507         this.translate();        
20508
20509         return this;
20510     },
20511
20512     // Scale the whole `<g>` group. Note the difference between `scale()` and `resize()` here.
20513     // `resize()` doesn't scale the whole `<g>` group but rather adjusts the `box.sx`/`box.sy` only.
20514     // `update()` is then responsible for scaling only those elements that have the `follow-scale`
20515     // attribute set to `true`. This is desirable in elements that have e.g. a `<text>` subelement
20516     // that is not supposed to be scaled together with a surrounding `<rect>` element that IS supposed
20517     // be be scaled.
20518     scale: function(sx, sy) {
20519
20520         // TODO: take into account the origin coordinates `ox` and `oy`.
20521         V(this.el).scale(sx, sy);
20522     },
20523
20524     resize: function() {
20525
20526         var size = this.model.get('size') || { width: 1, height: 1 };
20527         var angle = this.model.get('angle') || 0;
20528         
20529         var scalable = V(this.$('.scalable')[0]);
20530         if (!scalable) {
20531             // If there is no scalable elements, than there is nothing to resize.
20532             return;
20533         }
20534         var scalableBbox = scalable.bbox(true);
20535         
20536         scalable.attr('transform', 'scale(' + (size.width / scalableBbox.width) + ',' + (size.height / scalableBbox.height) + ')');
20537
20538         // Now the interesting part. The goal is to be able to store the object geometry via just `x`, `y`, `angle`, `width` and `height`
20539         // Order of transformations is significant but we want to reconstruct the object always in the order:
20540         // resize(), rotate(), translate() no matter of how the object was transformed. For that to work,
20541         // we must adjust the `x` and `y` coordinates of the object whenever we resize it (because the origin of the
20542         // rotation changes). The new `x` and `y` coordinates are computed by canceling the previous rotation
20543         // around the center of the resized object (which is a different origin then the origin of the previous rotation)
20544         // and getting the top-left corner of the resulting object. Then we clean up the rotation back to what it originally was.
20545         
20546         // Cancel the rotation but now around a different origin, which is the center of the scaled object.
20547         var rotatable = V(this.$('.rotatable')[0]);
20548         var rotation = rotatable && rotatable.attr('transform');
20549         if (rotation && rotation !== 'null') {
20550
20551             rotatable.attr('transform', rotation + ' rotate(' + (-angle) + ',' + (size.width/2) + ',' + (size.height/2) + ')');
20552             var rotatableBbox = scalable.bbox(false, this.paper.viewport);
20553             
20554             // Store new x, y and perform rotate() again against the new rotation origin.
20555             this.model.set('position', { x: rotatableBbox.x, y: rotatableBbox.y });
20556             this.rotate();
20557         }
20558
20559         // Update must always be called on non-rotated element. Otherwise, relative positioning
20560         // would work with wrong (rotated) bounding boxes.
20561         this.update();
20562     },
20563
20564     translate: function(model, changes, opt) {
20565
20566         var position = this.model.get('position') || { x: 0, y: 0 };
20567
20568         V(this.el).attr('transform', 'translate(' + position.x + ',' + position.y + ')');
20569     },
20570
20571     rotate: function() {
20572
20573         var rotatable = V(this.$('.rotatable')[0]);
20574         if (!rotatable) {
20575             // If there is no rotatable elements, then there is nothing to rotate.
20576             return;
20577         }
20578         
20579         var angle = this.model.get('angle') || 0;
20580         var size = this.model.get('size') || { width: 1, height: 1 };
20581
20582         var ox = size.width/2;
20583         var oy = size.height/2;
20584         
20585
20586         rotatable.attr('transform', 'rotate(' + angle + ',' + ox + ',' + oy + ')');
20587     },
20588
20589     // Interaction. The controller part.
20590     // ---------------------------------
20591
20592     
20593     pointerdown: function(evt, x, y) {
20594
20595         if ( // target is a valid magnet start linking
20596             evt.target.getAttribute('magnet') &&
20597             this.paper.options.validateMagnet.call(this.paper, this, evt.target)
20598         ) {
20599                 this.model.trigger('batch:start');
20600
20601                 var link = this.paper.getDefaultLink(this, evt.target);
20602                 link.set({
20603                     source: {
20604                         id: this.model.id,
20605                         selector: this.getSelector(evt.target),
20606                         port: $(evt.target).attr('port')
20607                     },
20608                     target: { x: x, y: y }
20609                 });
20610
20611                 this.paper.model.addCell(link);
20612
20613                 this._linkView = this.paper.findViewByModel(link);
20614                 this._linkView.startArrowheadMove('target');
20615
20616         } else {
20617
20618             this._dx = x;
20619             this._dy = y;
20620
20621             joint.dia.CellView.prototype.pointerdown.apply(this, arguments);
20622         }
20623     },
20624
20625     pointermove: function(evt, x, y) {
20626
20627         if (this._linkView) {
20628
20629             // let the linkview deal with this event
20630             this._linkView.pointermove(evt, x, y);
20631
20632         } else {
20633
20634             var grid = this.paper.options.gridSize;
20635
20636             if (this.options.interactive !== false) {
20637
20638                 var position = this.model.get('position');
20639
20640                 // Make sure the new element's position always snaps to the current grid after
20641                 // translate as the previous one could be calculated with a different grid size.
20642                 this.model.translate(
20643                     g.snapToGrid(position.x, grid) - position.x + g.snapToGrid(x - this._dx, grid),
20644                     g.snapToGrid(position.y, grid) - position.y + g.snapToGrid(y - this._dy, grid)
20645                 );
20646             }
20647
20648             this._dx = g.snapToGrid(x, grid);
20649             this._dy = g.snapToGrid(y, grid);
20650
20651             joint.dia.CellView.prototype.pointermove.apply(this, arguments);
20652         }
20653     },
20654
20655     pointerup: function(evt, x, y) {
20656
20657         if (this._linkView) {
20658
20659             // let the linkview deal with this event
20660             this._linkView.pointerup(evt, x, y);
20661
20662             delete this._linkView;
20663
20664             this.model.trigger('batch:stop');
20665
20666         } else {
20667
20668             joint.dia.CellView.prototype.pointerup.apply(this, arguments);
20669         }
20670     }
20671
20672 });
20673
20674 if (typeof exports === 'object') {
20675
20676     module.exports.Element = joint.dia.Element;
20677     module.exports.ElementView = joint.dia.ElementView;
20678 }
20679
20680 //      JointJS diagramming library.
20681 //      (c) 2011-2013 client IO
20682
20683
20684 if (typeof exports === 'object') {
20685
20686     var joint = {
20687         dia: {
20688             Cell: require('./joint.dia.cell').Cell,
20689             CellView: require('./joint.dia.cell').CellView
20690         }
20691     };
20692     var Backbone = require('backbone');
20693     var _ = require('lodash');
20694     var g = require('./geometry');
20695 }
20696
20697
20698
20699 // joint.dia.Link base model.
20700 // --------------------------
20701 joint.dia.Link = joint.dia.Cell.extend({
20702
20703     // The default markup for links.
20704     markup: [
20705         '<path class="connection" stroke="black"/>',
20706         '<path class="marker-source" fill="black" stroke="black" />',
20707         '<path class="marker-target" fill="black" stroke="black" />',
20708         '<path class="connection-wrap"/>',
20709         '<g class="labels"/>',
20710         '<g class="marker-vertices"/>',
20711         '<g class="marker-arrowheads"/>',
20712         '<g class="link-tools"/>'
20713     ].join(''),
20714
20715     labelMarkup: [
20716         '<g class="label">',
20717         '<rect />',
20718         '<text />',
20719         '</g>'
20720     ].join(''),
20721
20722     toolMarkup: [
20723         '<g class="link-tool">',
20724         '<g class="tool-remove" event="remove">',
20725         '<circle r="11" />',
20726         '<path transform="scale(.8) translate(-16, -16)" d="M24.778,21.419 19.276,15.917 24.777,10.415 21.949,7.585 16.447,13.087 10.945,7.585 8.117,10.415 13.618,15.917 8.116,21.419 10.946,24.248 16.447,18.746 21.948,24.248z"/>',
20727         '<title>Remove link.</title>',
20728         '</g>',
20729         '<g class="tool-options" event="link:options">',
20730         '<circle r="11" transform="translate(25)"/>',
20731         '<path fill="white" transform="scale(.55) translate(29, -16)" d="M31.229,17.736c0.064-0.571,0.104-1.148,0.104-1.736s-0.04-1.166-0.104-1.737l-4.377-1.557c-0.218-0.716-0.504-1.401-0.851-2.05l1.993-4.192c-0.725-0.91-1.549-1.734-2.458-2.459l-4.193,1.994c-0.647-0.347-1.334-0.632-2.049-0.849l-1.558-4.378C17.165,0.708,16.588,0.667,16,0.667s-1.166,0.041-1.737,0.105L12.707,5.15c-0.716,0.217-1.401,0.502-2.05,0.849L6.464,4.005C5.554,4.73,4.73,5.554,4.005,6.464l1.994,4.192c-0.347,0.648-0.632,1.334-0.849,2.05l-4.378,1.557C0.708,14.834,0.667,15.412,0.667,16s0.041,1.165,0.105,1.736l4.378,1.558c0.217,0.715,0.502,1.401,0.849,2.049l-1.994,4.193c0.725,0.909,1.549,1.733,2.459,2.458l4.192-1.993c0.648,0.347,1.334,0.633,2.05,0.851l1.557,4.377c0.571,0.064,1.148,0.104,1.737,0.104c0.588,0,1.165-0.04,1.736-0.104l1.558-4.377c0.715-0.218,1.399-0.504,2.049-0.851l4.193,1.993c0.909-0.725,1.733-1.549,2.458-2.458l-1.993-4.193c0.347-0.647,0.633-1.334,0.851-2.049L31.229,17.736zM16,20.871c-2.69,0-4.872-2.182-4.872-4.871c0-2.69,2.182-4.872,4.872-4.872c2.689,0,4.871,2.182,4.871,4.872C20.871,18.689,18.689,20.871,16,20.871z"/>',
20732         '<title>Link options.</title>',
20733         '</g>',
20734         '</g>'
20735     ].join(''),
20736
20737     // The default markup for showing/removing vertices. These elements are the children of the .marker-vertices element (see `this.markup`).
20738     // Only .marker-vertex and .marker-vertex-remove element have special meaning. The former is used for
20739     // dragging vertices (changin their position). The latter is used for removing vertices.
20740     vertexMarkup: [
20741         '<g class="marker-vertex-group" transform="translate(<%= x %>, <%= y %>)">',
20742         '<circle class="marker-vertex" idx="<%= idx %>" r="10" />',
20743         '<path class="marker-vertex-remove-area" idx="<%= idx %>" d="M16,5.333c-7.732,0-14,4.701-14,10.5c0,1.982,0.741,3.833,2.016,5.414L2,25.667l5.613-1.441c2.339,1.317,5.237,2.107,8.387,2.107c7.732,0,14-4.701,14-10.5C30,10.034,23.732,5.333,16,5.333z" transform="translate(5, -33)"/>',
20744         '<path class="marker-vertex-remove" idx="<%= idx %>" transform="scale(.8) translate(9.5, -37)" d="M24.778,21.419 19.276,15.917 24.777,10.415 21.949,7.585 16.447,13.087 10.945,7.585 8.117,10.415 13.618,15.917 8.116,21.419 10.946,24.248 16.447,18.746 21.948,24.248z">',
20745         '<title>Remove vertex.</title>',
20746         '</path>',
20747         '</g>'
20748     ].join(''),
20749
20750     arrowheadMarkup: [
20751         '<g class="marker-arrowhead-group marker-arrowhead-group-<%= end %>">',
20752         '<path class="marker-arrowhead" end="<%= end %>" d="M 26 0 L 0 13 L 26 26 z" />',
20753         '</g>'
20754     ].join(''),
20755
20756     defaults: {
20757
20758         type: 'link'
20759     },
20760
20761     disconnect: function() {
20762
20763         return this.set({ source: g.point(0, 0), target: g.point(0, 0) });
20764     },
20765
20766     // A convenient way to set labels. Currently set values will be mixined with `value` if used as a setter.
20767     label: function(idx, value) {
20768
20769         idx = idx || 0;
20770         
20771         var labels = this.get('labels') || [];
20772         
20773         // Is it a getter?
20774         if (arguments.length === 0 || arguments.length === 1) {
20775             
20776             return labels[idx];
20777         }
20778
20779         var newValue = _.merge({}, labels[idx], value);
20780
20781         var newLabels = labels.slice();
20782         newLabels[idx] = newValue;
20783         
20784         return this.set({ labels: newLabels });
20785     }
20786 });
20787
20788
20789 // joint.dia.Link base view and controller.
20790 // ----------------------------------------
20791
20792 joint.dia.LinkView = joint.dia.CellView.extend({
20793
20794     className: function() {
20795         return _.unique(this.model.get('type').split('.').concat('link')).join(' ');
20796     },
20797
20798     options: {
20799
20800         shortLinkLength: 100
20801     },
20802     
20803     initialize: function() {
20804
20805         joint.dia.CellView.prototype.initialize.apply(this, arguments);
20806
20807         // create methods in prototype, so they can be accessed from any instance and
20808         // don't need to be create over and over
20809         if (typeof this.constructor.prototype.watchSource !== 'function') {
20810             this.constructor.prototype.watchSource = this._createWatcher('source');
20811             this.constructor.prototype.watchTarget = this._createWatcher('target');
20812         }
20813
20814         // `_.labelCache` is a mapping of indexes of labels in the `this.get('labels')` array to
20815         // `<g class="label">` nodes wrapped by Vectorizer. This allows for quick access to the
20816         // nodes in `updateLabelPosition()` in order to update the label positions.
20817         this._labelCache = {};
20818
20819         // keeps markers bboxes and positions again for quicker access
20820         this._markerCache = {};
20821
20822         // bind events
20823         this.startListening();
20824     },
20825
20826     startListening: function() {
20827
20828         this.listenTo(this.model, 'change:markup', this.render);
20829         this.listenTo(this.model, 'change:smooth change:manhattan change:router change:connector', this.update);
20830         this.listenTo(this.model, 'change:toolMarkup', function() {
20831             this.renderTools().updateToolsPosition();
20832         });
20833         this.listenTo(this.model, 'change:labels change:labelMarkup', function() {
20834             this.renderLabels().updateLabelPositions();
20835         });
20836         this.listenTo(this.model, 'change:vertices change:vertexMarkup', function() {
20837             this.renderVertexMarkers().update();
20838         });
20839         this.listenTo(this.model, 'change:source', function(cell, source) {
20840             this.watchSource(cell, source).update();
20841         });
20842         this.listenTo(this.model, 'change:target', function(cell, target) {
20843             this.watchTarget(cell, target).update();
20844         });
20845     },
20846
20847     // Rendering
20848     //----------
20849
20850     render: function() {
20851
20852         this.$el.empty();
20853
20854         // A special markup can be given in the `properties.markup` property. This might be handy
20855         // if e.g. arrowhead markers should be `<image>` elements or any other element than `<path>`s.
20856         // `.connection`, `.connection-wrap`, `.marker-source` and `.marker-target` selectors
20857         // of elements with special meaning though. Therefore, those classes should be preserved in any
20858         // special markup passed in `properties.markup`.
20859         var children = V(this.model.get('markup') || this.model.markup);
20860
20861         // custom markup may contain only one children
20862         if (!_.isArray(children)) children = [children];
20863
20864         // Cache all children elements for quicker access.
20865         this._V = {}; // vectorized markup;
20866         _.each(children, function(child) {
20867             var c = child.attr('class');
20868             c && (this._V[$.camelCase(c)] = child);
20869         }, this);
20870
20871         // Only the connection path is mandatory
20872         if (!this._V.connection) throw new Error('link: no connection path in the markup');
20873
20874         // partial rendering
20875         this.renderTools();
20876         this.renderVertexMarkers();
20877         this.renderArrowheadMarkers();
20878
20879         V(this.el).append(children);
20880
20881         // rendering labels has to be run after the link is appended to DOM tree. (otherwise <Text> bbox
20882         // returns zero values)
20883         this.renderLabels();
20884
20885         // start watching the ends of the link for changes
20886         this.watchSource(this.model, this.model.get('source'))
20887             .watchTarget(this.model, this.model.get('target'))
20888             .update();
20889
20890         return this;
20891     },
20892
20893     renderLabels: function() {
20894
20895         if (!this._V.labels) return this;
20896
20897         this._labelCache = {};
20898         var $labels = $(this._V.labels.node).empty();
20899
20900         var labels = this.model.get('labels') || [];
20901         if (!labels.length) return this;
20902         
20903         var labelTemplate = _.template(this.model.get('labelMarkup') || this.model.labelMarkup);
20904         // This is a prepared instance of a vectorized SVGDOM node for the label element resulting from
20905         // compilation of the labelTemplate. The purpose is that all labels will just `clone()` this
20906         // node to create a duplicate.
20907         var labelNodeInstance = V(labelTemplate());
20908
20909         _.each(labels, function(label, idx) {
20910
20911             var labelNode = labelNodeInstance.clone().node;
20912             // Cache label nodes so that the `updateLabels()` can just update the label node positions.
20913             this._labelCache[idx] = V(labelNode);
20914
20915             var $text = $(labelNode).find('text');
20916             var $rect = $(labelNode).find('rect');
20917
20918             // Text attributes with the default `text-anchor` and font-size set.
20919             var textAttributes = _.extend({ 'text-anchor': 'middle', 'font-size': 14 }, joint.util.getByPath(label, 'attrs/text', '/'));
20920             
20921             $text.attr(_.omit(textAttributes, 'text'));
20922                 
20923             if (!_.isUndefined(textAttributes.text)) {
20924
20925                 V($text[0]).text(textAttributes.text + '');
20926             }
20927
20928             // Note that we first need to append the `<text>` element to the DOM in order to
20929             // get its bounding box.
20930             $labels.append(labelNode);
20931
20932             // `y-alignment` - center the text element around its y coordinate.
20933             var textBbox = V($text[0]).bbox(true, $labels[0]);
20934             V($text[0]).translate(0, -textBbox.height/2);
20935
20936             // Add default values.
20937             var rectAttributes = _.extend({
20938
20939                 fill: 'white',
20940                 rx: 3,
20941                 ry: 3
20942                 
20943             }, joint.util.getByPath(label, 'attrs/rect', '/'));
20944             
20945             $rect.attr(_.extend(rectAttributes, {
20946
20947                 x: textBbox.x,
20948                 y: textBbox.y - textBbox.height/2,  // Take into account the y-alignment translation.
20949                 width: textBbox.width,
20950                 height: textBbox.height
20951             }));
20952             
20953         }, this);
20954
20955         return this;
20956     },
20957
20958     renderTools: function() {
20959
20960         if (!this._V.linkTools) return this;
20961
20962         // Tools are a group of clickable elements that manipulate the whole link.
20963         // A good example of this is the remove tool that removes the whole link.
20964         // Tools appear after hovering the link close to the `source` element/point of the link
20965         // but are offset a bit so that they don't cover the `marker-arrowhead`.
20966
20967         var $tools = $(this._V.linkTools.node).empty();
20968         var toolTemplate = _.template(this.model.get('toolMarkup') || this.model.toolMarkup);
20969         var tool = V(toolTemplate());
20970
20971         $tools.append(tool.node);
20972         
20973         // Cache the tool node so that the `updateToolsPosition()` can update the tool position quickly.
20974         this._toolCache = tool;
20975
20976         return this;
20977     },
20978
20979     renderVertexMarkers: function() {
20980
20981         if (!this._V.markerVertices) return this;
20982
20983         var $markerVertices = $(this._V.markerVertices.node).empty();
20984
20985         // A special markup can be given in the `properties.vertexMarkup` property. This might be handy
20986         // if default styling (elements) are not desired. This makes it possible to use any
20987         // SVG elements for .marker-vertex and .marker-vertex-remove tools.
20988         var markupTemplate = _.template(this.model.get('vertexMarkup') || this.model.vertexMarkup);
20989         
20990         _.each(this.model.get('vertices'), function(vertex, idx) {
20991
20992             $markerVertices.append(V(markupTemplate(_.extend({ idx: idx }, vertex))).node);
20993         });
20994         
20995         return this;
20996     },
20997
20998     renderArrowheadMarkers: function() {
20999
21000         // Custom markups might not have arrowhead markers. Therefore, jump of this function immediately if that's the case.
21001         if (!this._V.markerArrowheads) return this;
21002
21003         var $markerArrowheads = $(this._V.markerArrowheads.node);
21004
21005         $markerArrowheads.empty();
21006
21007         // A special markup can be given in the `properties.vertexMarkup` property. This might be handy
21008         // if default styling (elements) are not desired. This makes it possible to use any
21009         // SVG elements for .marker-vertex and .marker-vertex-remove tools.
21010         var markupTemplate = _.template(this.model.get('arrowheadMarkup') || this.model.arrowheadMarkup);
21011
21012         this._V.sourceArrowhead = V(markupTemplate({ end: 'source' }));
21013         this._V.targetArrowhead = V(markupTemplate({ end: 'target' }));
21014
21015         $markerArrowheads.append(this._V.sourceArrowhead.node, this._V.targetArrowhead.node);
21016
21017         return this;
21018     },
21019
21020     // Updating
21021     //---------
21022
21023     // Default is to process the `attrs` object and set attributes on subelements based on the selectors.
21024     update: function() {
21025
21026         // Update attributes.
21027         _.each(this.model.get('attrs'), function(attrs, selector) {
21028             
21029             // If the `filter` attribute is an object, it is in the special JointJS filter format and so
21030             // it becomes a special attribute and is treated separately.
21031             if (_.isObject(attrs.filter)) {
21032                 
21033                 this.findBySelector(selector).attr(_.omit(attrs, 'filter'));
21034                 this.applyFilter(selector, attrs.filter);
21035                 
21036             } else {
21037                 
21038                 this.findBySelector(selector).attr(attrs);
21039             }
21040         }, this);
21041
21042         // Path finding
21043         var vertices = this.route = this.findRoute(this.model.get('vertices') || []);
21044
21045         // finds all the connection points taking new vertices into account
21046         this._findConnectionPoints(vertices);
21047
21048         var pathData = this.getPathData(vertices);
21049
21050         // The markup needs to contain a `.connection`
21051         this._V.connection.attr('d', pathData);
21052         this._V.connectionWrap && this._V.connectionWrap.attr('d', pathData);
21053
21054         this._translateAndAutoOrientArrows(this._V.markerSource, this._V.markerTarget);
21055
21056         //partials updates
21057         this.updateLabelPositions();
21058         this.updateToolsPosition();
21059         this.updateArrowheadMarkers();
21060
21061         delete this.options.perpendicular;
21062
21063         return this;
21064     },
21065
21066     _findConnectionPoints: function(vertices) {
21067
21068         // cache source and target points
21069         var sourcePoint, targetPoint, sourceMarkerPoint, targetMarkerPoint;
21070
21071         var firstVertex = _.first(vertices);
21072
21073         sourcePoint = this.getConnectionPoint(
21074             'source', this.model.get('source'), firstVertex || this.model.get('target')
21075         ).round();
21076
21077         var lastVertex = _.last(vertices);
21078
21079         targetPoint = this.getConnectionPoint(
21080             'target', this.model.get('target'), lastVertex || sourcePoint
21081         ).round();
21082
21083         // Move the source point by the width of the marker taking into account
21084         // its scale around x-axis. Note that scale is the only transform that
21085         // makes sense to be set in `.marker-source` attributes object
21086         // as all other transforms (translate/rotate) will be replaced
21087         // by the `translateAndAutoOrient()` function.
21088         var cache = this._markerCache;
21089
21090         if (this._V.markerSource) {
21091
21092             cache.sourceBBox = cache.sourceBBox || this._V.markerSource.bbox(true);
21093
21094             sourceMarkerPoint = g.point(sourcePoint).move(
21095                 firstVertex || targetPoint,
21096                 cache.sourceBBox.width * this._V.markerSource.scale().sx * -1
21097             ).round();
21098         }
21099
21100         if (this._V.markerTarget) {
21101
21102             cache.targetBBox = cache.targetBBox || this._V.markerTarget.bbox(true);
21103
21104             targetMarkerPoint = g.point(targetPoint).move(
21105                 lastVertex || sourcePoint,
21106                 cache.targetBBox.width * this._V.markerTarget.scale().sx * -1
21107             ).round();
21108         }
21109
21110         // if there was no markup for the marker, use the connection point.
21111         cache.sourcePoint = sourceMarkerPoint || sourcePoint;
21112         cache.targetPoint = targetMarkerPoint || targetPoint;
21113
21114         // make connection points public
21115         this.sourcePoint = sourcePoint;
21116         this.targetPoint = targetPoint;
21117     },
21118
21119     updateLabelPositions: function() {
21120
21121         if (!this._V.labels) return this;
21122
21123         // This method assumes all the label nodes are stored in the `this._labelCache` hash table
21124         // by their indexes in the `this.get('labels')` array. This is done in the `renderLabels()` method.
21125
21126         var labels = this.model.get('labels') || [];
21127         if (!labels.length) return this;
21128
21129         var connectionElement = this._V.connection.node;
21130         var connectionLength = connectionElement.getTotalLength();
21131
21132         _.each(labels, function(label, idx) {
21133
21134             var position = label.position;
21135             position = (position > connectionLength) ? connectionLength : position; // sanity check
21136             position = (position < 0) ? connectionLength + position : position;
21137             position = position > 1 ? position : connectionLength * position;
21138
21139             var labelCoordinates = connectionElement.getPointAtLength(position);
21140
21141             this._labelCache[idx].attr('transform', 'translate(' + labelCoordinates.x + ', ' + labelCoordinates.y + ')');
21142
21143         }, this);
21144
21145         return this;
21146     },
21147
21148
21149     updateToolsPosition: function() {
21150
21151         if (!this._V.linkTools) return this;
21152
21153         // Move the tools a bit to the target position but don't cover the `sourceArrowhead` marker.
21154         // Note that the offset is hardcoded here. The offset should be always
21155         // more than the `this.$('.marker-arrowhead[end="source"]')[0].bbox().width` but looking
21156         // this up all the time would be slow.
21157
21158         var scale = '';
21159         var offset = 40;
21160
21161         // If the link is too short, make the tools half the size and the offset twice as low.
21162         if (this.getConnectionLength() < this.options.shortLinkLength) {
21163             scale = 'scale(.5)';
21164             offset /= 2;
21165         }
21166
21167         var toolPosition = this.getPointAtLength(offset);
21168         
21169         this._toolCache.attr('transform', 'translate(' + toolPosition.x + ', ' + toolPosition.y + ') ' + scale);
21170
21171         return this;
21172     },
21173
21174
21175     updateArrowheadMarkers: function() {
21176
21177         if (!this._V.markerArrowheads) return this;
21178
21179         // getting bbox of an element with `display="none"` in IE9 ends up with access violation
21180         if ($.css(this._V.markerArrowheads.node, 'display') === 'none') return this;
21181
21182         var sx = this.getConnectionLength() < this.options.shortLinkLength ? .5 : 1;
21183         this._V.sourceArrowhead.scale(sx);
21184         this._V.targetArrowhead.scale(sx);
21185
21186         this._translateAndAutoOrientArrows(this._V.sourceArrowhead, this._V.targetArrowhead);
21187
21188         return this;
21189     },
21190
21191     // Returns a function observing changes on an end of the link. If a change happens and new end is a new model,
21192     // it stops listening on the previous one and starts listening to the new one.
21193     _createWatcher: function(endType) {
21194
21195         function watchEnd(link, end) {
21196
21197             end = end || {};
21198
21199             var previousEnd = link.previous(endType) || {};
21200
21201             // Pick updateMethod this._sourceBboxUpdate or this._targetBboxUpdate.
21202             var updateEndFunction = this['_' + endType + 'BBoxUpdate'];
21203
21204             if (this._isModel(previousEnd)) {
21205                 this.stopListening(this.paper.getModelById(previousEnd.id), 'change', updateEndFunction);
21206             }
21207
21208             if (this._isModel(end)) {
21209                 // If the observed model changes, it caches a new bbox and do the link update.
21210                 this.listenTo(this.paper.getModelById(end.id), 'change', updateEndFunction);
21211             }
21212
21213             _.bind(updateEndFunction, this)({ cacheOnly: true });
21214
21215             return this;
21216         }
21217
21218         return watchEnd;
21219     },
21220
21221     // It's important to keep both methods (sourceBboxUpdate and targetBboxUpdate) as unique methods
21222     // because of loop links. We have to be able to determine, which method we want to stop listen to.
21223     // ListenTo(model, event, handler) as model and event will be identical.
21224     _sourceBBoxUpdate: function(update) {
21225
21226         // keep track which end had been changed very last
21227         this.lastEndChange = 'source';
21228
21229         update = update || {};
21230         var end = this.model.get('source');
21231
21232         if (this._isModel(end)) {
21233
21234             var selector = this._makeSelector(end);
21235             var view = this.paper.findViewByModel(end.id);
21236             var magnetElement = this.paper.viewport.querySelector(selector);
21237
21238             this.sourceBBox = view.getStrokeBBox(magnetElement);
21239
21240         } else {
21241             // the link end is a point ~ rect 1x1
21242             this.sourceBBox = g.rect(end.x, end.y, 1, 1);
21243         }
21244
21245         if (!update.cacheOnly) this.update();
21246     },
21247
21248     _targetBBoxUpdate: function(update) {
21249
21250         // keep track which end had been changed very last
21251         this.lastEndChange = 'target';
21252
21253         update = update || {};
21254         var end = this.model.get('target');
21255
21256         if (this._isModel(end)) {
21257
21258             var selector = this._makeSelector(end);
21259             var view = this.paper.findViewByModel(end.id);
21260             var magnetElement = this.paper.viewport.querySelector(selector);
21261
21262             this.targetBBox = view.getStrokeBBox(magnetElement);
21263
21264         } else {
21265             // the link end is a point ~ rect 1x1
21266             this.targetBBox = g.rect(end.x, end.y, 1, 1);
21267         }
21268
21269         if (!update.cacheOnly) this.update();
21270     },
21271
21272     _translateAndAutoOrientArrows: function(sourceArrow, targetArrow) {
21273
21274         // Make the markers "point" to their sticky points being auto-oriented towards
21275         // `targetPosition`/`sourcePosition`. And do so only if there is a markup for them.
21276         if (sourceArrow) {
21277             sourceArrow.translateAndAutoOrient(
21278                 this.sourcePoint,
21279                 _.first(this.route) || this.targetPoint,
21280                 this.paper.viewport
21281             );
21282         }
21283
21284         if (targetArrow) {
21285             targetArrow.translateAndAutoOrient(
21286                 this.targetPoint,
21287                 _.last(this.route) || this.sourcePoint,
21288                 this.paper.viewport
21289             );
21290         }
21291     },
21292
21293     removeVertex: function(idx) {
21294
21295         var vertices = _.clone(this.model.get('vertices'));
21296         
21297         if (vertices && vertices.length) {
21298
21299             vertices.splice(idx, 1);
21300             this.model.set('vertices', vertices);
21301         }
21302
21303         return this;
21304     },
21305
21306     // This method ads a new vertex to the `vertices` array of `.connection`. This method
21307     // uses a heuristic to find the index at which the new `vertex` should be placed at assuming
21308     // the new vertex is somewhere on the path.
21309     addVertex: function(vertex) {
21310
21311         this.model.set('attrs', this.model.get('attrs') || {});
21312         var attrs = this.model.get('attrs');
21313         
21314         // As it is very hard to find a correct index of the newly created vertex,
21315         // a little heuristics is taking place here.
21316         // The heuristics checks if length of the newly created
21317         // path is lot more than length of the old path. If this is the case,
21318         // new vertex was probably put into a wrong index.
21319         // Try to put it into another index and repeat the heuristics again.
21320
21321         var vertices = (this.model.get('vertices') || []).slice();
21322         // Store the original vertices for a later revert if needed.
21323         var originalVertices = vertices.slice();
21324
21325         // A `<path>` element used to compute the length of the path during heuristics.
21326         var path = this._V.connection.node.cloneNode(false);
21327         
21328         // Length of the original path.        
21329         var originalPathLength = path.getTotalLength();
21330         // Current path length.
21331         var pathLength;
21332         // Tolerance determines the highest possible difference between the length
21333         // of the old and new path. The number has been chosen heuristically.
21334         var pathLengthTolerance = 20;
21335         // Total number of vertices including source and target points.
21336         var idx = vertices.length + 1;
21337
21338         // Loop through all possible indexes and check if the difference between
21339         // path lengths changes significantly. If not, the found index is
21340         // most probably the right one.
21341         while (idx--) {
21342
21343             vertices.splice(idx, 0, vertex);
21344             V(path).attr('d', this.getPathData(this.findRoute(vertices)));
21345
21346             pathLength = path.getTotalLength();
21347
21348             // Check if the path lengths changed significantly.
21349             if (pathLength - originalPathLength > pathLengthTolerance) {
21350
21351                 // Revert vertices to the original array. The path length has changed too much
21352                 // so that the index was not found yet.
21353                 vertices = originalVertices.slice();
21354                 
21355             } else {
21356
21357                 break;
21358             }
21359         }
21360
21361         this.model.set('vertices', vertices);
21362
21363         // In manhattan routing, if there are no vertices, the path length changes significantly
21364         // with the first vertex added. Shall we check vertices.length === 0? at beginning of addVertex()
21365         // in order to avoid the temporary path construction and other operations?
21366         return Math.max(idx, 0);
21367     },
21368
21369
21370     findRoute: function(oldVertices) {
21371
21372         var router = this.model.get('router');
21373
21374         if (!router) {
21375
21376             if (this.model.get('manhattan')) {
21377                 // backwards compability
21378                 router = { name: 'orthogonal' };
21379             } else {
21380
21381                 return oldVertices;
21382             }
21383         }
21384
21385         var fn = joint.routers[router.name];
21386
21387         if (!_.isFunction(fn)) {
21388
21389             throw 'unknown router: ' + router.name;
21390         }
21391
21392         var newVertices = fn.call(this, oldVertices || [], router.args || {}, this);
21393
21394         return newVertices;
21395     },
21396
21397     // Return the `d` attribute value of the `<path>` element representing the link
21398     // between `source` and `target`.
21399     getPathData: function(vertices) {
21400
21401         var connector = this.model.get('connector');
21402
21403         if (!connector) {
21404
21405             // backwards compability
21406             connector = this.model.get('smooth') ? { name: 'smooth' } : { name: 'normal' };
21407         }
21408
21409         if (!_.isFunction(joint.connectors[connector.name])) {
21410
21411             throw 'unknown connector: ' + connector.name;
21412         }
21413
21414         var pathData = joint.connectors[connector.name].call(
21415             this,
21416             this._markerCache.sourcePoint, // Note that the value is translated by the size
21417             this._markerCache.targetPoint, // of the marker. (We'r not using this.sourcePoint)
21418             vertices || (this.model.get('vertices') || {}),
21419             connector.args || {}, // options
21420             this
21421         );
21422
21423         return pathData;
21424     },
21425
21426     // Find a point that is the start of the connection.
21427     // If `selectorOrPoint` is a point, then we're done and that point is the start of the connection.
21428     // If the `selectorOrPoint` is an element however, we need to know a reference point (or element)
21429     // that the link leads to in order to determine the start of the connection on the original element.
21430     getConnectionPoint: function(end, selectorOrPoint, referenceSelectorOrPoint) {
21431
21432         var spot;
21433
21434         if (this._isPoint(selectorOrPoint)) {
21435
21436             // If the source is a point, we don't need a reference point to find the sticky point of connection.
21437             spot = g.point(selectorOrPoint);
21438
21439         } else {
21440
21441             // If the source is an element, we need to find a point on the element boundary that is closest
21442             // to the reference point (or reference element).
21443             // Get the bounding box of the spot relative to the paper viewport. This is necessary
21444             // in order to follow paper viewport transformations (scale/rotate).
21445             // `_sourceBbox` (`_targetBbox`) comes from `_sourceBboxUpdate` (`_sourceBboxUpdate`)
21446             // method, it exists since first render and are automatically updated
21447             var spotBbox = end === 'source' ? this.sourceBBox : this.targetBBox;
21448             
21449             var reference;
21450             
21451             if (this._isPoint(referenceSelectorOrPoint)) {
21452
21453                 // Reference was passed as a point, therefore, we're ready to find the sticky point of connection on the source element.
21454                 reference = g.point(referenceSelectorOrPoint);
21455
21456             } else {
21457
21458                 // Reference was passed as an element, therefore we need to find a point on the reference
21459                 // element boundary closest to the source element.
21460                 // Get the bounding box of the spot relative to the paper viewport. This is necessary
21461                 // in order to follow paper viewport transformations (scale/rotate).
21462                 var referenceBbox = end === 'source' ? this.targetBBox : this.sourceBBox;
21463
21464                 reference = g.rect(referenceBbox).intersectionWithLineFromCenterToPoint(g.rect(spotBbox).center());
21465                 reference = reference || g.rect(referenceBbox).center();
21466             }
21467
21468             // If `perpendicularLinks` flag is set on the paper and there are vertices
21469             // on the link, then try to find a connection point that makes the link perpendicular
21470             // even though the link won't point to the center of the targeted object.
21471             if (this.paper.options.perpendicularLinks || this.options.perpendicular) {
21472
21473                 var horizontalLineRect = g.rect(0, reference.y, this.paper.options.width, 1);
21474                 var verticalLineRect = g.rect(reference.x, 0, 1, this.paper.options.height);
21475                 var nearestSide;
21476
21477                 if (horizontalLineRect.intersect(g.rect(spotBbox))) {
21478
21479                     nearestSide = g.rect(spotBbox).sideNearestToPoint(reference);
21480                     switch (nearestSide) {
21481                       case 'left':
21482                         spot = g.point(spotBbox.x, reference.y);
21483                         break;
21484                       case 'right':
21485                         spot = g.point(spotBbox.x + spotBbox.width, reference.y);
21486                         break;
21487                     default:
21488                         spot = g.rect(spotBbox).center();
21489                         break;
21490                     }
21491                     
21492                 } else if (verticalLineRect.intersect(g.rect(spotBbox))) {
21493
21494                     nearestSide = g.rect(spotBbox).sideNearestToPoint(reference);
21495                     switch (nearestSide) {
21496                       case 'top':
21497                         spot = g.point(reference.x, spotBbox.y);
21498                         break;
21499                       case 'bottom':
21500                         spot = g.point(reference.x, spotBbox.y + spotBbox.height);
21501                         break;
21502                     default:
21503                         spot = g.rect(spotBbox).center();
21504                         break;
21505                     }
21506                     
21507                 } else {
21508
21509                     // If there is no intersection horizontally or vertically with the object bounding box,
21510                     // then we fall back to the regular situation finding straight line (not perpendicular)
21511                     // between the object and the reference point.
21512
21513                     spot = g.rect(spotBbox).intersectionWithLineFromCenterToPoint(reference);
21514                     spot = spot || g.rect(spotBbox).center();
21515                 }
21516                 
21517             } else {
21518             
21519                 spot = g.rect(spotBbox).intersectionWithLineFromCenterToPoint(reference);
21520                 spot = spot || g.rect(spotBbox).center();
21521             }
21522         }
21523
21524         return spot;
21525     },
21526
21527     _isModel: function(end) {
21528
21529         return end && end.id;
21530     },
21531
21532     _isPoint: function(end) {
21533
21534         return !this._isModel(end);
21535     },
21536
21537     _makeSelector: function(end) {
21538
21539         var selector = '[model-id="' + end.id + '"]';
21540         // `port` has a higher precendence over `selector`. This is because the selector to the magnet
21541         // might change while the name of the port can stay the same.
21542         if (end.port) {
21543             selector += ' [port="' + end.port + '"]';
21544         } else if (end.selector) {
21545             selector += ' ' + end.selector;
21546         }
21547
21548         return selector;
21549     },
21550
21551     // Public API
21552     // ----------
21553
21554     getConnectionLength: function() {
21555
21556         return this._V.connection.node.getTotalLength();
21557     },
21558
21559     getPointAtLength: function(length) {
21560
21561         return this._V.connection.node.getPointAtLength(length);
21562     },
21563
21564     // Interaction. The controller part.
21565     // ---------------------------------
21566
21567     _beforeArrowheadMove: function() {
21568
21569         this.model.trigger('batch:start');
21570
21571         this._z = this.model.get('z');
21572         this.model.set('z', Number.MAX_VALUE);
21573
21574         // Let the pointer propagate throught the link view elements so that
21575         // the `evt.target` is another element under the pointer, not the link itself.
21576         this.el.style.pointerEvents = 'none';
21577     },
21578
21579     _afterArrowheadMove: function() {
21580
21581         if (this._z) {
21582             this.model.set('z', this._z);
21583             delete this._z;
21584         }
21585
21586         // Put `pointer-events` back to its original value. See `startArrowheadMove()` for explanation.
21587         // Value `auto` doesn't work in IE9. We force to use `visiblePainted` instead.
21588         // See `https://developer.mozilla.org/en-US/docs/Web/CSS/pointer-events`.
21589         this.el.style.pointerEvents = 'visiblePainted';
21590
21591         this.model.trigger('batch:stop');
21592     },
21593
21594     _createValidateConnectionArgs: function(arrowhead) {
21595         // It makes sure the arguments for validateConnection have the following form:
21596         // (source view, source magnet, target view, target magnet and link view)
21597         var args = [];
21598
21599         args[4] = arrowhead;
21600         args[5] = this;
21601
21602         var oppositeArrowhead, i = 0, j = 0;
21603
21604         if (arrowhead === 'source') {
21605             i = 2;
21606             oppositeArrowhead = 'target';
21607         } else {
21608             j = 2;
21609             oppositeArrowhead = 'source';
21610         }
21611
21612         var end = this.model.get(oppositeArrowhead);
21613
21614         if (end.id) {
21615             args[i] = this.paper.findViewByModel(end.id);
21616             args[i+1] = end.selector && args[i].el.querySelector(end.selector);
21617         }
21618
21619         function validateConnectionArgs(cellView, magnet) {
21620             args[j] = cellView;
21621             args[j+1] = cellView.el === magnet ? undefined : magnet;
21622             return args;
21623         }
21624
21625         return validateConnectionArgs;
21626     },
21627
21628     startArrowheadMove: function(end) {
21629         // Allow to delegate events from an another view to this linkView in order to trigger arrowhead
21630         // move without need to click on the actual arrowhead dom element.
21631         this._action = 'arrowhead-move';
21632         this._arrowhead = end;
21633         this._beforeArrowheadMove();
21634         this._validateConnectionArgs = this._createValidateConnectionArgs(this._arrowhead);
21635     },
21636
21637     pointerdown: function(evt, x, y) {
21638
21639         joint.dia.CellView.prototype.pointerdown.apply(this, arguments);
21640
21641         this._dx = x;
21642         this._dy = y;
21643
21644         if (this.options.interactive === false) return;
21645
21646         var className = evt.target.getAttribute('class');
21647
21648         switch (className) {
21649
21650         case 'marker-vertex':
21651             this._action = 'vertex-move';
21652             this._vertexIdx = evt.target.getAttribute('idx');
21653             break;
21654
21655         case 'marker-vertex-remove':
21656         case 'marker-vertex-remove-area':
21657             this.removeVertex(evt.target.getAttribute('idx'));
21658             break;
21659
21660         case 'marker-arrowhead':
21661             this.startArrowheadMove(evt.target.getAttribute('end'));
21662             break;
21663
21664         default:
21665
21666             var targetParentEvent = evt.target.parentNode.getAttribute('event');
21667
21668             if (targetParentEvent) {
21669
21670                 // `remove` event is built-in. Other custom events are triggered on the paper.
21671                 if (targetParentEvent === 'remove') {
21672                     this.model.remove();
21673                 } else {
21674                     this.paper.trigger(targetParentEvent, evt, this, x, y);
21675                 }
21676
21677             } else {
21678
21679                 // Store the index at which the new vertex has just been placed.
21680                 // We'll be update the very same vertex position in `pointermove()`.
21681                 this._vertexIdx = this.addVertex({ x: x, y: y });
21682                 this._action = 'vertex-move';
21683             }
21684         }
21685     },
21686
21687     pointermove: function(evt, x, y) {
21688
21689         joint.dia.CellView.prototype.pointermove.apply(this, arguments);
21690
21691         switch (this._action) {
21692
21693           case 'vertex-move':
21694
21695             var vertices = _.clone(this.model.get('vertices'));
21696             vertices[this._vertexIdx] = { x: x, y: y };
21697             this.model.set('vertices', vertices);
21698             break;
21699
21700           case 'arrowhead-move':
21701
21702             if (this.paper.options.snapLinks) {
21703
21704                 // checking view in close area of the pointer
21705
21706                 var r = this.paper.options.snapLinks.radius || 50;
21707                 var viewsInArea = this.paper.findViewsInArea({ x: x - r, y: y - r, width: 2 * r, height: 2 * r });
21708
21709                 this._closestView && this._closestView.unhighlight(this._closestEnd.selector);
21710                 this._closestView = this._closestEnd = null;
21711
21712                 var pointer = g.point(x,y);
21713                 var distance, minDistance = Number.MAX_VALUE;
21714
21715                 _.each(viewsInArea, function(view) {
21716
21717                     // skip connecting to the element in case '.': { magnet: false } attribute present
21718                     if (view.el.getAttribute('magnet') !== 'false') {
21719
21720                         // find distance from the center of the model to pointer coordinates
21721                         distance = view.model.getBBox().center().distance(pointer);
21722
21723                         // the connection is looked up in a circle area by `distance < r`
21724                         if (distance < r && distance < minDistance) {
21725
21726                             if (this.paper.options.validateConnection.apply(
21727                                 this.paper, this._validateConnectionArgs(view, null)
21728                             )) {
21729                                 minDistance = distance;
21730                                 this._closestView = view;
21731                                 this._closestEnd = { id: view.model.id };
21732                             }
21733                         }
21734                     }
21735
21736                     view.$('[magnet]').each(_.bind(function(index, magnet) {
21737
21738                         var bbox = V(magnet).bbox(false, this.paper.viewport);
21739
21740                         distance = pointer.distance({
21741                             x: bbox.x + bbox.width / 2,
21742                             y: bbox.y + bbox.height / 2
21743                         });
21744
21745                         if (distance < r && distance < minDistance) {
21746
21747                             if (this.paper.options.validateConnection.apply(
21748                                 this.paper, this._validateConnectionArgs(view, magnet)
21749                             )) {
21750                                 minDistance = distance;
21751                                 this._closestView = view;
21752                                 this._closestEnd = {
21753                                     id: view.model.id,
21754                                     selector: view.getSelector(magnet),
21755                                     port: magnet.getAttribute('port')
21756                                 };
21757                             }
21758                         }
21759
21760                     }, this));
21761
21762                 }, this);
21763
21764                 this._closestView && this._closestView.highlight(this._closestEnd.selector);
21765
21766                 this.model.set(this._arrowhead, this._closestEnd || { x: x, y: y });
21767
21768             } else {
21769
21770                 // checking views right under the pointer
21771
21772                 // Touchmove event's target is not reflecting the element under the coordinates as mousemove does.
21773                 // It holds the element when a touchstart triggered.
21774                 var target = (evt.type === 'mousemove')
21775                     ? evt.target
21776                     : document.elementFromPoint(evt.clientX, evt.clientY);
21777
21778                 if (this._targetEvent !== target) {
21779                     // Unhighlight the previous view under pointer if there was one.
21780                     this._magnetUnderPointer && this._viewUnderPointer.unhighlight(this._magnetUnderPointer);
21781                     this._viewUnderPointer = this.paper.findView(target);
21782                     if (this._viewUnderPointer) {
21783                         // If we found a view that is under the pointer, we need to find the closest
21784                         // magnet based on the real target element of the event.
21785                         this._magnetUnderPointer = this._viewUnderPointer.findMagnet(target);
21786
21787                         if (this._magnetUnderPointer && this.paper.options.validateConnection.apply(
21788                             this.paper,
21789                             this._validateConnectionArgs(this._viewUnderPointer, this._magnetUnderPointer)
21790                         )) {
21791                             // If there was no magnet found, do not highlight anything and assume there
21792                             // is no view under pointer we're interested in reconnecting to.
21793                             // This can only happen if the overall element has the attribute `'.': { magnet: false }`.
21794                             this._magnetUnderPointer && this._viewUnderPointer.highlight(this._magnetUnderPointer);
21795                         } else {
21796                             // This type of connection is not valid. Disregard this magnet.
21797                             this._magnetUnderPointer = null;
21798                         }
21799                     } else {
21800                         // Make sure we'll delete previous magnet
21801                         this._magnetUnderPointer = null;
21802                     }
21803                 }
21804
21805                 this._targetEvent = target;
21806
21807                 this.model.set(this._arrowhead, { x: x, y: y });
21808             }
21809
21810             break;
21811         }
21812
21813         this._dx = x;
21814         this._dy = y;
21815     },
21816
21817     pointerup: function(evt) {
21818
21819         joint.dia.CellView.prototype.pointerup.apply(this, arguments);
21820
21821         if (this._action === 'arrowhead-move') {
21822
21823             if (this.paper.options.snapLinks) {
21824
21825                 this._closestView && this._closestView.unhighlight(this._closestEnd.selector);
21826                 this._closestView = this._closestEnd = null;
21827
21828             } else {
21829
21830                 if (this._magnetUnderPointer) {
21831                     this._viewUnderPointer.unhighlight(this._magnetUnderPointer);
21832                     // Find a unique `selector` of the element under pointer that is a magnet. If the
21833                     // `this._magnetUnderPointer` is the root element of the `this._viewUnderPointer` itself,
21834                     // the returned `selector` will be `undefined`. That means we can directly pass it to the
21835                     // `source`/`target` attribute of the link model below.
21836                     this.model.set(this._arrowhead, {
21837                         id: this._viewUnderPointer.model.id,
21838                         selector: this._viewUnderPointer.getSelector(this._magnetUnderPointer),
21839                         port: $(this._magnetUnderPointer).attr('port')
21840                     });
21841                 }
21842
21843                 delete this._viewUnderPointer;
21844                 delete this._magnetUnderPointer;
21845                 delete this._staticView;
21846                 delete this._staticMagnet;
21847             }
21848
21849             this._afterArrowheadMove();
21850         }
21851
21852         delete this._action;
21853     }
21854 });
21855
21856
21857 if (typeof exports === 'object') {
21858
21859     module.exports.Link = joint.dia.Link;
21860     module.exports.LinkView = joint.dia.LinkView;
21861 }
21862
21863 //      JointJS library.
21864 //      (c) 2011-2013 client IO
21865
21866
21867 joint.dia.Paper = Backbone.View.extend({
21868
21869     options: {
21870
21871         width: 800,
21872         height: 600,
21873         gridSize: 50,
21874         perpendicularLinks: false,
21875         elementView: joint.dia.ElementView,
21876         linkView: joint.dia.LinkView,
21877         snapLinks: false, // false, true, { radius: value }
21878
21879         // Defines what link model is added to the graph after an user clicks on an active magnet.
21880         // Value could be the Backbone.model or a function returning the Backbone.model
21881         // defaultLink: function(elementView, magnet) { return condition ? new customLink1() : new customLink2() }
21882         defaultLink: new joint.dia.Link,
21883
21884         // Check whether to add a new link to the graph when user clicks on an a magnet.
21885         validateMagnet: function(cellView, magnet) {
21886             return magnet.getAttribute('magnet') !== 'passive';
21887         },
21888
21889         // Check whether to allow or disallow the link connection while an arrowhead end (source/target)
21890         // being changed.
21891         validateConnection: function(cellViewS, magnetS, cellViewT, magnetT, end, linkView) {
21892             return (end === 'target' ? cellViewT : cellViewS) instanceof joint.dia.ElementView;
21893         }
21894     },
21895
21896     events: {
21897
21898         'mousedown': 'pointerdown',
21899         'dblclick': 'mousedblclick',
21900         'click': 'mouseclick',
21901         'touchstart': 'pointerdown',
21902         'mousemove': 'pointermove',
21903         'touchmove': 'pointermove'
21904     },
21905
21906     initialize: function() {
21907
21908         _.bindAll(this, 'addCell', 'sortCells', 'resetCells', 'pointerup');
21909
21910         this.svg = V('svg').node;
21911         this.viewport = V('g').node;
21912
21913         // Append `<defs>` element to the SVG document. This is useful for filters and gradients.
21914         V(this.svg).append(V('defs').node);
21915
21916         V(this.viewport).attr({ 'class': 'viewport' });
21917         
21918         V(this.svg).append(this.viewport);
21919
21920         this.$el.append(this.svg);
21921
21922         this.setDimensions();
21923
21924         this.listenTo(this.model, 'add', this.addCell);
21925         this.listenTo(this.model, 'reset', this.resetCells);
21926         this.listenTo(this.model, 'sort', this.sortCells);
21927
21928         $(document).on('mouseup touchend', this.pointerup);
21929
21930         // Hold the value when mouse has been moved: when mouse moved, no click event will be triggered.
21931         this._mousemoved = false;
21932     },
21933
21934     remove: function() {
21935
21936         $(document).off('mouseup touchend', this.pointerup);
21937
21938         Backbone.View.prototype.remove.call(this);
21939     },
21940
21941     setDimensions: function(width, height) {
21942
21943         if (width) this.options.width = width;
21944         if (height) this.options.height = height;
21945         
21946         V(this.svg).attr('width', this.options.width);
21947         V(this.svg).attr('height', this.options.height);
21948
21949         this.trigger('resize');
21950     },
21951
21952     // Expand/shrink the paper to fit the content. Snap the width/height to the grid
21953     // defined in `gridWidth`, `gridHeight`. `padding` adds to the resulting width/height of the paper.
21954     fitToContent: function(gridWidth, gridHeight, padding) {
21955
21956         gridWidth = gridWidth || 1;
21957         gridHeight = gridHeight || 1;
21958         padding = padding || 0;
21959
21960         // Calculate the paper size to accomodate all the graph's elements.
21961         var bbox = V(this.viewport).bbox(true, this.svg);
21962
21963         var calcWidth = Math.ceil((bbox.width + bbox.x) / gridWidth) * gridWidth;
21964         var calcHeight = Math.ceil((bbox.height + bbox.y) / gridHeight) * gridHeight;
21965
21966         calcWidth += padding;
21967         calcHeight += padding;
21968         
21969         // Change the dimensions only if there is a size discrepency
21970         if (calcWidth != this.options.width || calcHeight != this.options.height) {
21971             this.setDimensions(calcWidth || this.options.width , calcHeight || this.options.height);
21972         }
21973     },
21974
21975     getContentBBox: function() {
21976
21977         var crect = this.viewport.getBoundingClientRect();
21978
21979         // Using Screen CTM was the only way to get the real viewport bounding box working in both
21980         // Google Chrome and Firefox.
21981         var ctm = this.viewport.getScreenCTM();
21982
21983         var bbox = g.rect(Math.abs(crect.left - ctm.e), Math.abs(crect.top - ctm.f), crect.width, crect.height);
21984
21985         return bbox;
21986     },
21987
21988     createViewForModel: function(cell) {
21989
21990         var view;
21991         
21992         var type = cell.get('type');
21993         var module = type.split('.')[0];
21994         var entity = type.split('.')[1];
21995
21996         // If there is a special view defined for this model, use that one instead of the default `elementView`/`linkView`.
21997         if (joint.shapes[module] && joint.shapes[module][entity + 'View']) {
21998
21999             view = new joint.shapes[module][entity + 'View']({ model: cell, interactive: this.options.interactive });
22000             
22001         } else if (cell instanceof joint.dia.Element) {
22002                 
22003             view = new this.options.elementView({ model: cell, interactive: this.options.interactive });
22004
22005         } else {
22006
22007             view = new this.options.linkView({ model: cell, interactive: this.options.interactive });
22008         }
22009
22010         return view;
22011     },
22012     
22013     addCell: function(cell) {
22014
22015         var view = this.createViewForModel(cell);
22016
22017         V(this.viewport).append(view.el);
22018         view.paper = this;
22019         view.render();
22020
22021         // This is the only way to prevent image dragging in Firefox that works.
22022         // Setting -moz-user-select: none, draggable="false" attribute or user-drag: none didn't help.
22023         $(view.el).find('image').on('dragstart', function() { return false; });
22024     },
22025
22026     resetCells: function(cellsCollection) {
22027
22028         $(this.viewport).empty();
22029
22030         var cells = cellsCollection.models.slice();
22031
22032         // Make sure links are always added AFTER elements.
22033         // They wouldn't find their sources/targets in the DOM otherwise.
22034         cells.sort(function(a, b) { return a instanceof joint.dia.Link ? 1 : -1; });
22035         
22036         _.each(cells, this.addCell, this);
22037
22038         // Sort the cells in the DOM manually as we might have changed the order they
22039         // were added to the DOM (see above).
22040         this.sortCells();
22041     },
22042
22043     sortCells: function() {
22044
22045         // Run insertion sort algorithm in order to efficiently sort DOM elements according to their
22046         // associated model `z` attribute.
22047
22048         var $cells = $(this.viewport).children('[model-id]');
22049         var cells = this.model.get('cells');
22050
22051         this.sortElements($cells, function(a, b) {
22052
22053             var cellA = cells.get($(a).attr('model-id'));
22054             var cellB = cells.get($(b).attr('model-id'));
22055             
22056             return (cellA.get('z') || 0) > (cellB.get('z') || 0) ? 1 : -1;
22057         });
22058     },
22059
22060     // Highly inspired by the jquery.sortElements plugin by Padolsey.
22061     // See http://james.padolsey.com/javascript/sorting-elements-with-jquery/.
22062     sortElements: function(elements, comparator) {
22063
22064         var $elements = $(elements);
22065         
22066         var placements = $elements.map(function() {
22067
22068             var sortElement = this;
22069             var parentNode = sortElement.parentNode;
22070
22071             // Since the element itself will change position, we have
22072             // to have some way of storing it's original position in
22073             // the DOM. The easiest way is to have a 'flag' node:
22074             var nextSibling = parentNode.insertBefore(
22075                 document.createTextNode(''),
22076                 sortElement.nextSibling
22077             );
22078
22079             return function() {
22080                 
22081                 if (parentNode === this) {
22082                     throw new Error(
22083                         "You can't sort elements if any one is a descendant of another."
22084                     );
22085                 }
22086                 
22087                 // Insert before flag:
22088                 parentNode.insertBefore(this, nextSibling);
22089                 // Remove flag:
22090                 parentNode.removeChild(nextSibling);
22091                 
22092             };
22093         });
22094
22095         return Array.prototype.sort.call($elements, comparator).each(function(i) {
22096             placements[i].call(this);
22097         });
22098     },
22099
22100     scale: function(sx, sy, ox, oy) {
22101
22102         if (!ox) {
22103
22104             ox = 0;
22105             oy = 0;
22106         }
22107
22108         // Remove previous transform so that the new scale is not affected by previous scales, especially
22109         // the old translate() does not affect the new translate if an origin is specified.
22110         V(this.viewport).attr('transform', '');
22111         
22112         // TODO: V.scale() doesn't support setting scale origin. #Fix        
22113         if (ox || oy) {
22114             V(this.viewport).translate(-ox * (sx - 1), -oy * (sy - 1));
22115         }
22116         
22117         V(this.viewport).scale(sx, sy);
22118
22119         this.trigger('scale', ox, oy);
22120
22121         return this;
22122     },
22123
22124     rotate: function(deg, ox, oy) {
22125         
22126         // If the origin is not set explicitely, rotate around the center. Note that
22127         // we must use the plain bounding box (`this.el.getBBox()` instead of the one that gives us
22128         // the real bounding box (`bbox()`) including transformations).
22129         if (_.isUndefined(ox)) {
22130
22131             var bbox = this.viewport.getBBox();
22132             ox = bbox.width/2;
22133             oy = bbox.height/2;
22134         }
22135
22136         V(this.viewport).rotate(deg, ox, oy);
22137     },
22138
22139     // Find the first view climbing up the DOM tree starting at element `el`. Note that `el` can also
22140     // be a selector or a jQuery object.
22141     findView: function(el) {
22142
22143         var $el = this.$(el);
22144
22145         if ($el.length === 0 || $el[0] === this.el) {
22146
22147             return undefined;
22148         }
22149
22150         if ($el.data('view')) {
22151
22152             return $el.data('view');
22153         }
22154
22155         return this.findView($el.parent());
22156     },
22157
22158     // Find a view for a model `cell`. `cell` can also be a string representing a model `id`.
22159     findViewByModel: function(cell) {
22160
22161         var id = _.isString(cell) ? cell : cell.id;
22162         
22163         var $view = this.$('[model-id="' + id + '"]');
22164         if ($view.length) {
22165
22166             return $view.data('view');
22167         }
22168         return undefined;
22169     },
22170
22171     // Find all views at given point
22172     findViewsFromPoint: function(p) {
22173
22174         p = g.point(p);
22175
22176         var views = _.map(this.model.getElements(), this.findViewByModel);
22177
22178         return _.filter(views, function(view) {
22179             return g.rect(V(view.el).bbox(false, this.viewport)).containsPoint(p);
22180         }, this);
22181     },
22182
22183     // Find all views in given area
22184     findViewsInArea: function(r) {
22185
22186         r = g.rect(r);
22187
22188         var views = _.map(this.model.getElements(), this.findViewByModel);
22189
22190         return _.filter(views, function(view) {
22191             return r.intersect(g.rect(V(view.el).bbox(false, this.viewport)));
22192         }, this);
22193     },
22194
22195     getModelById: function(id) {
22196
22197         return this.model.getCell(id);
22198     },
22199
22200     snapToGrid: function(p) {
22201
22202         // Convert global coordinates to the local ones of the `viewport`. Otherwise,
22203         // improper transformation would be applied when the viewport gets transformed (scaled/rotated). 
22204         var localPoint = V(this.viewport).toLocalPoint(p.x, p.y);
22205
22206         return {
22207             x: g.snapToGrid(localPoint.x, this.options.gridSize),
22208             y: g.snapToGrid(localPoint.y, this.options.gridSize)
22209         };
22210     },
22211
22212     getDefaultLink: function(cellView, magnet) {
22213
22214         return _.isFunction(this.options.defaultLink)
22215         // default link is a function producing link model
22216             ? this.options.defaultLink.call(this, cellView, magnet)
22217         // default link is the Backbone model
22218             : this.options.defaultLink.clone();
22219     },
22220
22221     // Interaction.
22222     // ------------
22223
22224     mousedblclick: function(evt) {
22225         
22226         evt.preventDefault();
22227         evt = joint.util.normalizeEvent(evt);
22228         
22229         var view = this.findView(evt.target);
22230         var localPoint = this.snapToGrid({ x: evt.clientX, y: evt.clientY });
22231
22232         if (view) {
22233             
22234             view.pointerdblclick(evt, localPoint.x, localPoint.y);
22235             
22236         } else {
22237             
22238             this.trigger('blank:pointerdblclick', evt, localPoint.x, localPoint.y);
22239         }
22240     },
22241
22242     mouseclick: function(evt) {
22243
22244         // Trigger event when mouse not moved.
22245         if (!this._mousemoved) {
22246             
22247             evt.preventDefault();
22248             evt = joint.util.normalizeEvent(evt);
22249
22250             var view = this.findView(evt.target);
22251             var localPoint = this.snapToGrid({ x: evt.clientX, y: evt.clientY });
22252
22253             if (view) {
22254
22255                 view.pointerclick(evt, localPoint.x, localPoint.y);
22256                 
22257             } else {
22258
22259                 this.trigger('blank:pointerclick', evt, localPoint.x, localPoint.y);
22260             }
22261         }
22262
22263         this._mousemoved = false;
22264     },
22265
22266     pointerdown: function(evt) {
22267
22268         evt.preventDefault();
22269         evt = joint.util.normalizeEvent(evt);
22270         
22271         var view = this.findView(evt.target);
22272
22273         var localPoint = this.snapToGrid({ x: evt.clientX, y: evt.clientY });
22274         
22275         if (view) {
22276
22277             this.sourceView = view;
22278
22279             view.pointerdown(evt, localPoint.x, localPoint.y);
22280             
22281         } else {
22282
22283             this.trigger('blank:pointerdown', evt, localPoint.x, localPoint.y);
22284         }
22285     },
22286
22287     pointermove: function(evt) {
22288
22289         evt.preventDefault();
22290         evt = joint.util.normalizeEvent(evt);
22291
22292         if (this.sourceView) {
22293
22294             // Mouse moved.
22295             this._mousemoved = true;
22296
22297             var localPoint = this.snapToGrid({ x: evt.clientX, y: evt.clientY });
22298
22299             this.sourceView.pointermove(evt, localPoint.x, localPoint.y);
22300         }
22301     },
22302
22303     pointerup: function(evt) {
22304
22305         evt = joint.util.normalizeEvent(evt);
22306
22307         var localPoint = this.snapToGrid({ x: evt.clientX, y: evt.clientY });
22308         
22309         if (this.sourceView) {
22310
22311             this.sourceView.pointerup(evt, localPoint.x, localPoint.y);
22312
22313             //"delete sourceView" occasionally throws an error in chrome (illegal access exception)
22314             this.sourceView = null;
22315
22316         } else {
22317
22318             this.trigger('blank:pointerup', evt, localPoint.x, localPoint.y);
22319         }
22320     }
22321 });
22322
22323
22324 //      JointJS library.
22325 //      (c) 2011-2013 client IO
22326
22327
22328 if (typeof exports === 'object') {
22329
22330     var joint = {
22331         util: require('../src/core').util,
22332         shapes: {},
22333         dia: {
22334             Element: require('../src/joint.dia.element').Element,
22335             ElementView: require('../src/joint.dia.element').ElementView
22336         }
22337     };
22338     var _ = require('lodash');
22339 }
22340
22341
22342 joint.shapes.basic = {};
22343
22344
22345 joint.shapes.basic.Generic = joint.dia.Element.extend({
22346
22347     defaults: joint.util.deepSupplement({
22348         
22349         type: 'basic.Generic',
22350         attrs: {
22351             '.': { fill: '#FFFFFF', stroke: 'none' }
22352         }
22353         
22354     }, joint.dia.Element.prototype.defaults)
22355 });
22356
22357 joint.shapes.basic.Rect = joint.shapes.basic.Generic.extend({
22358
22359     markup: '<g class="rotatable"><g class="scalable"><rect/></g><text/></g>',
22360     
22361     defaults: joint.util.deepSupplement({
22362     
22363         type: 'basic.Rect',
22364         attrs: {
22365             'rect': { fill: '#FFFFFF', stroke: 'black', width: 100, height: 60 },
22366             'text': { 'font-size': 14, text: '', 'ref-x': .5, 'ref-y': .5, ref: 'rect', 'y-alignment': 'middle', 'x-alignment': 'middle', fill: 'black', 'font-family': 'Arial, helvetica, sans-serif' }
22367         }
22368         
22369     }, joint.shapes.basic.Generic.prototype.defaults)
22370 });
22371
22372 joint.shapes.basic.Text = joint.shapes.basic.Generic.extend({
22373
22374     markup: '<g class="rotatable"><g class="scalable"><text/></g></g>',
22375     
22376     defaults: joint.util.deepSupplement({
22377         
22378         type: 'basic.Text',
22379         attrs: {
22380             'text': { 'font-size': 18, fill: 'black' }
22381         }
22382         
22383     }, joint.shapes.basic.Generic.prototype.defaults)
22384 });
22385
22386 joint.shapes.basic.Circle = joint.shapes.basic.Generic.extend({
22387
22388     markup: '<g class="rotatable"><g class="scalable"><circle/></g><text/></g>',
22389     
22390     defaults: joint.util.deepSupplement({
22391
22392         type: 'basic.Circle',
22393         size: { width: 60, height: 60 },
22394         attrs: {
22395             'circle': { fill: '#FFFFFF', stroke: 'black', r: 30, transform: 'translate(30, 30)' },
22396             'text': { 'font-size': 14, text: '', 'text-anchor': 'middle', 'ref-x': .5, 'ref-y': .5, ref: 'circle', 'y-alignment': 'middle', fill: 'black', 'font-family': 'Arial, helvetica, sans-serif' }
22397         }
22398     }, joint.shapes.basic.Generic.prototype.defaults)
22399 });
22400
22401 joint.shapes.basic.Image = joint.shapes.basic.Generic.extend({
22402
22403     markup: '<g class="rotatable"><g class="scalable"><image/></g><text/></g>',
22404     
22405     defaults: joint.util.deepSupplement({
22406
22407         type: 'basic.Image',
22408         attrs: {
22409             'text': { 'font-size': 14, text: '', 'text-anchor': 'middle', 'ref-x': .5, 'ref-dy': 20, ref: 'image', 'y-alignment': 'middle', fill: 'black', 'font-family': 'Arial, helvetica, sans-serif' }
22410         }
22411     }, joint.shapes.basic.Generic.prototype.defaults)
22412 });
22413
22414 joint.shapes.basic.Path = joint.shapes.basic.Generic.extend({
22415
22416     markup: '<g class="rotatable"><g class="scalable"><path/></g><text/></g>',
22417     
22418     defaults: joint.util.deepSupplement({
22419
22420         type: 'basic.Path',
22421         size: { width: 60, height: 60 },
22422         attrs: {
22423             'path': { fill: '#FFFFFF', stroke: 'black' },
22424             'text': { 'font-size': 14, text: '', 'text-anchor': 'middle', 'ref-x': .5, 'ref-dy': 20, ref: 'path', 'y-alignment': 'middle', fill: 'black', 'font-family': 'Arial, helvetica, sans-serif' }
22425         }
22426     }, joint.shapes.basic.Generic.prototype.defaults)
22427 });
22428
22429 // PortsModelInterface is a common interface for shapes that have ports. This interface makes it easy
22430 // to create new shapes with ports functionality. It is assumed that the new shapes have
22431 // `inPorts` and `outPorts` array properties. Only these properties should be used to set ports.
22432 // In other words, using this interface, it is no longer recommended to set ports directly through the
22433 // `attrs` object.
22434
22435 // Usage:
22436 // joint.shapes.custom.MyElementWithPorts = joint.shapes.basic.Path.extend(_.extend({}, joint.shapes.basic.PortsModelInterface, {
22437 //     getPortAttrs: function(portName, index, total, selector, type) {
22438 //         var attrs = {};
22439 //         var portClass = 'port' + index;
22440 //         var portSelector = selector + '>.' + portClass;
22441 //         var portTextSelector = portSelector + '>text';
22442 //         var portCircleSelector = portSelector + '>circle';
22443 //
22444 //         attrs[portTextSelector] = { text: portName };
22445 //         attrs[portCircleSelector] = { port: { id: portName || _.uniqueId(type) , type: type } };
22446 //         attrs[portSelector] = { ref: 'rect', 'ref-y': (index + 0.5) * (1 / total) };
22447 //
22448 //         if (selector === '.outPorts') { attrs[portSelector]['ref-dx'] = 0; }
22449 //
22450 //         return attrs;
22451 //     }
22452 //}));
22453 joint.shapes.basic.PortsModelInterface = {
22454
22455     initialize: function() {
22456
22457         this.updatePortsAttrs();
22458         this.on('change:inPorts change:outPorts', this.updatePortsAttrs, this);
22459
22460         // Call the `initialize()` of the parent.
22461         this.constructor.__super__.constructor.__super__.initialize.apply(this, arguments);
22462     },
22463     
22464     updatePortsAttrs: function(eventName) {
22465
22466         // Delete previously set attributes for ports.
22467         var currAttrs = this.get('attrs');
22468         _.each(this._portSelectors, function(selector) {
22469             if (currAttrs[selector]) delete currAttrs[selector];
22470         });
22471         
22472         // This holds keys to the `attrs` object for all the port specific attribute that
22473         // we set in this method. This is necessary in order to remove previously set
22474         // attributes for previous ports.
22475         this._portSelectors = [];
22476         
22477         var attrs = {};
22478         
22479         _.each(this.get('inPorts'), function(portName, index, ports) {
22480             var portAttributes = this.getPortAttrs(portName, index, ports.length, '.inPorts', 'in');
22481             this._portSelectors = this._portSelectors.concat(_.keys(portAttributes));
22482             _.extend(attrs, portAttributes);
22483         }, this);
22484         
22485         _.each(this.get('outPorts'), function(portName, index, ports) {
22486             var portAttributes = this.getPortAttrs(portName, index, ports.length, '.outPorts', 'out');
22487             this._portSelectors = this._portSelectors.concat(_.keys(portAttributes));
22488             _.extend(attrs, portAttributes);
22489         }, this);
22490
22491         // Silently set `attrs` on the cell so that noone knows the attrs have changed. This makes sure
22492         // that, for example, command manager does not register `change:attrs` command but only
22493         // the important `change:inPorts`/`change:outPorts` command.
22494         this.attr(attrs, { silent: true });
22495         // Manually call the `processPorts()` method that is normally called on `change:attrs` (that we just made silent).
22496         this.processPorts();
22497         // Let the outside world (mainly the `ModelView`) know that we're done configuring the `attrs` object.
22498         this.trigger('process:ports');
22499     },
22500
22501     getPortSelector: function(name) {
22502
22503         var selector = '.inPorts';
22504         var index = this.get('inPorts').indexOf(name);
22505
22506         if (index < 0) {
22507             selector = '.outPorts';
22508             index = this.get('outPorts').indexOf(name);
22509
22510             if (index < 0) throw new Error("getPortSelector(): Port doesn't exist.");
22511         }
22512
22513         return selector + '>g:nth-child(' + (index + 1) + ')>circle';
22514     }
22515 };
22516
22517 joint.shapes.basic.PortsViewInterface = {
22518     
22519     initialize: function() {
22520
22521         // `Model` emits the `process:ports` whenever it's done configuring the `attrs` object for ports.
22522         this.listenTo(this.model, 'process:ports', this.update);
22523         
22524         joint.dia.ElementView.prototype.initialize.apply(this, arguments);
22525     },
22526
22527     update: function() {
22528
22529         // First render ports so that `attrs` can be applied to those newly created DOM elements
22530         // in `ElementView.prototype.update()`.
22531         this.renderPorts();
22532         joint.dia.ElementView.prototype.update.apply(this, arguments);
22533     },
22534
22535     renderPorts: function() {
22536
22537         var $inPorts = this.$('.inPorts').empty();
22538         var $outPorts = this.$('.outPorts').empty();
22539
22540         var portTemplate = _.template(this.model.portMarkup);
22541
22542         _.each(_.filter(this.model.ports, function(p) { return p.type === 'in' }), function(port, index) {
22543
22544             $inPorts.append(V(portTemplate({ id: index, port: port })).node);
22545         });
22546         _.each(_.filter(this.model.ports, function(p) { return p.type === 'out' }), function(port, index) {
22547
22548             $outPorts.append(V(portTemplate({ id: index, port: port })).node);
22549         });
22550     }
22551 };
22552
22553 joint.shapes.basic.TextBlock = joint.shapes.basic.Generic.extend({
22554
22555     markup: ['<g class="rotatable"><g class="scalable"><rect/></g><switch>',
22556
22557              // if foreignObject supported
22558
22559              '<foreignObject requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" class="fobj">',
22560              '<body xmlns="http://www.w3.org/1999/xhtml"><div/></body>',
22561              '</foreignObject>',
22562
22563              // else foreignObject is not supported (fallback for IE)
22564              '<text class="content"/>',
22565
22566              '</switch></g>'].join(''),
22567
22568     defaults: joint.util.deepSupplement({
22569
22570         type: 'basic.TextBlock',
22571
22572         // see joint.css for more element styles
22573         attrs: {
22574             rect: {
22575                 fill: '#ffffff',
22576                 stroke: '#000000',
22577                 width: 80,
22578                 height: 100
22579             },
22580             text: {
22581                 fill: '#000000',
22582                 'font-size': 14,
22583                 'font-family': 'Arial, helvetica, sans-serif'
22584             },
22585             '.content': {
22586                 text: '',
22587                 ref: 'rect',
22588                 'ref-x': .5,
22589                 'ref-y': .5,
22590                 'y-alignment': 'middle',
22591                 'x-alignment': 'middle'
22592             }
22593         },
22594
22595         content: ''
22596
22597     }, joint.shapes.basic.Generic.prototype.defaults),
22598
22599     initialize: function() {
22600
22601         if (typeof SVGForeignObjectElement !== 'undefined') {
22602
22603             // foreignObject supported
22604             this.setForeignObjectSize(this, this.get('size'));
22605             this.setDivContent(this, this.get('content'));
22606             this.listenTo(this, 'change:size', this.setForeignObjectSize);
22607             this.listenTo(this, 'change:content', this.setDivContent);
22608
22609         }
22610
22611         joint.shapes.basic.Generic.prototype.initialize.apply(this, arguments);
22612     },
22613
22614     setForeignObjectSize: function(cell, size) {
22615
22616         // Selector `foreignObject' doesn't work accross all browsers, we'r using class selector instead.
22617         // We have to clone size as we don't want attributes.div.style to be same object as attributes.size.
22618         cell.attr({
22619             '.fobj': _.clone(size),
22620             div: { style: _.clone(size) }
22621         });
22622     },
22623
22624     setDivContent: function(cell, content) {
22625
22626         // Append the content to div as html.
22627         cell.attr({ div : {
22628             html: content
22629         }});
22630     }
22631
22632 });
22633
22634 // TextBlockView implements the fallback for IE when no foreignObject exists and
22635 // the text needs to be manually broken.
22636 joint.shapes.basic.TextBlockView = joint.dia.ElementView.extend({
22637
22638     initialize: function() {
22639
22640         joint.dia.ElementView.prototype.initialize.apply(this, arguments);
22641
22642         if (typeof SVGForeignObjectElement === 'undefined') {
22643
22644             this.noSVGForeignObjectElement = true;
22645
22646             this.listenTo(this.model, 'change:content', function(cell) {
22647                 // avoiding pass of extra paramters
22648                 this.updateContent(cell);
22649             });
22650         }
22651     },
22652
22653     update: function(cell, renderingOnlyAttrs) {
22654
22655         if (this.noSVGForeignObjectElement) {
22656
22657             var model = this.model;
22658
22659             // Update everything but the content first.
22660             var noTextAttrs = _.omit(renderingOnlyAttrs || model.get('attrs'), '.content');
22661             joint.dia.ElementView.prototype.update.call(this, model, noTextAttrs);
22662
22663             if (!renderingOnlyAttrs || _.has(renderingOnlyAttrs, '.content')) {
22664                 // Update the content itself.
22665                 this.updateContent(model, renderingOnlyAttrs);
22666             }
22667
22668         } else {
22669
22670             joint.dia.ElementView.prototype.update.call(this, model, renderingOnlyAttrs);
22671         }
22672     },
22673
22674     updateContent: function(cell, renderingOnlyAttrs) {
22675
22676         // Create copy of the text attributes
22677         var textAttrs = _.merge({}, (renderingOnlyAttrs || cell.get('attrs'))['.content']);
22678
22679         delete textAttrs.text;
22680
22681         // Break the content to fit the element size taking into account the attributes
22682         // set on the model.
22683         var text = joint.util.breakText(cell.get('content'), cell.get('size'), textAttrs, {
22684             // measuring sandbox svg document
22685             svgDocument: this.paper.svg
22686         });
22687
22688         // Create a new attrs with same structure as the model attrs { text: { *textAttributes* }}
22689         var attrs = joint.util.setByPath({}, '.content', textAttrs,'/');
22690
22691         // Replace text attribute with the one we just processed.
22692         attrs['.content'].text = text;
22693
22694         // Update the view using renderingOnlyAttributes parameter.
22695         joint.dia.ElementView.prototype.update.call(this, cell, attrs);
22696     }
22697 });
22698
22699 if (typeof exports === 'object') {
22700
22701     module.exports = joint.shapes.basic;
22702 }
22703
22704 joint.routers.orthogonal = function() {
22705
22706     var sourceBBox, targetBBox;
22707
22708     // Return the direction that one would have to take traveling from `p1` to `p2`.
22709     // This function assumes the line between `p1` and `p2` is orthogonal.
22710     function direction(p1, p2) {
22711         
22712         if (p1.y < p2.y && p1.x === p2.x) {
22713             return 'down';
22714         } else if (p1.y > p2.y && p1.x === p2.x) {
22715             return 'up';
22716         } else if (p1.x < p2.x && p1.y === p2.y) {
22717             return 'right';
22718         }
22719         return 'left';
22720     }
22721
22722     function bestDirection(p1, p2, preferredDirection) {
22723
22724         var directions;
22725
22726         // This branching determines possible directions that one can take to travel
22727         // from `p1` to `p2`.
22728         if (p1.x < p2.x) {
22729
22730             if (p1.y > p2.y) { directions = ['up', 'right']; }
22731             else if (p1.y < p2.y) { directions = ['down', 'right']; }
22732             else { directions = ['right']; }
22733
22734         } else if (p1.x > p2.x) {
22735
22736             if (p1.y > p2.y) { directions = ['up', 'left']; }
22737             else if (p1.y < p2.y) { directions = ['down', 'left']; }
22738             else { directions = ['left']; }
22739
22740         } else {
22741
22742             if (p1.y > p2.y) { directions = ['up']; }
22743             else { directions = ['down']; }
22744         }
22745
22746         if (_.contains(directions, preferredDirection)) {
22747             return preferredDirection;
22748         }
22749
22750         var direction = _.first(directions);
22751
22752         // Should the direction be the exact opposite of the preferred direction,
22753         // try another one if such direction exists.
22754         switch (preferredDirection) {
22755         case 'down': if (direction === 'up') return _.last(directions); break;
22756         case 'up': if (direction === 'down') return _.last(directions); break;
22757         case 'left': if (direction === 'right') return _.last(directions); break;
22758         case 'right': if (direction === 'left') return _.last(directions); break;
22759         }
22760         return direction;
22761     };
22762
22763     // Find a vertex in between the vertices `p1` and `p2` so that the route between those vertices
22764     // is orthogonal. Prefer going the direction determined by `preferredDirection`.
22765     function findMiddleVertex(p1, p2, preferredDirection) {
22766         
22767         var direction = bestDirection(p1, p2, preferredDirection);
22768         if (direction === 'down' || direction === 'up') {
22769             return { x: p1.x, y: p2.y, d: direction };
22770         }
22771         return { x: p2.x, y: p1.y, d: direction };
22772     }
22773
22774     // Return points that one needs to draw a connection through in order to have a orthogonal link
22775     // routing from source to target going through `vertices`.
22776     function findOrthogonalRoute(vertices) {
22777
22778         vertices = (vertices || []).slice();
22779         var orthogonalVertices = [];
22780
22781         var sourceCenter = sourceBBox.center();
22782         var targetCenter = targetBBox.center();
22783
22784         if (!vertices.length) {
22785
22786             if (Math.abs(sourceCenter.x - targetCenter.x) < (sourceBBox.width / 2) ||
22787                 Math.abs(sourceCenter.y - targetCenter.y) < (sourceBBox.height / 2)
22788             ) {
22789
22790                 vertices = [{
22791                     x: Math.min(sourceCenter.x, targetCenter.x) +
22792                         Math.abs(sourceCenter.x - targetCenter.x) / 2,
22793                     y: Math.min(sourceCenter.y, targetCenter.y) +
22794                         Math.abs(sourceCenter.y - targetCenter.y) / 2
22795                 }];
22796             }
22797         }
22798
22799         vertices.unshift(sourceCenter);
22800         vertices.push(targetCenter);
22801
22802         var orthogonalVertex;
22803         var lastOrthogonalVertex;
22804         var vertex;
22805         var nextVertex;
22806
22807         // For all the pairs of link model vertices...
22808         for (var i = 0; i < vertices.length - 1; i++) {
22809
22810             vertex = vertices[i];
22811             nextVertex = vertices[i + 1];
22812             lastOrthogonalVertex = _.last(orthogonalVertices);
22813             
22814             if (i > 0) {
22815                 // Push all the link vertices to the orthogonal route.
22816                 orthogonalVertex = vertex;
22817                 // Determine a direction between the last vertex and the new one.
22818                 // Therefore, each vertex contains the `d` property describing the direction that one
22819                 // would have to take to travel to that vertex.
22820                 orthogonalVertex.d = lastOrthogonalVertex
22821                     ? direction(lastOrthogonalVertex, vertex)
22822                     : 'top';
22823
22824                 orthogonalVertices.push(orthogonalVertex);
22825                 lastOrthogonalVertex = orthogonalVertex;
22826             }
22827
22828             // Make sure that we don't create a vertex that would go the opposite direction then
22829             // that of the previous one.
22830             // Othwerwise, a 'spike' segment would be created which is not desirable.
22831             // Find a dummy vertex to keep the link orthogonal. Preferably, take the same direction
22832             // as the previous one.
22833             var d = lastOrthogonalVertex && lastOrthogonalVertex.d;
22834             orthogonalVertex = findMiddleVertex(vertex, nextVertex, d);
22835
22836             // Do not add a new vertex that is the same as one of the vertices already added.
22837             if (!g.point(orthogonalVertex).equals(g.point(vertex)) &&
22838                 !g.point(orthogonalVertex).equals(g.point(nextVertex))) {
22839
22840                 orthogonalVertices.push(orthogonalVertex);
22841             }
22842         }
22843         return orthogonalVertices;
22844     };
22845
22846     return function(vertices) {
22847
22848         sourceBBox = this.sourceBBox;
22849         targetBBox = this.targetBBox;
22850
22851         return findOrthogonalRoute(vertices);
22852     };
22853
22854 }();
22855
22856 joint.routers.manhattan = (function() {
22857
22858     'use strict';
22859
22860     var config = {
22861
22862         // size of the step to find a route
22863         step: 10,
22864
22865         // use of the perpendicular linkView option to connect center of element with first vertex
22866         perpendicular: true,
22867
22868         // tells how to divide the paper when creating the elements map
22869         mapGridSize: 100,
22870
22871         // should be source or target not to be consider as an obstacle
22872         excludeEnds: [], // 'source', 'target'
22873
22874         // should be any element with a certain type not to be consider as an obstacle
22875         excludeTypes: ['basic.Text'],
22876
22877         // if number of route finding loops exceed the maximum, stops searching and returns
22878         // fallback route
22879         maximumLoops: 500,
22880
22881         // possible starting directions from an element
22882         startDirections: ['left','right','top','bottom'],
22883
22884         // possible ending directions to an element
22885         endDirections: ['left','right','top','bottom'],
22886
22887         // specify directions above
22888         directionMap: {
22889             right: { x: 1, y: 0 },
22890             bottom: { x: 0, y: 1 },
22891             left: { x: -1, y: 0 },
22892             top: { x: 0, y: -1 }
22893         },
22894
22895         // maximum change of the direction
22896         maxAllowedDirectionChange: 1,
22897
22898         // padding applied on the element bounding boxes
22899         paddingBox: function() {
22900
22901             var step = this.step;
22902
22903             return {
22904                 x: -step,
22905                 y: -step,
22906                 width: 2*step,
22907                 height: 2*step
22908             }
22909         },
22910
22911         // an array of directions to find next points on the route
22912         directions: function() {
22913
22914             var step = this.step;
22915
22916             return [
22917                 { offsetX: step  , offsetY: 0     , cost: step },
22918                 { offsetX: 0     , offsetY: step  , cost: step },
22919                 { offsetX: -step , offsetY: 0     , cost: step },
22920                 { offsetX: 0     , offsetY: -step , cost: step }
22921             ];
22922         },
22923
22924         // a penalty received for direction change
22925         penalties: function() {
22926
22927             return [0, this.step / 2, this.step];
22928         },
22929
22930         // heurestic method to determine the distance between two points
22931         estimateCost: function(from, to) {
22932
22933             return from.manhattanDistance(to);
22934         },
22935
22936         // a simple route used in situations, when main routing method fails
22937         // (exceed loops, inaccessible).
22938         fallbackRoute: function(from, to, opts) {
22939
22940             // Find an orthogonal route ignoring obstacles.
22941
22942             var prevDirIndexes = opts.prevDirIndexes || {};
22943
22944             var point = (prevDirIndexes[from] || 0) % 2
22945                     ? g.point(from.x, to.y)
22946                     : g.point(to.x, from.y);
22947
22948             return [point, to];
22949         },
22950
22951         // if a function is provided, it's used to route the link while dragging an end
22952         // i.e. function(from, to, opts) { return []; }
22953         draggingRoute: null
22954     };
22955
22956     // reconstructs a route by concating points with their parents
22957     function reconstructRoute(parents, point) {
22958
22959         var route = [];
22960         var prevDiff = { x: 0, y: 0 };
22961         var current = point;
22962         var parent;
22963
22964         while ((parent = parents[current])) {
22965
22966             var diff = parent.difference(current);
22967
22968             if (!diff.equals(prevDiff)) {
22969
22970                 route.unshift(current);
22971                 prevDiff = diff;
22972             }
22973
22974             current = parent;
22975         }
22976
22977         route.unshift(current);
22978
22979         return route;
22980     };
22981
22982     // find points around the rectangle taking given directions in the account
22983     function getRectPoints(bbox, directionList, opts) {
22984
22985         var step = opts.step;
22986
22987         var center = bbox.center();
22988
22989         var startPoints = _.chain(opts.directionMap).pick(directionList).map(function(direction) {
22990
22991             var x = direction.x * bbox.width / 2;
22992             var y = direction.y * bbox.height / 2;
22993
22994             var point = g.point(center).offset(x,y).snapToGrid(step);
22995
22996             if (bbox.containsPoint(point)) {
22997
22998                 point.offset(direction.x * step, direction.y * step);
22999             }
23000
23001             return point;
23002
23003         }).value();
23004
23005         return startPoints;
23006     };
23007
23008     // returns a direction index from start point to end point
23009     function getDirection(start, end, dirLen) {
23010
23011         var dirAngle = 360 / dirLen;
23012
23013         var q = Math.floor(start.theta(end) / dirAngle);
23014
23015         return dirLen - q;
23016     }
23017
23018     // finds the route between to points/rectangles implementing A* alghoritm
23019     function findRoute(start, end, map, opt) {
23020
23021         var startDirections = opt.reversed ? opt.endDirections : opt.startDirections;
23022         var endDirections = opt.reversed ? opt.startDirections : opt.endDirections;
23023
23024         // set of points we start pathfinding from
23025         var startSet = start instanceof g.rect
23026                 ? getRectPoints(start, startDirections, opt)
23027                 : [start];
23028
23029         // set of points we want the pathfinding to finish at
23030         var endSet = end instanceof g.rect
23031                 ? getRectPoints(end, endDirections, opt)
23032                 : [end];
23033
23034         var startCenter = startSet.length > 1 ? start.center() : startSet[0];
23035         var endCenter = endSet.length > 1 ? end.center() : endSet[0];
23036
23037         // take into account  only accessible end points
23038         var endPoints = _.filter(endSet, function(point) {
23039
23040             var mapKey = g.point(point).snapToGrid(opt.mapGridSize).toString();
23041
23042             var accesible = _.every(map[mapKey], function(obstacle) {
23043                 return !obstacle.containsPoint(point);
23044             });
23045
23046             return accesible;
23047         });
23048
23049
23050         if (endPoints.length) {
23051
23052             var step = opt.step;
23053             var penalties = opt.penalties;
23054
23055             // choose the end point with the shortest estimated path cost
23056             var endPoint = _.chain(endPoints).invoke('snapToGrid', step).min(function(point) {
23057
23058                 return opt.estimateCost(startCenter, point);
23059
23060             }).value();
23061
23062             var parents = {};
23063             var costFromStart = {};
23064             var totalCost = {};
23065
23066             // directions
23067             var dirs = opt.directions;
23068             var dirLen = dirs.length;
23069             var dirHalfLen = dirLen / 2;
23070             var dirIndexes = opt.previousDirIndexes || {};
23071
23072             // The set of point already evaluated.
23073             var closeHash = {}; // keeps only information whether a point was evaluated'
23074
23075             // The set of tentative points to be evaluated, initially containing the start points
23076             var openHash = {}; // keeps only information whether a point is to be evaluated'
23077             var openSet = _.chain(startSet).invoke('snapToGrid', step).each(function(point) {
23078
23079                 var key = point.toString();
23080
23081                 costFromStart[key] = 0; // Cost from start along best known path.
23082                 totalCost[key] = opt.estimateCost(point, endPoint);
23083                 dirIndexes[key] = dirIndexes[key] || getDirection(startCenter, point, dirLen);
23084                 openHash[key] = true;
23085
23086             }).map(function(point) {
23087
23088                 return point.toString();
23089
23090             }).sortBy(function(pointKey) {
23091
23092                 return totalCost[pointKey];
23093
23094             }).value();
23095
23096             var loopCounter = opt.maximumLoops;
23097
23098             var maxAllowedDirectionChange = opt.maxAllowedDirectionChange;
23099
23100             // main route finding loop
23101             while (openSet.length && loopCounter--) {
23102
23103                 var currentKey = openSet[0];
23104                 var currentPoint = g.point(currentKey);
23105
23106                 if (endPoint.equals(currentPoint)) {
23107
23108                     opt.previousDirIndexes = _.pick(dirIndexes, currentKey);
23109                     return reconstructRoute(parents, currentPoint);
23110                 }
23111
23112                 // remove current from the open list
23113                 openSet.splice(0, 1);
23114                 openHash[neighborKey] = null;
23115
23116                 // add current to the close list
23117                 closeHash[neighborKey] = true;
23118
23119                 var currentDirIndex = dirIndexes[currentKey];
23120                 var currentDist = costFromStart[currentKey];
23121
23122                 for (var dirIndex = 0; dirIndex < dirLen; dirIndex++) {
23123
23124                     var dirChange = Math.abs(dirIndex - currentDirIndex);
23125
23126                     if (dirChange > dirHalfLen) {
23127
23128                         dirChange = dirLen - dirChange;
23129                     }
23130
23131                     // if the direction changed rapidly don't use this point
23132                     if (dirChange > maxAllowedDirectionChange) {
23133
23134                         continue;
23135                     }
23136
23137                     var dir = dirs[dirIndex];
23138
23139                     var neighborPoint = g.point(currentPoint).offset(dir.offsetX, dir.offsetY);
23140                     var neighborKey = neighborPoint.toString();
23141
23142                     if (closeHash[neighborKey]) {
23143
23144                         continue;
23145                     }
23146
23147                     // is point accesible - no obstacle in the way
23148
23149                     var mapKey = g.point(neighborPoint).snapToGrid(opt.mapGridSize).toString();
23150
23151                     var isAccesible = _.every(map[mapKey], function(obstacle) {
23152                         return !obstacle.containsPoint(neighborPoint);
23153                     });
23154
23155                     if (!isAccesible) {
23156
23157                         continue;
23158                     }
23159
23160                     var inOpenSet = _.has(openHash, neighborKey);
23161
23162                     var costToNeighbor = currentDist + dir.cost;
23163
23164                     if (!inOpenSet || costToNeighbor < costFromStart[neighborKey]) {
23165
23166                         parents[neighborKey] = currentPoint;
23167                         dirIndexes[neighborKey] = dirIndex;
23168                         costFromStart[neighborKey] = costToNeighbor;
23169
23170                         totalCost[neighborKey] = costToNeighbor +
23171                             opt.estimateCost(neighborPoint, endPoint) +
23172                             penalties[dirChange];
23173
23174                         if (!inOpenSet) {
23175
23176                             var openIndex = _.sortedIndex(openSet, neighborKey, function(openKey) {
23177
23178                                 return totalCost[openKey];
23179                             });
23180
23181                             openSet.splice(openIndex, 0, neighborKey);
23182                             openHash[neighborKey] = true;
23183                         }
23184                     };
23185                 };
23186             }
23187         }
23188
23189         // no route found ('to' point wasn't either accessible or finding route took
23190         // way to much calculations)
23191         return opt.fallbackRoute(startCenter, endCenter, opt);
23192     };
23193
23194     // initiation of the route finding
23195     function router(oldVertices, opt) {
23196
23197         // resolve some of the options
23198         opt.directions = _.result(opt, 'directions');
23199         opt.penalties = _.result(opt, 'penalties');
23200         opt.paddingBox = _.result(opt, 'paddingBox');
23201
23202         // enable/disable linkView perpendicular option
23203         this.options.perpendicular = !!opt.perpendicular;
23204
23205         // As route changes its shape rapidly when we start finding route from different point
23206         // it's necessary to start from the element that was not interacted with
23207         // (the position was changed) at very last.
23208         var reverseRouting = opt.reversed = (this.lastEndChange === 'source');
23209
23210         var sourceBBox = reverseRouting ? g.rect(this.targetBBox) : g.rect(this.sourceBBox);
23211         var targetBBox = reverseRouting ? g.rect(this.sourceBBox) : g.rect(this.targetBBox);
23212
23213         // expand boxes by specific padding
23214         sourceBBox.moveAndExpand(opt.paddingBox);
23215         targetBBox.moveAndExpand(opt.paddingBox);
23216
23217         // building an elements map
23218
23219         var link = this.model;
23220         var graph = this.paper.model;
23221
23222         // source or target element could be excluded from set of obstacles
23223         var excludedEnds = _.chain(opt.excludeEnds)
23224                 .map(link.get, link)
23225                 .pluck('id')
23226                 .map(graph.getCell, graph).value();
23227
23228         var mapGridSize = opt.mapGridSize;
23229
23230         // builds a map of all elements for quicker obstacle queries (i.e. is a point contained
23231         // in any obstacle?) (a simplified grid search)
23232         // The paper is divided to smaller cells, where each of them holds an information which
23233         // elements belong to it. When we query whether a point is in an obstacle we don't need
23234         // to go through all obstacles, we check only those in a particular cell.
23235         var map = _.chain(graph.getElements())
23236             // remove source and target element if required
23237             .difference(excludedEnds)
23238             // remove all elements whose type is listed in excludedTypes array
23239             .reject(function(element) {
23240                 return _.contains(opt.excludeTypes, element.get('type'));
23241             })
23242             // change elements (models) to their bounding boxes
23243             .invoke('getBBox')
23244             // expand their boxes by specific padding
23245             .invoke('moveAndExpand', opt.paddingBox)
23246             // build the map
23247             .foldl(function(res, bbox) {
23248
23249                 var origin = bbox.origin().snapToGrid(mapGridSize);
23250                 var corner = bbox.corner().snapToGrid(mapGridSize);
23251
23252                 for (var x = origin.x; x <= corner.x; x += mapGridSize) {
23253                     for (var y = origin.y; y <= corner.y; y += mapGridSize) {
23254
23255                         var gridKey = x + '@' + y;
23256
23257                         res[gridKey] = res[gridKey] || [];
23258                         res[gridKey].push(bbox);
23259                     }
23260                 }
23261
23262                 return res;
23263
23264             }, {}).value();
23265
23266         // pathfinding
23267
23268         var newVertices = [];
23269
23270         var points = _.map(oldVertices, g.point);
23271
23272         var tailPoint = sourceBBox.center();
23273
23274         // find a route by concating all partial routes (routes need to go through the vertices)
23275         // startElement -> vertex[1] -> ... -> vertex[n] -> endElement
23276         for (var i = 0, len = points.length; i <= len; i++) {
23277
23278             var partialRoute = null;
23279
23280             var from = to || sourceBBox;
23281             var to = points[i];
23282
23283             if (!to) {
23284
23285                 to = targetBBox;
23286
23287                 // 'to' is not a vertex. If the target is a point (i.e. it's not an element), we
23288                 // might use dragging route instead of main routing method if that is enabled.
23289                 var endingAtPoint = !this.model.get('source').id || !this.model.get('target').id;
23290
23291                 if (endingAtPoint && _.isFunction(opt.draggingRoute)) {
23292                     // Make sure we passing points only (not rects).
23293                     var dragFrom = from instanceof g.rect ? from.center() : from;
23294                     partialRoute = opt.draggingRoute(dragFrom, to.origin(), opt);
23295                 }
23296             }
23297
23298             // if partial route has not been calculated yet use the main routing method to find one
23299             partialRoute = partialRoute || findRoute(from, to, map, opt);
23300
23301             var leadPoint = _.first(partialRoute);
23302
23303             if (leadPoint && leadPoint.equals(tailPoint)) {
23304
23305                 // remove the first point if the previous partial route had the same point as last
23306                 partialRoute.shift();
23307             }
23308
23309             tailPoint = _.last(partialRoute) || tailPoint;
23310
23311             newVertices = newVertices.concat(partialRoute);
23312         };
23313
23314         // we might have to reverse the result if we swapped source and target at the beginning
23315         return reverseRouting ? newVertices.reverse() : newVertices;
23316     };
23317
23318     // public function
23319     return function(vertices, opt, linkView) {
23320
23321         return router.call(linkView, vertices, _.extend({}, config, opt));
23322     };
23323
23324 })();
23325
23326 joint.routers.metro = (function() {
23327
23328     if (!_.isFunction(joint.routers.manhattan)) {
23329
23330         throw('Metro requires the manhattan router.');
23331     }
23332
23333     var config = {
23334
23335         // cost of a diagonal step (calculated if not defined).
23336         diagonalCost: null,
23337
23338         // an array of directions to find next points on the route
23339         directions: function() {
23340
23341             var step = this.step;
23342             var diagonalCost = this.diagonalCost || Math.ceil(Math.sqrt(step * step << 1));
23343
23344             return [
23345                 { offsetX: step  , offsetY: 0     , cost: step         },
23346                 { offsetX: step  , offsetY: step  , cost: diagonalCost },
23347                 { offsetX: 0     , offsetY: step  , cost: step         },
23348                 { offsetX: -step , offsetY: step  , cost: diagonalCost },
23349                 { offsetX: -step , offsetY: 0     , cost: step         },
23350                 { offsetX: -step , offsetY: -step , cost: diagonalCost },
23351                 { offsetX: 0     , offsetY: -step , cost: step         },
23352                 { offsetX: step  , offsetY: -step , cost: diagonalCost }
23353             ];
23354         },
23355
23356         // a simple route used in situations, when main routing method fails
23357         // (exceed loops, inaccessible).
23358         fallbackRoute: function(from, to, opts) {
23359
23360             // Find a route which breaks by 45 degrees ignoring all obstacles.
23361
23362             var theta = from.theta(to);
23363
23364             var a = { x: to.x, y: from.y };
23365             var b = { x: from.x, y: to.y };
23366
23367             if (theta % 180 > 90) {
23368                 var t = a;
23369                 a = b;
23370                 b = t;
23371             }
23372
23373             var p1 = (theta % 90) < 45 ? a : b;
23374
23375             var l1 = g.line(from, p1);
23376
23377             var alpha = 90 * Math.ceil(theta / 90);
23378
23379             var p2 = g.point.fromPolar(l1.squaredLength(), g.toRad(alpha + 135), p1);
23380
23381             var l2 = g.line(to, p2);
23382
23383             var point = l1.intersection(l2);
23384
23385             return point ? [point.round(), to] : [to];
23386         }
23387     };
23388
23389     // public function
23390     return function(vertices, opts, linkView) {
23391
23392         return joint.routers.manhattan(vertices, _.extend({}, config, opts), linkView);
23393     };
23394
23395 })();
23396
23397 joint.connectors.normal = function(sourcePoint, targetPoint, vertices) {
23398
23399     // Construct the `d` attribute of the `<path>` element.
23400     var d = ['M', sourcePoint.x, sourcePoint.y];
23401
23402     _.each(vertices, function(vertex) {
23403
23404         d.push(vertex.x, vertex.y);
23405     });
23406
23407     d.push(targetPoint.x, targetPoint.y);
23408
23409     return d.join(' ');
23410 };
23411
23412 joint.connectors.rounded = function(sourcePoint, targetPoint, vertices, opts) {
23413
23414     var offset = opts.radius || 10;
23415
23416     var c1, c2, d1, d2, prev, next;
23417
23418     // Construct the `d` attribute of the `<path>` element.
23419     var d = ['M', sourcePoint.x, sourcePoint.y];
23420
23421     _.each(vertices, function(vertex, index) {
23422
23423         // the closest vertices
23424         prev = vertices[index-1] || sourcePoint;
23425         next = vertices[index+1] || targetPoint;
23426
23427         // a half distance to the closest vertex
23428         d1 = d2 || g.point(vertex).distance(prev) / 2;
23429         d2 = g.point(vertex).distance(next) / 2;
23430
23431         // control points
23432         c1 = g.point(vertex).move(prev, -Math.min(offset, d1)).round();
23433         c2 = g.point(vertex).move(next, -Math.min(offset, d2)).round();
23434
23435         d.push(c1.x, c1.y, 'S', vertex.x, vertex.y, c2.x, c2.y, 'L');
23436     });
23437
23438     d.push(targetPoint.x, targetPoint.y);
23439
23440     return d.join(' ');
23441 };
23442
23443 joint.connectors.smooth = function(sourcePoint, targetPoint, vertices) {
23444
23445     var d;
23446
23447     if (vertices.length) {
23448
23449         d = g.bezier.curveThroughPoints([sourcePoint].concat(vertices).concat([targetPoint]));
23450
23451     } else {
23452         // if we have no vertices use a default cubic bezier curve, cubic bezier requires
23453         // two control points. The two control points are both defined with X as mid way
23454         // between the source and target points. SourceControlPoint Y is equal to sourcePoint Y
23455         // and targetControlPointY being equal to targetPointY. Handle situation were
23456         // sourcePointX is greater or less then targetPointX.
23457         var controlPointX = (sourcePoint.x < targetPoint.x) 
23458                 ? targetPoint.x - ((targetPoint.x - sourcePoint.x) / 2)
23459                 : sourcePoint.x - ((sourcePoint.x - targetPoint.x) / 2);
23460
23461         d = [
23462             'M', sourcePoint.x, sourcePoint.y,
23463             'C', controlPointX, sourcePoint.y, controlPointX, targetPoint.y,
23464             targetPoint.x, targetPoint.y
23465         ];
23466     }
23467
23468     return d.join(' ');
23469 };
23470
23471 if (typeof exports === 'object') {
23472
23473     var joint = {
23474         util: require('../src/core').util,
23475         shapes: {},
23476         dia: {
23477             Element: require('../src/joint.dia.element').Element,
23478             Link: require('../src/joint.dia.link').Link
23479         }
23480     };
23481 }
23482
23483
23484 joint.shapes.erd = {};
23485
23486 joint.shapes.erd.Entity = joint.dia.Element.extend({
23487
23488     markup: '<g class="rotatable"><g class="scalable"><polygon class="outer"/><polygon class="inner"/></g><text/></g>',
23489
23490     defaults: joint.util.deepSupplement({
23491
23492         type: 'erd.Entity',
23493         size: { width: 150, height: 60 },
23494         attrs: {
23495             '.outer': {
23496                 fill: '#2ECC71', stroke: '#27AE60', 'stroke-width': 2,
23497                 points: '100,0 100,60 0,60 0,0'
23498             },
23499             '.inner': {
23500                 fill: '#2ECC71', stroke: '#27AE60', 'stroke-width': 2,
23501                 points: '95,5 95,55 5,55 5,5',
23502                 display: 'none'
23503             },
23504             text: {
23505                 text: 'Entity',
23506                 'font-family': 'Arial', 'font-size': 14,
23507                 ref: '.outer', 'ref-x': .5, 'ref-y': .5,
23508                 'x-alignment': 'middle', 'y-alignment': 'middle'
23509             }
23510         }
23511
23512     }, joint.dia.Element.prototype.defaults)
23513 });
23514
23515 joint.shapes.erd.WeakEntity = joint.shapes.erd.Entity.extend({
23516
23517     defaults: joint.util.deepSupplement({
23518
23519         type: 'erd.WeakEntity',
23520
23521         attrs: {
23522             '.inner' : { display: 'auto' },
23523             text: { text: 'Weak Entity' }
23524         }
23525
23526     }, joint.shapes.erd.Entity.prototype.defaults)
23527 });
23528
23529 joint.shapes.erd.Relationship = joint.dia.Element.extend({
23530
23531     markup: '<g class="rotatable"><g class="scalable"><polygon class="outer"/><polygon class="inner"/></g><text/></g>',
23532     
23533     defaults: joint.util.deepSupplement({
23534
23535         type: 'erd.Relationship',
23536         size: { width: 80, height: 80 },
23537         attrs: {
23538             '.outer': {
23539                 fill: '#3498DB', stroke: '#2980B9', 'stroke-width': 2,
23540                 points: '40,0 80,40 40,80 0,40'
23541             },
23542             '.inner': {
23543                 fill: '#3498DB', stroke: '#2980B9', 'stroke-width': 2,
23544                 points: '40,5 75,40 40,75 5,40',
23545                 display: 'none'
23546             },
23547             text: {
23548                 text: 'Relationship',
23549                 'font-family': 'Arial', 'font-size': 12,
23550                 ref: '.', 'ref-x': .5, 'ref-y': .5,
23551                 'x-alignment': 'middle', 'y-alignment': 'middle'
23552             }
23553         }
23554
23555     }, joint.dia.Element.prototype.defaults)
23556 });
23557
23558 joint.shapes.erd.IdentifyingRelationship = joint.shapes.erd.Relationship.extend({
23559
23560     defaults: joint.util.deepSupplement({
23561
23562         type: 'erd.IdentifyingRelationship',
23563
23564         attrs: {
23565             '.inner': { display: 'auto' },
23566             text: { text: 'Identifying' }
23567         }
23568
23569     }, joint.shapes.erd.Relationship.prototype.defaults)
23570 });
23571
23572 joint.shapes.erd.Attribute = joint.dia.Element.extend({
23573
23574     markup: '<g class="rotatable"><g class="scalable"><ellipse class="outer"/><ellipse class="inner"/></g><text/></g>',
23575
23576     defaults: joint.util.deepSupplement({
23577
23578         type: 'erd.Attribute',
23579         size: { width: 100, height: 50 },
23580         attrs: {
23581             'ellipse': {
23582                 transform: 'translate(50, 25)'
23583             },
23584             '.outer': {
23585                 stroke: '#D35400', 'stroke-width': 2,
23586                 cx: 0, cy: 0, rx: 50, ry: 25,
23587                 fill: '#E67E22'
23588             },
23589             '.inner': {
23590                 stroke: '#D35400', 'stroke-width': 2,
23591                 cx: 0, cy: 0, rx: 45, ry: 20,
23592                 fill: 'transparent', display: 'none'
23593             },
23594             text: {
23595                  'font-family': 'Arial', 'font-size': 14,
23596                  ref: '.', 'ref-x': .5, 'ref-y': .5,
23597                  'x-alignment': 'middle', 'y-alignment': 'middle'
23598              }
23599          }
23600
23601      }, joint.dia.Element.prototype.defaults)
23602
23603  });
23604
23605  joint.shapes.erd.Multivalued = joint.shapes.erd.Attribute.extend({
23606
23607      defaults: joint.util.deepSupplement({
23608
23609          type: 'erd.Multivalued',
23610
23611          attrs: {
23612              '.inner': { display: 'block' },
23613              text: { text: 'multivalued' }
23614          }
23615      }, joint.shapes.erd.Attribute.prototype.defaults)
23616  });
23617
23618  joint.shapes.erd.Derived = joint.shapes.erd.Attribute.extend({
23619
23620      defaults: joint.util.deepSupplement({
23621
23622          type: 'erd.Derived',
23623
23624          attrs: {
23625              '.outer': { 'stroke-dasharray': '3,5' },
23626              text: { text: 'derived' }
23627          }
23628
23629      }, joint.shapes.erd.Attribute.prototype.defaults)
23630  });
23631
23632  joint.shapes.erd.Key = joint.shapes.erd.Attribute.extend({
23633
23634      defaults: joint.util.deepSupplement({
23635
23636          type: 'erd.Key',
23637
23638          attrs: {
23639              ellipse: { 'stroke-width': 4 },
23640              text: { text: 'key', 'font-weight': 'bold', 'text-decoration': 'underline' }
23641          }
23642      }, joint.shapes.erd.Attribute.prototype.defaults)
23643 });
23644
23645 joint.shapes.erd.Normal = joint.shapes.erd.Attribute.extend({
23646
23647     defaults: joint.util.deepSupplement({
23648
23649         type: 'erd.Normal',
23650
23651         attrs: { text: { text: 'Normal' }}
23652
23653     }, joint.shapes.erd.Attribute.prototype.defaults)
23654 });
23655
23656 joint.shapes.erd.ISA = joint.dia.Element.extend({
23657
23658     markup: '<g class="rotatable"><g class="scalable"><polygon/></g><text/></g>',
23659
23660     defaults: joint.util.deepSupplement({
23661
23662         type: 'erd.ISA',
23663         size: { width: 100, height: 50 },
23664         attrs: {
23665             polygon: {
23666                 points: '0,0 50,50 100,0',
23667                 fill: '#F1C40F', stroke: '#F39C12', 'stroke-width': 2
23668             },
23669             text: {
23670                 text: 'ISA',
23671                 ref: '.', 'ref-x': .5, 'ref-y': .3,
23672                 'x-alignment': 'middle', 'y-alignment': 'middle'
23673             }
23674         }
23675
23676     }, joint.dia.Element.prototype.defaults)
23677
23678 });
23679
23680 joint.shapes.erd.Line = joint.dia.Link.extend({
23681
23682     defaults: { type: "erd.Line" },
23683
23684     cardinality: function(value) {
23685         this.set('labels', [{ position: -20, attrs: { text: { dy: -8, text: value }}}]);
23686     }
23687 });
23688
23689 if (typeof exports === 'object') {
23690
23691     module.exports = joint.shapes.erd;
23692 }
23693
23694 if (typeof exports === 'object') {
23695
23696     var joint = {
23697         util: require('../src/core').util,
23698         shapes: {
23699             basic: require('./joint.shapes.basic')
23700         },
23701         dia: {
23702             Element: require('../src/joint.dia.element').Element,
23703             Link: require('../src/joint.dia.link').Link
23704         }
23705     };
23706 }
23707
23708 joint.shapes.fsa = {};
23709
23710 joint.shapes.fsa.State = joint.shapes.basic.Circle.extend({
23711     defaults: joint.util.deepSupplement({
23712         type: 'fsa.State',
23713         attrs: {
23714             circle: { 'stroke-width': 3 },
23715             text: { 'font-weight': 'bold' }
23716         }
23717     }, joint.shapes.basic.Circle.prototype.defaults)
23718 });
23719
23720 joint.shapes.fsa.StartState = joint.dia.Element.extend({
23721
23722     markup: '<g class="rotatable"><g class="scalable"><circle/></g></g>',
23723
23724     defaults: joint.util.deepSupplement({
23725
23726         type: 'fsa.StartState',
23727         size: { width: 20, height: 20 },
23728         attrs: {
23729             circle: {
23730                 transform: 'translate(10, 10)',
23731                 r: 10,
23732                 fill: 'black'
23733             }
23734         }
23735
23736     }, joint.dia.Element.prototype.defaults)
23737 });
23738
23739 joint.shapes.fsa.EndState = joint.dia.Element.extend({
23740
23741     markup: '<g class="rotatable"><g class="scalable"><circle class="outer"/><circle class="inner"/></g></g>',
23742
23743     defaults: joint.util.deepSupplement({
23744
23745         type: 'fsa.EndState',
23746         size: { width: 20, height: 20 },
23747         attrs: {
23748             '.outer': {
23749                 transform: 'translate(10, 10)',
23750                 r: 10,
23751                 fill: '#FFFFFF',
23752                 stroke: 'black'
23753             },
23754
23755             '.inner': {
23756                 transform: 'translate(10, 10)',
23757                 r: 6,
23758                 fill: '#000000'
23759             }
23760         }
23761
23762     }, joint.dia.Element.prototype.defaults)
23763 });
23764
23765 joint.shapes.fsa.Arrow = joint.dia.Link.extend({
23766
23767     defaults: joint.util.deepSupplement({
23768         type: 'fsa.Arrow',
23769         attrs: { '.marker-target': { d: 'M 10 0 L 0 5 L 10 10 z' }},
23770         smooth: true
23771     }, joint.dia.Link.prototype.defaults)
23772 });
23773
23774 if (typeof exports === 'object') {
23775
23776     module.exports = joint.shapes.fsa;
23777 }
23778
23779 if (typeof exports === 'object') {
23780
23781     var joint = {
23782         util: require('../src/core').util,
23783         shapes: {},
23784         dia: {
23785             Element: require('../src/joint.dia.element').Element,
23786             Link: require('../src/joint.dia.link').Link
23787         }
23788     };
23789 }
23790
23791 joint.shapes.org = {};
23792
23793 joint.shapes.org.Member = joint.dia.Element.extend({
23794
23795     markup: '<g class="rotatable"><g class="scalable"><rect class="card"/><image/></g><text class="rank"/><text class="name"/></g>',
23796
23797     defaults: joint.util.deepSupplement({
23798
23799         type: 'org.Member',
23800         size: { width: 180, height: 70 },
23801         attrs: {
23802
23803             rect: { width: 170, height: 60 },
23804
23805             '.card': {
23806                 fill: '#FFFFFF', stroke: '#000000', 'stroke-width': 2,
23807                 'pointer-events': 'visiblePainted', rx: 10, ry: 10
23808             },
23809
23810             image: {
23811                 width: 48, height: 48,
23812                 ref: '.card', 'ref-x': 10, 'ref-y': 5
23813             },
23814             
23815             '.rank': {
23816                 'text-decoration': 'underline',
23817                 ref: '.card', 'ref-x': 0.9, 'ref-y': 0.2,
23818                 'font-family': 'Courier New', 'font-size': 14,
23819                 'text-anchor': 'end'
23820             },
23821
23822             '.name': {
23823                 'font-weight': 'bold',
23824                 ref: '.card', 'ref-x': 0.9, 'ref-y': 0.6,
23825                 'font-family': 'Courier New', 'font-size': 14,
23826                 'text-anchor': 'end'
23827             }
23828         }
23829     }, joint.dia.Element.prototype.defaults)
23830 });
23831
23832 joint.shapes.org.Arrow = joint.dia.Link.extend({
23833
23834     defaults: {
23835         type: 'org.Arrow',
23836         source: { selector: '.card' }, target: { selector: '.card' },
23837         attrs: { '.connection': { stroke: '#585858', 'stroke-width': 3 }},
23838         z: -1
23839     }
23840 });
23841
23842
23843 if (typeof exports === 'object') {
23844
23845     module.exports = joint.shapes.org;
23846 }
23847
23848 if (typeof exports === 'object') {
23849
23850     var joint = {
23851         util: require('../src/core').util,
23852         shapes: {
23853             basic: require('./joint.shapes.basic')
23854         },
23855         dia: {}
23856     };
23857 }
23858
23859 joint.shapes.chess = {};
23860
23861 joint.shapes.chess.KingWhite = joint.shapes.basic.Generic.extend({
23862
23863     markup: '<g class="rotatable"><g class="scalable"><g style="fill:none; fill-opacity:1; fill-rule:evenodd; stroke:#000000; stroke-width:1.5; stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4; stroke-dasharray:none; stroke-opacity:1;"><path      d="M 22.5,11.63 L 22.5,6"      style="fill:none; stroke:#000000; stroke-linejoin:miter;" />    <path      d="M 20,8 L 25,8"      style="fill:none; stroke:#000000; stroke-linejoin:miter;" />    <path      d="M 22.5,25 C 22.5,25 27,17.5 25.5,14.5 C 25.5,14.5 24.5,12 22.5,12 C 20.5,12 19.5,14.5 19.5,14.5 C 18,17.5 22.5,25 22.5,25"      style="fill:#ffffff; stroke:#000000; stroke-linecap:butt; stroke-linejoin:miter;" />    <path      d="M 11.5,37 C 17,40.5 27,40.5 32.5,37 L 32.5,30 C 32.5,30 41.5,25.5 38.5,19.5 C 34.5,13 25,16 22.5,23.5 L 22.5,27 L 22.5,23.5 C 19,16 9.5,13 6.5,19.5 C 3.5,25.5 11.5,29.5 11.5,29.5 L 11.5,37 z "      style="fill:#ffffff; stroke:#000000;" />    <path      d="M 11.5,30 C 17,27 27,27 32.5,30"      style="fill:none; stroke:#000000;" />    <path      d="M 11.5,33.5 C 17,30.5 27,30.5 32.5,33.5"      style="fill:none; stroke:#000000;" />    <path      d="M 11.5,37 C 17,34 27,34 32.5,37"      style="fill:none; stroke:#000000;" />  </g></g></g>',
23864
23865     defaults: joint.util.deepSupplement({
23866
23867         type: 'chess.KingWhite',
23868         size: { width: 42, height: 38 }
23869
23870     }, joint.shapes.basic.Generic.prototype.defaults)
23871 });
23872
23873 joint.shapes.chess.KingBlack = joint.shapes.basic.Generic.extend({
23874
23875     markup: '<g class="rotatable"><g class="scalable"><g style="fill:none; fill-opacity:1; fill-rule:evenodd; stroke:#000000; stroke-width:1.5; stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4; stroke-dasharray:none; stroke-opacity:1;">    <path       d="M 22.5,11.63 L 22.5,6"       style="fill:none; stroke:#000000; stroke-linejoin:miter;"       id="path6570" />    <path       d="M 22.5,25 C 22.5,25 27,17.5 25.5,14.5 C 25.5,14.5 24.5,12 22.5,12 C 20.5,12 19.5,14.5 19.5,14.5 C 18,17.5 22.5,25 22.5,25"       style="fill:#000000;fill-opacity:1; stroke-linecap:butt; stroke-linejoin:miter;" />    <path       d="M 11.5,37 C 17,40.5 27,40.5 32.5,37 L 32.5,30 C 32.5,30 41.5,25.5 38.5,19.5 C 34.5,13 25,16 22.5,23.5 L 22.5,27 L 22.5,23.5 C 19,16 9.5,13 6.5,19.5 C 3.5,25.5 11.5,29.5 11.5,29.5 L 11.5,37 z "       style="fill:#000000; stroke:#000000;" />    <path       d="M 20,8 L 25,8"       style="fill:none; stroke:#000000; stroke-linejoin:miter;" />    <path       d="M 32,29.5 C 32,29.5 40.5,25.5 38.03,19.85 C 34.15,14 25,18 22.5,24.5 L 22.51,26.6 L 22.5,24.5 C 20,18 9.906,14 6.997,19.85 C 4.5,25.5 11.85,28.85 11.85,28.85"       style="fill:none; stroke:#ffffff;" />    <path       d="M 11.5,30 C 17,27 27,27 32.5,30 M 11.5,33.5 C 17,30.5 27,30.5 32.5,33.5 M 11.5,37 C 17,34 27,34 32.5,37"       style="fill:none; stroke:#ffffff;" />  </g></g></g>',
23876
23877     defaults: joint.util.deepSupplement({
23878
23879         type: 'chess.KingBlack',
23880         size: { width: 42, height: 38 }
23881         
23882     }, joint.shapes.basic.Generic.prototype.defaults)
23883 });
23884
23885 joint.shapes.chess.QueenWhite = joint.shapes.basic.Generic.extend({
23886
23887     markup: '<g class="rotatable"><g class="scalable"><g style="opacity:1; fill:#ffffff; fill-opacity:1; fill-rule:evenodd; stroke:#000000; stroke-width:1.5; stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4; stroke-dasharray:none; stroke-opacity:1;">    <path      d="M 9 13 A 2 2 0 1 1  5,13 A 2 2 0 1 1  9 13 z"      transform="translate(-1,-1)" />    <path      d="M 9 13 A 2 2 0 1 1  5,13 A 2 2 0 1 1  9 13 z"      transform="translate(15.5,-5.5)" />    <path      d="M 9 13 A 2 2 0 1 1  5,13 A 2 2 0 1 1  9 13 z"      transform="translate(32,-1)" />    <path      d="M 9 13 A 2 2 0 1 1  5,13 A 2 2 0 1 1  9 13 z"      transform="translate(7,-4.5)" />    <path      d="M 9 13 A 2 2 0 1 1  5,13 A 2 2 0 1 1  9 13 z"      transform="translate(24,-4)" />    <path      d="M 9,26 C 17.5,24.5 30,24.5 36,26 L 38,14 L 31,25 L 31,11 L 25.5,24.5 L 22.5,9.5 L 19.5,24.5 L 14,10.5 L 14,25 L 7,14 L 9,26 z "      style="stroke-linecap:butt;" />    <path      d="M 9,26 C 9,28 10.5,28 11.5,30 C 12.5,31.5 12.5,31 12,33.5 C 10.5,34.5 10.5,36 10.5,36 C 9,37.5 11,38.5 11,38.5 C 17.5,39.5 27.5,39.5 34,38.5 C 34,38.5 35.5,37.5 34,36 C 34,36 34.5,34.5 33,33.5 C 32.5,31 32.5,31.5 33.5,30 C 34.5,28 36,28 36,26 C 27.5,24.5 17.5,24.5 9,26 z "      style="stroke-linecap:butt;" />    <path      d="M 11.5,30 C 15,29 30,29 33.5,30"      style="fill:none;" />    <path      d="M 12,33.5 C 18,32.5 27,32.5 33,33.5"      style="fill:none;" />  </g></g></g>',
23888
23889     defaults: joint.util.deepSupplement({
23890
23891         type: 'chess.QueenWhite',
23892         size: { width: 42, height: 38 }
23893
23894     }, joint.shapes.basic.Generic.prototype.defaults)
23895 });
23896
23897 joint.shapes.chess.QueenBlack = joint.shapes.basic.Generic.extend({
23898
23899     markup: '<g class="rotatable"><g class="scalable"><g style="opacity:1; fill:#000000; fill-opacity:1; fill-rule:evenodd; stroke:#000000; stroke-width:1.5; stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4; stroke-dasharray:none; stroke-opacity:1;">    <g style="fill:#000000; stroke:none;">      <circle cx="6"    cy="12" r="2.75" />      <circle cx="14"   cy="9"  r="2.75" />      <circle cx="22.5" cy="8"  r="2.75" />      <circle cx="31"   cy="9"  r="2.75" />      <circle cx="39"   cy="12" r="2.75" />    </g>    <path       d="M 9,26 C 17.5,24.5 30,24.5 36,26 L 38.5,13.5 L 31,25 L 30.7,10.9 L 25.5,24.5 L 22.5,10 L 19.5,24.5 L 14.3,10.9 L 14,25 L 6.5,13.5 L 9,26 z"       style="stroke-linecap:butt; stroke:#000000;" />    <path       d="M 9,26 C 9,28 10.5,28 11.5,30 C 12.5,31.5 12.5,31 12,33.5 C 10.5,34.5 10.5,36 10.5,36 C 9,37.5 11,38.5 11,38.5 C 17.5,39.5 27.5,39.5 34,38.5 C 34,38.5 35.5,37.5 34,36 C 34,36 34.5,34.5 33,33.5 C 32.5,31 32.5,31.5 33.5,30 C 34.5,28 36,28 36,26 C 27.5,24.5 17.5,24.5 9,26 z"       style="stroke-linecap:butt;" />    <path       d="M 11,38.5 A 35,35 1 0 0 34,38.5"       style="fill:none; stroke:#000000; stroke-linecap:butt;" />    <path       d="M 11,29 A 35,35 1 0 1 34,29"       style="fill:none; stroke:#ffffff;" />    <path       d="M 12.5,31.5 L 32.5,31.5"       style="fill:none; stroke:#ffffff;" />    <path       d="M 11.5,34.5 A 35,35 1 0 0 33.5,34.5"       style="fill:none; stroke:#ffffff;" />    <path       d="M 10.5,37.5 A 35,35 1 0 0 34.5,37.5"       style="fill:none; stroke:#ffffff;" />  </g></g></g>',
23900
23901     defaults: joint.util.deepSupplement({
23902
23903         type: 'chess.QueenBlack',
23904         size: { width: 42, height: 38 }
23905
23906     }, joint.shapes.basic.Generic.prototype.defaults)
23907 });
23908
23909 joint.shapes.chess.RookWhite = joint.shapes.basic.Generic.extend({
23910
23911     markup: '<g class="rotatable"><g class="scalable"><g style="opacity:1; fill:#ffffff; fill-opacity:1; fill-rule:evenodd; stroke:#000000; stroke-width:1.5; stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4; stroke-dasharray:none; stroke-opacity:1;">    <path      d="M 9,39 L 36,39 L 36,36 L 9,36 L 9,39 z "      style="stroke-linecap:butt;" />    <path      d="M 12,36 L 12,32 L 33,32 L 33,36 L 12,36 z "      style="stroke-linecap:butt;" />    <path      d="M 11,14 L 11,9 L 15,9 L 15,11 L 20,11 L 20,9 L 25,9 L 25,11 L 30,11 L 30,9 L 34,9 L 34,14"      style="stroke-linecap:butt;" />    <path      d="M 34,14 L 31,17 L 14,17 L 11,14" />    <path      d="M 31,17 L 31,29.5 L 14,29.5 L 14,17"      style="stroke-linecap:butt; stroke-linejoin:miter;" />    <path      d="M 31,29.5 L 32.5,32 L 12.5,32 L 14,29.5" />    <path      d="M 11,14 L 34,14"      style="fill:none; stroke:#000000; stroke-linejoin:miter;" />  </g></g></g>',
23912
23913     defaults: joint.util.deepSupplement({
23914
23915         type: 'chess.RookWhite',
23916         size: { width: 32, height: 34 }
23917
23918     }, joint.shapes.basic.Generic.prototype.defaults)
23919 });
23920
23921 joint.shapes.chess.RookBlack = joint.shapes.basic.Generic.extend({
23922
23923     markup: '<g class="rotatable"><g class="scalable"><g style="opacity:1; fill:#000000; fill-opacity:1; fill-rule:evenodd; stroke:#000000; stroke-width:1.5; stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4; stroke-dasharray:none; stroke-opacity:1;">    <path      d="M 9,39 L 36,39 L 36,36 L 9,36 L 9,39 z "      style="stroke-linecap:butt;" />    <path      d="M 12.5,32 L 14,29.5 L 31,29.5 L 32.5,32 L 12.5,32 z "      style="stroke-linecap:butt;" />    <path      d="M 12,36 L 12,32 L 33,32 L 33,36 L 12,36 z "      style="stroke-linecap:butt;" />    <path      d="M 14,29.5 L 14,16.5 L 31,16.5 L 31,29.5 L 14,29.5 z "      style="stroke-linecap:butt;stroke-linejoin:miter;" />    <path      d="M 14,16.5 L 11,14 L 34,14 L 31,16.5 L 14,16.5 z "      style="stroke-linecap:butt;" />    <path      d="M 11,14 L 11,9 L 15,9 L 15,11 L 20,11 L 20,9 L 25,9 L 25,11 L 30,11 L 30,9 L 34,9 L 34,14 L 11,14 z "      style="stroke-linecap:butt;" />    <path      d="M 12,35.5 L 33,35.5 L 33,35.5"      style="fill:none; stroke:#ffffff; stroke-width:1; stroke-linejoin:miter;" />    <path      d="M 13,31.5 L 32,31.5"      style="fill:none; stroke:#ffffff; stroke-width:1; stroke-linejoin:miter;" />    <path      d="M 14,29.5 L 31,29.5"      style="fill:none; stroke:#ffffff; stroke-width:1; stroke-linejoin:miter;" />    <path      d="M 14,16.5 L 31,16.5"      style="fill:none; stroke:#ffffff; stroke-width:1; stroke-linejoin:miter;" />    <path      d="M 11,14 L 34,14"      style="fill:none; stroke:#ffffff; stroke-width:1; stroke-linejoin:miter;" />  </g></g></g>',
23924
23925     defaults: joint.util.deepSupplement({
23926
23927         type: 'chess.RookBlack',
23928         size: { width: 32, height: 34 }
23929         
23930     }, joint.shapes.basic.Generic.prototype.defaults)
23931 });
23932
23933 joint.shapes.chess.BishopWhite = joint.shapes.basic.Generic.extend({
23934
23935     markup: '<g class="rotatable"><g class="scalable"><g style="opacity:1; fill:none; fill-rule:evenodd; fill-opacity:1; stroke:#000000; stroke-width:1.5; stroke-linecap:round; stroke-linejoin:round; stroke-miterlimit:4; stroke-dasharray:none; stroke-opacity:1;">    <g style="fill:#ffffff; stroke:#000000; stroke-linecap:butt;">       <path        d="M 9,36 C 12.39,35.03 19.11,36.43 22.5,34 C 25.89,36.43 32.61,35.03 36,36 C 36,36 37.65,36.54 39,38 C 38.32,38.97 37.35,38.99 36,38.5 C 32.61,37.53 25.89,38.96 22.5,37.5 C 19.11,38.96 12.39,37.53 9,38.5 C 7.646,38.99 6.677,38.97 6,38 C 7.354,36.06 9,36 9,36 z" />      <path        d="M 15,32 C 17.5,34.5 27.5,34.5 30,32 C 30.5,30.5 30,30 30,30 C 30,27.5 27.5,26 27.5,26 C 33,24.5 33.5,14.5 22.5,10.5 C 11.5,14.5 12,24.5 17.5,26 C 17.5,26 15,27.5 15,30 C 15,30 14.5,30.5 15,32 z" />      <path        d="M 25 8 A 2.5 2.5 0 1 1  20,8 A 2.5 2.5 0 1 1  25 8 z" />    </g>    <path      d="M 17.5,26 L 27.5,26 M 15,30 L 30,30 M 22.5,15.5 L 22.5,20.5 M 20,18 L 25,18"      style="fill:none; stroke:#000000; stroke-linejoin:miter;" />  </g></g></g>',
23936
23937     defaults: joint.util.deepSupplement({
23938
23939         type: 'chess.BishopWhite',
23940         size: { width: 38, height: 38 }
23941
23942     }, joint.shapes.basic.Generic.prototype.defaults)
23943 });
23944
23945 joint.shapes.chess.BishopBlack = joint.shapes.basic.Generic.extend({
23946
23947     markup: '<g class="rotatable"><g class="scalable"><g style="opacity:1; fill:none; fill-rule:evenodd; fill-opacity:1; stroke:#000000; stroke-width:1.5; stroke-linecap:round; stroke-linejoin:round; stroke-miterlimit:4; stroke-dasharray:none; stroke-opacity:1;">    <g style="fill:#000000; stroke:#000000; stroke-linecap:butt;">       <path        d="M 9,36 C 12.39,35.03 19.11,36.43 22.5,34 C 25.89,36.43 32.61,35.03 36,36 C 36,36 37.65,36.54 39,38 C 38.32,38.97 37.35,38.99 36,38.5 C 32.61,37.53 25.89,38.96 22.5,37.5 C 19.11,38.96 12.39,37.53 9,38.5 C 7.646,38.99 6.677,38.97 6,38 C 7.354,36.06 9,36 9,36 z" />      <path        d="M 15,32 C 17.5,34.5 27.5,34.5 30,32 C 30.5,30.5 30,30 30,30 C 30,27.5 27.5,26 27.5,26 C 33,24.5 33.5,14.5 22.5,10.5 C 11.5,14.5 12,24.5 17.5,26 C 17.5,26 15,27.5 15,30 C 15,30 14.5,30.5 15,32 z" />      <path        d="M 25 8 A 2.5 2.5 0 1 1  20,8 A 2.5 2.5 0 1 1  25 8 z" />    </g>    <path       d="M 17.5,26 L 27.5,26 M 15,30 L 30,30 M 22.5,15.5 L 22.5,20.5 M 20,18 L 25,18"       style="fill:none; stroke:#ffffff; stroke-linejoin:miter;" />  </g></g></g>',
23948
23949     defaults: joint.util.deepSupplement({
23950
23951         type: 'chess.BishopBlack',
23952         size: { width: 38, height: 38 }
23953
23954     }, joint.shapes.basic.Generic.prototype.defaults)
23955 });
23956
23957 joint.shapes.chess.KnightWhite = joint.shapes.basic.Generic.extend({
23958
23959     markup: '<g class="rotatable"><g class="scalable"><g style="opacity:1; fill:none; fill-opacity:1; fill-rule:evenodd; stroke:#000000; stroke-width:1.5; stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4; stroke-dasharray:none; stroke-opacity:1;">    <path      d="M 22,10 C 32.5,11 38.5,18 38,39 L 15,39 C 15,30 25,32.5 23,18"      style="fill:#ffffff; stroke:#000000;" />    <path      d="M 24,18 C 24.38,20.91 18.45,25.37 16,27 C 13,29 13.18,31.34 11,31 C 9.958,30.06 12.41,27.96 11,28 C 10,28 11.19,29.23 10,30 C 9,30 5.997,31 6,26 C 6,24 12,14 12,14 C 12,14 13.89,12.1 14,10.5 C 13.27,9.506 13.5,8.5 13.5,7.5 C 14.5,6.5 16.5,10 16.5,10 L 18.5,10 C 18.5,10 19.28,8.008 21,7 C 22,7 22,10 22,10"      style="fill:#ffffff; stroke:#000000;" />    <path      d="M 9.5 25.5 A 0.5 0.5 0 1 1 8.5,25.5 A 0.5 0.5 0 1 1 9.5 25.5 z"      style="fill:#000000; stroke:#000000;" />    <path      d="M 15 15.5 A 0.5 1.5 0 1 1  14,15.5 A 0.5 1.5 0 1 1  15 15.5 z"      transform="matrix(0.866,0.5,-0.5,0.866,9.693,-5.173)"      style="fill:#000000; stroke:#000000;" />  </g></g></g>',
23960
23961     defaults: joint.util.deepSupplement({
23962
23963         type: 'chess.KnightWhite',
23964         size: { width: 38, height: 37 }
23965
23966     }, joint.shapes.basic.Generic.prototype.defaults)
23967 });
23968
23969 joint.shapes.chess.KnightBlack = joint.shapes.basic.Generic.extend({
23970
23971     markup: '<g class="rotatable"><g class="scalable"><g style="opacity:1; fill:none; fill-opacity:1; fill-rule:evenodd; stroke:#000000; stroke-width:1.5; stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4; stroke-dasharray:none; stroke-opacity:1;">    <path      d="M 22,10 C 32.5,11 38.5,18 38,39 L 15,39 C 15,30 25,32.5 23,18"      style="fill:#000000; stroke:#000000;" />    <path      d="M 24,18 C 24.38,20.91 18.45,25.37 16,27 C 13,29 13.18,31.34 11,31 C 9.958,30.06 12.41,27.96 11,28 C 10,28 11.19,29.23 10,30 C 9,30 5.997,31 6,26 C 6,24 12,14 12,14 C 12,14 13.89,12.1 14,10.5 C 13.27,9.506 13.5,8.5 13.5,7.5 C 14.5,6.5 16.5,10 16.5,10 L 18.5,10 C 18.5,10 19.28,8.008 21,7 C 22,7 22,10 22,10"      style="fill:#000000; stroke:#000000;" />    <path      d="M 9.5 25.5 A 0.5 0.5 0 1 1 8.5,25.5 A 0.5 0.5 0 1 1 9.5 25.5 z"      style="fill:#ffffff; stroke:#ffffff;" />    <path      d="M 15 15.5 A 0.5 1.5 0 1 1  14,15.5 A 0.5 1.5 0 1 1  15 15.5 z"      transform="matrix(0.866,0.5,-0.5,0.866,9.693,-5.173)"      style="fill:#ffffff; stroke:#ffffff;" />    <path      d="M 24.55,10.4 L 24.1,11.85 L 24.6,12 C 27.75,13 30.25,14.49 32.5,18.75 C 34.75,23.01 35.75,29.06 35.25,39 L 35.2,39.5 L 37.45,39.5 L 37.5,39 C 38,28.94 36.62,22.15 34.25,17.66 C 31.88,13.17 28.46,11.02 25.06,10.5 L 24.55,10.4 z "      style="fill:#ffffff; stroke:none;" />  </g></g></g>',
23972
23973     defaults: joint.util.deepSupplement({
23974
23975         type: 'chess.KnightBlack',
23976         size: { width: 38, height: 37 }
23977
23978     }, joint.shapes.basic.Generic.prototype.defaults)
23979 });
23980
23981 joint.shapes.chess.PawnWhite = joint.shapes.basic.Generic.extend({
23982
23983     markup: '<g class="rotatable"><g class="scalable"><path d="M 22,9 C 19.79,9 18,10.79 18,13 C 18,13.89 18.29,14.71 18.78,15.38 C 16.83,16.5 15.5,18.59 15.5,21 C 15.5,23.03 16.44,24.84 17.91,26.03 C 14.91,27.09 10.5,31.58 10.5,39.5 L 33.5,39.5 C 33.5,31.58 29.09,27.09 26.09,26.03 C 27.56,24.84 28.5,23.03 28.5,21 C 28.5,18.59 27.17,16.5 25.22,15.38 C 25.71,14.71 26,13.89 26,13 C 26,10.79 24.21,9 22,9 z "  style="opacity:1; fill:#ffffff; fill-opacity:1; fill-rule:nonzero; stroke:#000000; stroke-width:1.5; stroke-linecap:round; stroke-linejoin:miter; stroke-miterlimit:4; stroke-dasharray:none; stroke-opacity:1;" /></g></g>',
23984
23985     defaults: joint.util.deepSupplement({
23986
23987         type: 'chess.PawnWhite',
23988         size: { width: 28, height: 33 }
23989
23990     }, joint.shapes.basic.Generic.prototype.defaults)
23991 });
23992
23993 joint.shapes.chess.PawnBlack = joint.shapes.basic.Generic.extend({
23994
23995     markup: '<g class="rotatable"><g class="scalable"><path d="M 22,9 C 19.79,9 18,10.79 18,13 C 18,13.89 18.29,14.71 18.78,15.38 C 16.83,16.5 15.5,18.59 15.5,21 C 15.5,23.03 16.44,24.84 17.91,26.03 C 14.91,27.09 10.5,31.58 10.5,39.5 L 33.5,39.5 C 33.5,31.58 29.09,27.09 26.09,26.03 C 27.56,24.84 28.5,23.03 28.5,21 C 28.5,18.59 27.17,16.5 25.22,15.38 C 25.71,14.71 26,13.89 26,13 C 26,10.79 24.21,9 22,9 z "  style="opacity:1; fill:#000000; fill-opacity:1; fill-rule:nonzero; stroke:#000000; stroke-width:1.5; stroke-linecap:round; stroke-linejoin:miter; stroke-miterlimit:4; stroke-dasharray:none; stroke-opacity:1;" /></g></g>',
23996
23997     defaults: joint.util.deepSupplement({
23998
23999         type: 'chess.PawnBlack',
24000         size: { width: 28, height: 33 }
24001
24002     }, joint.shapes.basic.Generic.prototype.defaults)
24003 });
24004
24005 if (typeof exports === 'object') {
24006
24007     module.exports = joint.shapes.chess;
24008 }
24009
24010 if (typeof exports === 'object') {
24011
24012     var joint = {
24013         util: require('../src/core').util,
24014         shapes: {
24015             basic: require('./joint.shapes.basic')
24016         },
24017         dia: {
24018             ElementView: require('../src/joint.dia.element').ElementView,
24019             Link: require('../src/joint.dia.link').Link
24020         }
24021     };
24022 }
24023
24024 joint.shapes.pn = {};
24025
24026 joint.shapes.pn.Place = joint.shapes.basic.Generic.extend({
24027
24028     markup: '<g class="rotatable"><g class="scalable"><circle class="root"/><g class="tokens" /></g><text class="label"/></g>',
24029
24030     defaults: joint.util.deepSupplement({
24031
24032         type: 'pn.Place',
24033         size: { width: 50, height: 50 },
24034         attrs: {
24035             '.root': {
24036                 r: 25,
24037                 fill: 'white',
24038                 stroke: 'black',
24039                 transform: 'translate(25, 25)'
24040             },
24041             '.label': {
24042                 'text-anchor': 'middle',
24043                 'ref-x': .5,
24044                 'ref-y': -20,
24045                 ref: '.root',
24046                 fill: 'black',
24047                 'font-size': 12
24048             },
24049             '.tokens > circle': {
24050                 fill: 'black',
24051                 r: 5
24052             },
24053             '.tokens.one > circle': { transform: 'translate(25, 25)' },
24054             
24055             '.tokens.two > circle:nth-child(1)': { transform: 'translate(19, 25)' },
24056             '.tokens.two > circle:nth-child(2)': { transform: 'translate(31, 25)' },
24057             
24058             '.tokens.three > circle:nth-child(1)': { transform: 'translate(18, 29)' },
24059             '.tokens.three > circle:nth-child(2)': { transform: 'translate(25, 19)' },
24060             '.tokens.three > circle:nth-child(3)': { transform: 'translate(32, 29)' },
24061
24062             '.tokens.alot > text': {
24063                 transform: 'translate(25, 18)',
24064                 'text-anchor': 'middle',
24065                 fill: 'black'
24066             }
24067         }
24068
24069     }, joint.shapes.basic.Generic.prototype.defaults)
24070 });
24071
24072
24073 joint.shapes.pn.PlaceView = joint.dia.ElementView.extend({
24074
24075     initialize: function() {
24076
24077         joint.dia.ElementView.prototype.initialize.apply(this, arguments);
24078
24079         this.model.on('change:tokens', function() {
24080
24081             this.renderTokens();
24082             this.update();
24083
24084         }, this);
24085     },
24086
24087     render: function() {
24088
24089         joint.dia.ElementView.prototype.render.apply(this, arguments);
24090
24091         this.renderTokens();
24092         this.update();
24093     },
24094
24095     renderTokens: function() {
24096
24097         var $tokens = this.$('.tokens').empty();
24098         $tokens[0].className.baseVal = 'tokens';
24099
24100         var tokens = this.model.get('tokens');
24101
24102         if (!tokens) return;
24103
24104         switch (tokens) {
24105
24106           case 1:
24107             $tokens[0].className.baseVal += ' one';
24108             $tokens.append(V('<circle/>').node);
24109             break;
24110             
24111           case 2:
24112             $tokens[0].className.baseVal += ' two';
24113             $tokens.append(V('<circle/>').node, V('<circle/>').node);
24114             break;
24115
24116           case 3:
24117             $tokens[0].className.baseVal += ' three';
24118             $tokens.append(V('<circle/>').node, V('<circle/>').node, V('<circle/>').node);
24119             break;
24120
24121           default:
24122             $tokens[0].className.baseVal += ' alot';
24123             $tokens.append(V('<text/>').text(tokens + '' ).node);
24124             break;
24125         }
24126     }
24127 });
24128
24129
24130 joint.shapes.pn.Transition = joint.shapes.basic.Generic.extend({
24131
24132     markup: '<g class="rotatable"><g class="scalable"><rect class="root"/></g></g><text class="label"/>',
24133
24134     defaults: joint.util.deepSupplement({
24135
24136         type: 'pn.Transition',
24137         size: { width: 12, height: 50 },
24138         attrs: {
24139             'rect': {
24140                 width: 12,
24141                 height: 50,
24142                 fill: 'black',
24143                 stroke: 'black'
24144             },
24145             '.label': {
24146                 'text-anchor': 'middle',
24147                 'ref-x': .5,
24148                 'ref-y': -20,
24149                 ref: 'rect',
24150                 fill: 'black',
24151                 'font-size': 12
24152             }
24153         }
24154
24155     }, joint.shapes.basic.Generic.prototype.defaults)
24156 });
24157
24158 joint.shapes.pn.Link = joint.dia.Link.extend({
24159
24160     defaults: joint.util.deepSupplement({
24161
24162         attrs: { '.marker-target': { d: 'M 10 0 L 0 5 L 10 10 z' }}
24163         
24164     }, joint.dia.Link.prototype.defaults)
24165 });
24166
24167 if (typeof exports === 'object') {
24168
24169     module.exports = joint.shapes.pn;
24170 }
24171
24172 if (typeof exports === 'object') {
24173
24174     var joint = {
24175         util: require('../src/core').util,
24176         shapes: {
24177             basic: require('./joint.shapes.basic')
24178         },
24179         dia: {
24180             ElementView: require('../src/joint.dia.element').ElementView,
24181             Link: require('../src/joint.dia.link').Link
24182         }
24183     };
24184     var _ = require('lodash');
24185 }
24186
24187 joint.shapes.devs = {};
24188
24189 joint.shapes.devs.Model = joint.shapes.basic.Generic.extend(_.extend({}, joint.shapes.basic.PortsModelInterface, {
24190
24191     markup: '<g class="rotatable"><g class="scalable"><rect/></g><text class="label"/><g class="inPorts"/><g class="outPorts"/></g>',
24192     portMarkup: '<g class="port<%= id %>"><circle/><text/></g>',
24193
24194     defaults: joint.util.deepSupplement({
24195
24196         type: 'devs.Model',
24197         size: { width: 1, height: 1 },
24198         
24199         inPorts: [],
24200         outPorts: [],
24201
24202         attrs: {
24203             '.': { magnet: false },
24204             rect: {
24205                 width: 150, height: 250,
24206                 stroke: 'black'
24207             },
24208             circle: {
24209                 r: 10,
24210                 magnet: true,
24211                 stroke: 'black'
24212             },
24213             text: {
24214                 fill: 'black',
24215                 'pointer-events': 'none'
24216             },
24217             '.label': { text: 'Model', 'ref-x': .3, 'ref-y': .2 },
24218             '.inPorts text': { x:-15, dy: 4, 'text-anchor': 'end' },
24219             '.outPorts text':{ x: 15, dy: 4 }
24220         }
24221
24222     }, joint.shapes.basic.Generic.prototype.defaults),
24223
24224     getPortAttrs: function(portName, index, total, selector, type) {
24225
24226         var attrs = {};
24227         
24228         var portClass = 'port' + index;
24229         var portSelector = selector + '>.' + portClass;
24230         var portTextSelector = portSelector + '>text';
24231         var portCircleSelector = portSelector + '>circle';
24232
24233         attrs[portTextSelector] = { text: portName };
24234         attrs[portCircleSelector] = { port: { id: portName || _.uniqueId(type) , type: type } };
24235         attrs[portSelector] = { ref: 'rect', 'ref-y': (index + 0.5) * (1 / total) };
24236         
24237         if (selector === '.outPorts') { attrs[portSelector]['ref-dx'] = 0; }
24238
24239         return attrs;
24240     }
24241 }));
24242
24243
24244 joint.shapes.devs.Atomic = joint.shapes.devs.Model.extend({
24245
24246     defaults: joint.util.deepSupplement({
24247
24248         type: 'devs.Atomic',
24249         size: { width: 80, height: 80 },
24250         attrs: {
24251             rect: { fill: 'salmon' },
24252             '.label': { text: 'Atomic' },
24253             '.inPorts circle': { fill: 'PaleGreen' },
24254             '.outPorts circle': { fill: 'Tomato' }
24255         }
24256
24257     }, joint.shapes.devs.Model.prototype.defaults)
24258
24259 });
24260
24261 joint.shapes.devs.Coupled = joint.shapes.devs.Model.extend({
24262
24263     defaults: joint.util.deepSupplement({
24264
24265         type: 'devs.Coupled',
24266         size: { width: 200, height: 300 },
24267         attrs: {
24268             rect: { fill: 'seaGreen' },
24269             '.label': { text: 'Coupled' },
24270             '.inPorts circle': { fill: 'PaleGreen' },
24271             '.outPorts circle': { fill: 'Tomato' }
24272         }
24273
24274     }, joint.shapes.devs.Model.prototype.defaults)
24275 });
24276
24277 joint.shapes.devs.Link = joint.dia.Link.extend({
24278
24279     defaults: {
24280         type: 'devs.Link',
24281         attrs: { '.connection' : { 'stroke-width' :  2 }}
24282     }
24283 });
24284
24285 joint.shapes.devs.ModelView = joint.dia.ElementView.extend(joint.shapes.basic.PortsViewInterface);
24286 joint.shapes.devs.AtomicView = joint.shapes.devs.ModelView;
24287 joint.shapes.devs.CoupledView = joint.shapes.devs.ModelView;
24288
24289
24290 if (typeof exports === 'object') {
24291
24292     module.exports = joint.shapes.devs;
24293 }
24294
24295 if (typeof exports === 'object') {
24296
24297     var joint = {
24298         util: require('../src/core').util,
24299         shapes: {
24300             basic: require('./joint.shapes.basic')
24301         },
24302         dia: {
24303             ElementView: require('../src/joint.dia.element').ElementView,
24304             Link: require('../src/joint.dia.link').Link
24305         }
24306     };
24307     var _ = require('lodash');
24308 }
24309
24310 joint.shapes.uml = {}
24311
24312 joint.shapes.uml.Class = joint.shapes.basic.Generic.extend({
24313
24314     markup: [
24315         '<g class="rotatable">',
24316           '<g class="scalable">',
24317             '<rect class="uml-class-name-rect"/><rect class="uml-class-attrs-rect"/><rect class="uml-class-methods-rect"/>',
24318           '</g>',
24319           '<text class="uml-class-name-text"/><text class="uml-class-attrs-text"/><text class="uml-class-methods-text"/>',
24320         '</g>'
24321     ].join(''),
24322
24323     defaults: joint.util.deepSupplement({
24324
24325         type: 'uml.Class',
24326
24327         attrs: {
24328             rect: { 'width': 200 },
24329
24330             '.uml-class-name-rect': { 'stroke': 'black', 'stroke-width': 2, 'fill': '#3498db' },
24331             '.uml-class-attrs-rect': { 'stroke': 'black', 'stroke-width': 2, 'fill': '#2980b9' },
24332             '.uml-class-methods-rect': { 'stroke': 'black', 'stroke-width': 2, 'fill': '#2980b9' },
24333
24334             '.uml-class-name-text': {
24335                 'ref': '.uml-class-name-rect', 'ref-y': .5, 'ref-x': .5, 'text-anchor': 'middle', 'y-alignment': 'middle', 'font-weight': 'bold',
24336                 'fill': 'black', 'font-size': 12, 'font-family': 'Times New Roman'
24337             },
24338             '.uml-class-attrs-text': {
24339                 'ref': '.uml-class-attrs-rect', 'ref-y': 5, 'ref-x': 5,
24340                 'fill': 'black', 'font-size': 12, 'font-family': 'Times New Roman'
24341             },
24342             '.uml-class-methods-text': {
24343                 'ref': '.uml-class-methods-rect', 'ref-y': 5, 'ref-x': 5,
24344                 'fill': 'black', 'font-size': 12, 'font-family': 'Times New Roman'
24345             }
24346         },
24347
24348         name: [],
24349         attributes: [],
24350         methods: []
24351
24352     }, joint.shapes.basic.Generic.prototype.defaults),
24353
24354     initialize: function() {
24355
24356         _.bindAll(this, 'updateRectangles');
24357
24358         this.on('change:name change:attributes change:methods', function() {
24359             this.updateRectangles();
24360             this.trigger('uml-update');
24361         });
24362
24363         this.updateRectangles();
24364
24365         joint.shapes.basic.Generic.prototype.initialize.apply(this, arguments);
24366     },
24367
24368     getClassName: function() {
24369         return this.get('name');
24370     },
24371
24372     updateRectangles: function() {
24373
24374         var attrs = this.get('attrs');
24375
24376         var rects = [
24377             { type: 'name', text: this.getClassName() },
24378             { type: 'attrs', text: this.get('attributes') },
24379             { type: 'methods', text: this.get('methods') }
24380         ];
24381
24382         var offsetY = 0;
24383
24384         _.each(rects, function(rect) {
24385
24386             var lines = _.isArray(rect.text) ? rect.text : [rect.text];
24387             var rectHeight = lines.length * 20 + 20;
24388
24389             attrs['.uml-class-' + rect.type + '-text'].text = lines.join('\n');
24390             attrs['.uml-class-' + rect.type + '-rect'].height = rectHeight;
24391             attrs['.uml-class-' + rect.type + '-rect'].transform = 'translate(0,'+ offsetY + ')';
24392
24393             offsetY += rectHeight;
24394         });
24395     }
24396
24397 });
24398
24399 joint.shapes.uml.ClassView = joint.dia.ElementView.extend({
24400
24401     initialize: function() {
24402
24403         joint.dia.ElementView.prototype.initialize.apply(this, arguments);
24404
24405         this.model.on('uml-update', _.bind(function() {
24406             this.update();
24407             this.resize();
24408         }, this));
24409     }
24410 });
24411
24412 joint.shapes.uml.Abstract = joint.shapes.uml.Class.extend({
24413
24414     defaults: joint.util.deepSupplement({
24415         type: 'uml.Abstract',
24416         attrs: {
24417             '.uml-class-name-rect': { fill : '#e74c3c' },
24418             '.uml-class-attrs-rect': { fill : '#c0392b' },
24419             '.uml-class-methods-rect': { fill : '#c0392b' }
24420         }
24421     }, joint.shapes.uml.Class.prototype.defaults),
24422
24423     getClassName: function() {
24424         return ['<<Abstract>>', this.get('name')];
24425     }
24426
24427 });
24428 joint.shapes.uml.AbstractView = joint.shapes.uml.ClassView;
24429
24430 joint.shapes.uml.Interface = joint.shapes.uml.Class.extend({
24431
24432     defaults: joint.util.deepSupplement({
24433         type: 'uml.Interface',
24434         attrs: {
24435             '.uml-class-name-rect': { fill : '#f1c40f' },
24436             '.uml-class-attrs-rect': { fill : '#f39c12' },
24437             '.uml-class-methods-rect': { fill : '#f39c12' }
24438         }
24439     }, joint.shapes.uml.Class.prototype.defaults),
24440
24441     getClassName: function() {
24442         return ['<<Interface>>', this.get('name')];
24443     }
24444
24445 });
24446 joint.shapes.uml.InterfaceView = joint.shapes.uml.ClassView;
24447
24448 joint.shapes.uml.Generalization = joint.dia.Link.extend({
24449     defaults: {
24450         type: 'uml.Generalization',
24451         attrs: { '.marker-target': { d: 'M 20 0 L 0 10 L 20 20 z', fill: 'white' }}
24452     }
24453 });
24454
24455 joint.shapes.uml.Implementation = joint.dia.Link.extend({
24456     defaults: {
24457         type: 'uml.Implementation',
24458         attrs: {
24459             '.marker-target': { d: 'M 20 0 L 0 10 L 20 20 z', fill: 'white' },
24460             '.connection': { 'stroke-dasharray': '3,3' }
24461         }
24462     }
24463 });
24464
24465 joint.shapes.uml.Aggregation = joint.dia.Link.extend({
24466     defaults: {
24467         type: 'uml.Aggregation',
24468         attrs: { '.marker-target': { d: 'M 40 10 L 20 20 L 0 10 L 20 0 z', fill: 'white' }}
24469     }
24470 });
24471
24472 joint.shapes.uml.Composition = joint.dia.Link.extend({
24473     defaults: {
24474         type: 'uml.Composition',
24475         attrs: { '.marker-target': { d: 'M 40 10 L 20 20 L 0 10 L 20 0 z', fill: 'black' }}
24476     }
24477 });
24478
24479 joint.shapes.uml.Association = joint.dia.Link.extend({
24480     defaults: { type: 'uml.Association' }
24481 });
24482
24483 // Statechart
24484
24485 joint.shapes.uml.State = joint.shapes.basic.Generic.extend({
24486
24487     markup: [
24488         '<g class="rotatable">',
24489           '<g class="scalable">',
24490             '<rect/>',
24491           '</g>',
24492           '<path/><text class="uml-state-name"/><text class="uml-state-events"/>',
24493         '</g>'
24494     ].join(''),
24495
24496     defaults: joint.util.deepSupplement({
24497
24498         type: 'uml.State',
24499
24500         attrs: {
24501             rect: { 'width': 200, 'height': 200, 'fill': '#ecf0f1', 'stroke': '#bdc3c7', 'stroke-width': 3, 'rx': 10, 'ry': 10 },
24502             path: { 'd': 'M 0 20 L 200 20', 'stroke': '#bdc3c7', 'stroke-width': 2 },
24503             '.uml-state-name': {
24504                 'ref': 'rect', 'ref-x': .5, 'ref-y': 5, 'text-anchor': 'middle',
24505                 'font-family': 'Courier New', 'font-size': 14, fill: '#000000'
24506             },
24507             '.uml-state-events': {
24508                 'ref': 'path', 'ref-x': 5, 'ref-y': 5,
24509                 'font-family': 'Courier New', 'font-size': 14, fill: '#000000'
24510             }
24511         },
24512
24513         name: 'State',
24514         events: []
24515
24516     }, joint.shapes.basic.Generic.prototype.defaults),
24517
24518     initialize: function() {
24519
24520         _.bindAll(this, 'updateEvents', 'updatePath');
24521
24522         this.on({
24523             'change:name': function() { this.updateName(); this.trigger('change:attrs'); },
24524             'change:events': function() { this.updateEvents(); this.trigger('change:attrs'); },
24525             'change:size': this.updatePath
24526         });
24527
24528         this.updateName();
24529         this.updateEvents();
24530         this.updatePath();
24531
24532         joint.shapes.basic.Generic.prototype.initialize.apply(this, arguments);
24533     },
24534
24535     updateName: function() {
24536         this.get('attrs')['.uml-state-name'].text = this.get('name');
24537     },
24538
24539     updateEvents: function() {
24540         this.get('attrs')['.uml-state-events'].text = this.get('events').join('\n');
24541     },
24542
24543     updatePath: function() {
24544         this.get('attrs')['path'].d = 'M 0 20 L ' + this.get('size').width + ' 20';
24545     }
24546
24547 });
24548
24549 joint.shapes.uml.StartState = joint.shapes.basic.Circle.extend({
24550
24551     defaults: joint.util.deepSupplement({
24552
24553         type: 'uml.StartState',
24554         attrs: { circle: { 'fill': '#34495e', 'stroke': '#2c3e50', 'stroke-width': 2, 'rx': 1 }}
24555
24556     }, joint.shapes.basic.Circle.prototype.defaults)
24557
24558 });
24559
24560 joint.shapes.uml.EndState = joint.shapes.basic.Generic.extend({
24561
24562     markup: '<g class="rotatable"><g class="scalable"><circle class="outer"/><circle class="inner"/></g></g>',
24563
24564     defaults: joint.util.deepSupplement({
24565
24566         type: 'uml.EndState',
24567         size: { width: 20, height: 20 },
24568         attrs: {
24569             'circle.outer': {
24570                 transform: 'translate(10, 10)',
24571                 r: 10,
24572                 fill: 'white',
24573                 stroke: '#2c3e50'
24574             },
24575
24576             'circle.inner': {
24577                 transform: 'translate(10, 10)',
24578                 r: 6,
24579                 fill: '#34495e'
24580             }
24581         }
24582
24583     }, joint.shapes.basic.Generic.prototype.defaults)
24584
24585 });
24586
24587 joint.shapes.uml.Transition = joint.dia.Link.extend({
24588     defaults: {
24589         type: 'uml.Transition',
24590         attrs: {
24591             '.marker-target': { d: 'M 10 0 L 0 5 L 10 10 z', fill: '#34495e', stroke: '#2c3e50' },
24592             '.connection': { stroke: '#2c3e50' }
24593         }
24594     }
24595 });
24596
24597 if (typeof exports === 'object') {
24598
24599     module.exports = joint.shapes.uml;
24600 }
24601
24602 ;(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
24603 var global=typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {};/**
24604  * @license
24605  * Copyright (c) 2012-2013 Chris Pettitt
24606  *
24607  * Permission is hereby granted, free of charge, to any person obtaining a copy
24608  * of this software and associated documentation files (the "Software"), to deal
24609  * in the Software without restriction, including without limitation the rights
24610  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
24611  * copies of the Software, and to permit persons to whom the Software is
24612  * furnished to do so, subject to the following conditions:
24613  *
24614  * The above copyright notice and this permission notice shall be included in
24615  * all copies or substantial portions of the Software.
24616  *
24617  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24618  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24619  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24620  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24621  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24622  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24623  * THE SOFTWARE.
24624  */
24625 global.dagre = require("./index");
24626
24627 },{"./index":2}],2:[function(require,module,exports){
24628 /*
24629 Copyright (c) 2012-2013 Chris Pettitt
24630
24631 Permission is hereby granted, free of charge, to any person obtaining a copy
24632 of this software and associated documentation files (the "Software"), to deal
24633 in the Software without restriction, including without limitation the rights
24634 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
24635 copies of the Software, and to permit persons to whom the Software is
24636 furnished to do so, subject to the following conditions:
24637
24638 The above copyright notice and this permission notice shall be included in
24639 all copies or substantial portions of the Software.
24640
24641 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24642 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24643 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24644 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24645 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24646 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24647 THE SOFTWARE.
24648 */
24649 exports.Digraph = require("graphlib").Digraph;
24650 exports.Graph = require("graphlib").Graph;
24651 exports.layout = require("./lib/layout");
24652 exports.version = require("./lib/version");
24653
24654 },{"./lib/layout":3,"./lib/version":18,"graphlib":24}],3:[function(require,module,exports){
24655 var util = require('./util'),
24656     rank = require('./rank'),
24657     order = require('./order'),
24658     CGraph = require('graphlib').CGraph,
24659     CDigraph = require('graphlib').CDigraph;
24660
24661 module.exports = function() {
24662   // External configuration
24663   var config = {
24664     // How much debug information to include?
24665     debugLevel: 0,
24666     // Max number of sweeps to perform in order phase
24667     orderMaxSweeps: order.DEFAULT_MAX_SWEEPS,
24668     // Use network simplex algorithm in ranking
24669     rankSimplex: false,
24670     // Rank direction. Valid values are (TB, LR)
24671     rankDir: 'TB'
24672   };
24673
24674   // Phase functions
24675   var position = require('./position')();
24676
24677   // This layout object
24678   var self = {};
24679
24680   self.orderIters = util.propertyAccessor(self, config, 'orderMaxSweeps');
24681
24682   self.rankSimplex = util.propertyAccessor(self, config, 'rankSimplex');
24683
24684   self.nodeSep = delegateProperty(position.nodeSep);
24685   self.edgeSep = delegateProperty(position.edgeSep);
24686   self.universalSep = delegateProperty(position.universalSep);
24687   self.rankSep = delegateProperty(position.rankSep);
24688   self.rankDir = util.propertyAccessor(self, config, 'rankDir');
24689   self.debugAlignment = delegateProperty(position.debugAlignment);
24690
24691   self.debugLevel = util.propertyAccessor(self, config, 'debugLevel', function(x) {
24692     util.log.level = x;
24693     position.debugLevel(x);
24694   });
24695
24696   self.run = util.time('Total layout', run);
24697
24698   self._normalize = normalize;
24699
24700   return self;
24701
24702   /*
24703    * Constructs an adjacency graph using the nodes and edges specified through
24704    * config. For each node and edge we add a property `dagre` that contains an
24705    * object that will hold intermediate and final layout information. Some of
24706    * the contents include:
24707    *
24708    *  1) A generated ID that uniquely identifies the object.
24709    *  2) Dimension information for nodes (copied from the source node).
24710    *  3) Optional dimension information for edges.
24711    *
24712    * After the adjacency graph is constructed the code no longer needs to use
24713    * the original nodes and edges passed in via config.
24714    */
24715   function initLayoutGraph(inputGraph) {
24716     var g = new CDigraph();
24717
24718     inputGraph.eachNode(function(u, value) {
24719       if (value === undefined) value = {};
24720       g.addNode(u, {
24721         width: value.width,
24722         height: value.height
24723       });
24724       if (value.hasOwnProperty('rank')) {
24725         g.node(u).prefRank = value.rank;
24726       }
24727     });
24728
24729     // Set up subgraphs
24730     if (inputGraph.parent) {
24731       inputGraph.nodes().forEach(function(u) {
24732         g.parent(u, inputGraph.parent(u));
24733       });
24734     }
24735
24736     inputGraph.eachEdge(function(e, u, v, value) {
24737       if (value === undefined) value = {};
24738       var newValue = {
24739         e: e,
24740         minLen: value.minLen || 1,
24741         width: value.width || 0,
24742         height: value.height || 0,
24743         points: []
24744       };
24745
24746       g.addEdge(null, u, v, newValue);
24747     });
24748
24749     // Initial graph attributes
24750     var graphValue = inputGraph.graph() || {};
24751     g.graph({
24752       rankDir: graphValue.rankDir || config.rankDir,
24753       orderRestarts: graphValue.orderRestarts
24754     });
24755
24756     return g;
24757   }
24758
24759   function run(inputGraph) {
24760     var rankSep = self.rankSep();
24761     var g;
24762     try {
24763       // Build internal graph
24764       g = util.time('initLayoutGraph', initLayoutGraph)(inputGraph);
24765
24766       if (g.order() === 0) {
24767         return g;
24768       }
24769
24770       // Make space for edge labels
24771       g.eachEdge(function(e, s, t, a) {
24772         a.minLen *= 2;
24773       });
24774       self.rankSep(rankSep / 2);
24775
24776       // Determine the rank for each node. Nodes with a lower rank will appear
24777       // above nodes of higher rank.
24778       util.time('rank.run', rank.run)(g, config.rankSimplex);
24779
24780       // Normalize the graph by ensuring that every edge is proper (each edge has
24781       // a length of 1). We achieve this by adding dummy nodes to long edges,
24782       // thus shortening them.
24783       util.time('normalize', normalize)(g);
24784
24785       // Order the nodes so that edge crossings are minimized.
24786       util.time('order', order)(g, config.orderMaxSweeps);
24787
24788       // Find the x and y coordinates for every node in the graph.
24789       util.time('position', position.run)(g);
24790
24791       // De-normalize the graph by removing dummy nodes and augmenting the
24792       // original long edges with coordinate information.
24793       util.time('undoNormalize', undoNormalize)(g);
24794
24795       // Reverses points for edges that are in a reversed state.
24796       util.time('fixupEdgePoints', fixupEdgePoints)(g);
24797
24798       // Restore delete edges and reverse edges that were reversed in the rank
24799       // phase.
24800       util.time('rank.restoreEdges', rank.restoreEdges)(g);
24801
24802       // Construct final result graph and return it
24803       return util.time('createFinalGraph', createFinalGraph)(g, inputGraph.isDirected());
24804     } finally {
24805       self.rankSep(rankSep);
24806     }
24807   }
24808
24809   /*
24810    * This function is responsible for 'normalizing' the graph. The process of
24811    * normalization ensures that no edge in the graph has spans more than one
24812    * rank. To do this it inserts dummy nodes as needed and links them by adding
24813    * dummy edges. This function keeps enough information in the dummy nodes and
24814    * edges to ensure that the original graph can be reconstructed later.
24815    *
24816    * This method assumes that the input graph is cycle free.
24817    */
24818   function normalize(g) {
24819     var dummyCount = 0;
24820     g.eachEdge(function(e, s, t, a) {
24821       var sourceRank = g.node(s).rank;
24822       var targetRank = g.node(t).rank;
24823       if (sourceRank + 1 < targetRank) {
24824         for (var u = s, rank = sourceRank + 1, i = 0; rank < targetRank; ++rank, ++i) {
24825           var v = '_D' + (++dummyCount);
24826           var node = {
24827             width: a.width,
24828             height: a.height,
24829             edge: { id: e, source: s, target: t, attrs: a },
24830             rank: rank,
24831             dummy: true
24832           };
24833
24834           // If this node represents a bend then we will use it as a control
24835           // point. For edges with 2 segments this will be the center dummy
24836           // node. For edges with more than two segments, this will be the
24837           // first and last dummy node.
24838           if (i === 0) node.index = 0;
24839           else if (rank + 1 === targetRank) node.index = 1;
24840
24841           g.addNode(v, node);
24842           g.addEdge(null, u, v, {});
24843           u = v;
24844         }
24845         g.addEdge(null, u, t, {});
24846         g.delEdge(e);
24847       }
24848     });
24849   }
24850
24851   /*
24852    * Reconstructs the graph as it was before normalization. The positions of
24853    * dummy nodes are used to build an array of points for the original 'long'
24854    * edge. Dummy nodes and edges are removed.
24855    */
24856   function undoNormalize(g) {
24857     g.eachNode(function(u, a) {
24858       if (a.dummy) {
24859         if ('index' in a) {
24860           var edge = a.edge;
24861           if (!g.hasEdge(edge.id)) {
24862             g.addEdge(edge.id, edge.source, edge.target, edge.attrs);
24863           }
24864           var points = g.edge(edge.id).points;
24865           points[a.index] = { x: a.x, y: a.y, ul: a.ul, ur: a.ur, dl: a.dl, dr: a.dr };
24866         }
24867         g.delNode(u);
24868       }
24869     });
24870   }
24871
24872   /*
24873    * For each edge that was reversed during the `acyclic` step, reverse its
24874    * array of points.
24875    */
24876   function fixupEdgePoints(g) {
24877     g.eachEdge(function(e, s, t, a) { if (a.reversed) a.points.reverse(); });
24878   }
24879
24880   function createFinalGraph(g, isDirected) {
24881     var out = isDirected ? new CDigraph() : new CGraph();
24882     out.graph(g.graph());
24883     g.eachNode(function(u, value) { out.addNode(u, value); });
24884     g.eachNode(function(u) { out.parent(u, g.parent(u)); });
24885     g.eachEdge(function(e, u, v, value) {
24886       out.addEdge(value.e, u, v, value);
24887     });
24888
24889     // Attach bounding box information
24890     var maxX = 0, maxY = 0;
24891     g.eachNode(function(u, value) {
24892       if (!g.children(u).length) {
24893         maxX = Math.max(maxX, value.x + value.width / 2);
24894         maxY = Math.max(maxY, value.y + value.height / 2);
24895       }
24896     });
24897     g.eachEdge(function(e, u, v, value) {
24898       var maxXPoints = Math.max.apply(Math, value.points.map(function(p) { return p.x; }));
24899       var maxYPoints = Math.max.apply(Math, value.points.map(function(p) { return p.y; }));
24900       maxX = Math.max(maxX, maxXPoints + value.width / 2);
24901       maxY = Math.max(maxY, maxYPoints + value.height / 2);
24902     });
24903     out.graph().width = maxX;
24904     out.graph().height = maxY;
24905
24906     return out;
24907   }
24908
24909   /*
24910    * Given a function, a new function is returned that invokes the given
24911    * function. The return value from the function is always the `self` object.
24912    */
24913   function delegateProperty(f) {
24914     return function() {
24915       if (!arguments.length) return f();
24916       f.apply(null, arguments);
24917       return self;
24918     };
24919   }
24920 };
24921
24922
24923 },{"./order":4,"./position":9,"./rank":10,"./util":17,"graphlib":24}],4:[function(require,module,exports){
24924 var util = require('./util'),
24925     crossCount = require('./order/crossCount'),
24926     initLayerGraphs = require('./order/initLayerGraphs'),
24927     initOrder = require('./order/initOrder'),
24928     sortLayer = require('./order/sortLayer');
24929
24930 module.exports = order;
24931
24932 // The maximum number of sweeps to perform before finishing the order phase.
24933 var DEFAULT_MAX_SWEEPS = 24;
24934 order.DEFAULT_MAX_SWEEPS = DEFAULT_MAX_SWEEPS;
24935
24936 /*
24937  * Runs the order phase with the specified `graph, `maxSweeps`, and
24938  * `debugLevel`. If `maxSweeps` is not specified we use `DEFAULT_MAX_SWEEPS`.
24939  * If `debugLevel` is not set we assume 0.
24940  */
24941 function order(g, maxSweeps) {
24942   if (arguments.length < 2) {
24943     maxSweeps = DEFAULT_MAX_SWEEPS;
24944   }
24945
24946   var restarts = g.graph().orderRestarts || 0;
24947
24948   var layerGraphs = initLayerGraphs(g);
24949   // TODO: remove this when we add back support for ordering clusters
24950   layerGraphs.forEach(function(lg) {
24951     lg = lg.filterNodes(function(u) { return !g.children(u).length; });
24952   });
24953
24954   var iters = 0,
24955       currentBestCC,
24956       allTimeBestCC = Number.MAX_VALUE,
24957       allTimeBest = {};
24958
24959   function saveAllTimeBest() {
24960     g.eachNode(function(u, value) { allTimeBest[u] = value.order; });
24961   }
24962
24963   for (var j = 0; j < Number(restarts) + 1 && allTimeBestCC !== 0; ++j) {
24964     currentBestCC = Number.MAX_VALUE;
24965     initOrder(g, restarts > 0);
24966
24967     util.log(2, 'Order phase start cross count: ' + g.graph().orderInitCC);
24968
24969     var i, lastBest, cc;
24970     for (i = 0, lastBest = 0; lastBest < 4 && i < maxSweeps && currentBestCC > 0; ++i, ++lastBest, ++iters) {
24971       sweep(g, layerGraphs, i);
24972       cc = crossCount(g);
24973       if (cc < currentBestCC) {
24974         lastBest = 0;
24975         currentBestCC = cc;
24976         if (cc < allTimeBestCC) {
24977           saveAllTimeBest();
24978           allTimeBestCC = cc;
24979         }
24980       }
24981       util.log(3, 'Order phase start ' + j + ' iter ' + i + ' cross count: ' + cc);
24982     }
24983   }
24984
24985   Object.keys(allTimeBest).forEach(function(u) {
24986     if (!g.children || !g.children(u).length) {
24987       g.node(u).order = allTimeBest[u];
24988     }
24989   });
24990   g.graph().orderCC = allTimeBestCC;
24991
24992   util.log(2, 'Order iterations: ' + iters);
24993   util.log(2, 'Order phase best cross count: ' + g.graph().orderCC);
24994 }
24995
24996 function predecessorWeights(g, nodes) {
24997   var weights = {};
24998   nodes.forEach(function(u) {
24999     weights[u] = g.inEdges(u).map(function(e) {
25000       return g.node(g.source(e)).order;
25001     });
25002   });
25003   return weights;
25004 }
25005
25006 function successorWeights(g, nodes) {
25007   var weights = {};
25008   nodes.forEach(function(u) {
25009     weights[u] = g.outEdges(u).map(function(e) {
25010       return g.node(g.target(e)).order;
25011     });
25012   });
25013   return weights;
25014 }
25015
25016 function sweep(g, layerGraphs, iter) {
25017   if (iter % 2 === 0) {
25018     sweepDown(g, layerGraphs, iter);
25019   } else {
25020     sweepUp(g, layerGraphs, iter);
25021   }
25022 }
25023
25024 function sweepDown(g, layerGraphs) {
25025   var cg;
25026   for (i = 1; i < layerGraphs.length; ++i) {
25027     cg = sortLayer(layerGraphs[i], cg, predecessorWeights(g, layerGraphs[i].nodes()));
25028   }
25029 }
25030
25031 function sweepUp(g, layerGraphs) {
25032   var cg;
25033   for (i = layerGraphs.length - 2; i >= 0; --i) {
25034     sortLayer(layerGraphs[i], cg, successorWeights(g, layerGraphs[i].nodes()));
25035   }
25036 }
25037
25038 },{"./order/crossCount":5,"./order/initLayerGraphs":6,"./order/initOrder":7,"./order/sortLayer":8,"./util":17}],5:[function(require,module,exports){
25039 var util = require('../util');
25040
25041 module.exports = crossCount;
25042
25043 /*
25044  * Returns the cross count for the given graph.
25045  */
25046 function crossCount(g) {
25047   var cc = 0;
25048   var ordering = util.ordering(g);
25049   for (var i = 1; i < ordering.length; ++i) {
25050     cc += twoLayerCrossCount(g, ordering[i-1], ordering[i]);
25051   }
25052   return cc;
25053 }
25054
25055 /*
25056  * This function searches through a ranked and ordered graph and counts the
25057  * number of edges that cross. This algorithm is derived from:
25058  *
25059  *    W. Barth et al., Bilayer Cross Counting, JGAA, 8(2) 179–194 (2004)
25060  */
25061 function twoLayerCrossCount(g, layer1, layer2) {
25062   var indices = [];
25063   layer1.forEach(function(u) {
25064     var nodeIndices = [];
25065     g.outEdges(u).forEach(function(e) { nodeIndices.push(g.node(g.target(e)).order); });
25066     nodeIndices.sort(function(x, y) { return x - y; });
25067     indices = indices.concat(nodeIndices);
25068   });
25069
25070   var firstIndex = 1;
25071   while (firstIndex < layer2.length) firstIndex <<= 1;
25072
25073   var treeSize = 2 * firstIndex - 1;
25074   firstIndex -= 1;
25075
25076   var tree = [];
25077   for (var i = 0; i < treeSize; ++i) { tree[i] = 0; }
25078
25079   var cc = 0;
25080   indices.forEach(function(i) {
25081     var treeIndex = i + firstIndex;
25082     ++tree[treeIndex];
25083     while (treeIndex > 0) {
25084       if (treeIndex % 2) {
25085         cc += tree[treeIndex + 1];
25086       }
25087       treeIndex = (treeIndex - 1) >> 1;
25088       ++tree[treeIndex];
25089     }
25090   });
25091
25092   return cc;
25093 }
25094
25095 },{"../util":17}],6:[function(require,module,exports){
25096 var nodesFromList = require('graphlib').filter.nodesFromList,
25097     /* jshint -W079 */
25098     Set = require('cp-data').Set;
25099
25100 module.exports = initLayerGraphs;
25101
25102 /*
25103  * This function takes a compound layered graph, g, and produces an array of
25104  * layer graphs. Each entry in the array represents a subgraph of nodes
25105  * relevant for performing crossing reduction on that layer.
25106  */
25107 function initLayerGraphs(g) {
25108   var ranks = [];
25109
25110   function dfs(u) {
25111     if (u === null) {
25112       g.children(u).forEach(function(v) { dfs(v); });
25113       return;
25114     }
25115
25116     var value = g.node(u);
25117     value.minRank = ('rank' in value) ? value.rank : Number.MAX_VALUE;
25118     value.maxRank = ('rank' in value) ? value.rank : Number.MIN_VALUE;
25119     var uRanks = new Set();
25120     g.children(u).forEach(function(v) {
25121       var rs = dfs(v);
25122       uRanks = Set.union([uRanks, rs]);
25123       value.minRank = Math.min(value.minRank, g.node(v).minRank);
25124       value.maxRank = Math.max(value.maxRank, g.node(v).maxRank);
25125     });
25126
25127     if ('rank' in value) uRanks.add(value.rank);
25128
25129     uRanks.keys().forEach(function(r) {
25130       if (!(r in ranks)) ranks[r] = [];
25131       ranks[r].push(u);
25132     });
25133
25134     return uRanks;
25135   }
25136   dfs(null);
25137
25138   var layerGraphs = [];
25139   ranks.forEach(function(us, rank) {
25140     layerGraphs[rank] = g.filterNodes(nodesFromList(us));
25141   });
25142
25143   return layerGraphs;
25144 }
25145
25146 },{"cp-data":19,"graphlib":24}],7:[function(require,module,exports){
25147 var crossCount = require('./crossCount'),
25148     util = require('../util');
25149
25150 module.exports = initOrder;
25151
25152 /*
25153  * Given a graph with a set of layered nodes (i.e. nodes that have a `rank`
25154  * attribute) this function attaches an `order` attribute that uniquely
25155  * arranges each node of each rank. If no constraint graph is provided the
25156  * order of the nodes in each rank is entirely arbitrary.
25157  */
25158 function initOrder(g, random) {
25159   var layers = [];
25160
25161   g.eachNode(function(u, value) {
25162     var layer = layers[value.rank];
25163     if (g.children && g.children(u).length > 0) return;
25164     if (!layer) {
25165       layer = layers[value.rank] = [];
25166     }
25167     layer.push(u);
25168   });
25169
25170   layers.forEach(function(layer) {
25171     if (random) {
25172       util.shuffle(layer);
25173     }
25174     layer.forEach(function(u, i) {
25175       g.node(u).order = i;
25176     });
25177   });
25178
25179   var cc = crossCount(g);
25180   g.graph().orderInitCC = cc;
25181   g.graph().orderCC = Number.MAX_VALUE;
25182 }
25183
25184 },{"../util":17,"./crossCount":5}],8:[function(require,module,exports){
25185 var util = require('../util');
25186 /*
25187     Digraph = require('graphlib').Digraph,
25188     topsort = require('graphlib').alg.topsort,
25189     nodesFromList = require('graphlib').filter.nodesFromList;
25190 */
25191
25192 module.exports = sortLayer;
25193
25194 /*
25195 function sortLayer(g, cg, weights) {
25196   var result = sortLayerSubgraph(g, null, cg, weights);
25197   result.list.forEach(function(u, i) {
25198     g.node(u).order = i;
25199   });
25200   return result.constraintGraph;
25201 }
25202 */
25203
25204 function sortLayer(g, cg, weights) {
25205   var ordering = [];
25206   var bs = {};
25207   g.eachNode(function(u, value) {
25208     ordering[value.order] = u;
25209     var ws = weights[u];
25210     if (ws.length) {
25211       bs[u] = util.sum(ws) / ws.length;
25212     }
25213   });
25214
25215   var toSort = g.nodes().filter(function(u) { return bs[u] !== undefined; });
25216   toSort.sort(function(x, y) {
25217     return bs[x] - bs[y] || g.node(x).order - g.node(y).order;
25218   });
25219
25220   for (var i = 0, j = 0, jl = toSort.length; j < jl; ++i) {
25221     if (bs[ordering[i]] !== undefined) {
25222       g.node(toSort[j++]).order = i;
25223     }
25224   }
25225 }
25226
25227 // TOOD: re-enable constrained sorting once we have a strategy for handling
25228 // undefined barycenters.
25229 /*
25230 function sortLayerSubgraph(g, sg, cg, weights) {
25231   cg = cg ? cg.filterNodes(nodesFromList(g.children(sg))) : new Digraph();
25232
25233   var nodeData = {};
25234   g.children(sg).forEach(function(u) {
25235     if (g.children(u).length) {
25236       nodeData[u] = sortLayerSubgraph(g, u, cg, weights);
25237       nodeData[u].firstSG = u;
25238       nodeData[u].lastSG = u;
25239     } else {
25240       var ws = weights[u];
25241       nodeData[u] = {
25242         degree: ws.length,
25243         barycenter: ws.length > 0 ? util.sum(ws) / ws.length : 0,
25244         list: [u]
25245       };
25246     }
25247   });
25248
25249   resolveViolatedConstraints(g, cg, nodeData);
25250
25251   var keys = Object.keys(nodeData);
25252   keys.sort(function(x, y) {
25253     return nodeData[x].barycenter - nodeData[y].barycenter;
25254   });
25255
25256   var result =  keys.map(function(u) { return nodeData[u]; })
25257                     .reduce(function(lhs, rhs) { return mergeNodeData(g, lhs, rhs); });
25258   return result;
25259 }
25260
25261 /*
25262 function mergeNodeData(g, lhs, rhs) {
25263   var cg = mergeDigraphs(lhs.constraintGraph, rhs.constraintGraph);
25264
25265   if (lhs.lastSG !== undefined && rhs.firstSG !== undefined) {
25266     if (cg === undefined) {
25267       cg = new Digraph();
25268     }
25269     if (!cg.hasNode(lhs.lastSG)) { cg.addNode(lhs.lastSG); }
25270     cg.addNode(rhs.firstSG);
25271     cg.addEdge(null, lhs.lastSG, rhs.firstSG);
25272   }
25273
25274   return {
25275     degree: lhs.degree + rhs.degree,
25276     barycenter: (lhs.barycenter * lhs.degree + rhs.barycenter * rhs.degree) /
25277                 (lhs.degree + rhs.degree),
25278     list: lhs.list.concat(rhs.list),
25279     firstSG: lhs.firstSG !== undefined ? lhs.firstSG : rhs.firstSG,
25280     lastSG: rhs.lastSG !== undefined ? rhs.lastSG : lhs.lastSG,
25281     constraintGraph: cg
25282   };
25283 }
25284
25285 function mergeDigraphs(lhs, rhs) {
25286   if (lhs === undefined) return rhs;
25287   if (rhs === undefined) return lhs;
25288
25289   lhs = lhs.copy();
25290   rhs.nodes().forEach(function(u) { lhs.addNode(u); });
25291   rhs.edges().forEach(function(e, u, v) { lhs.addEdge(null, u, v); });
25292   return lhs;
25293 }
25294
25295 function resolveViolatedConstraints(g, cg, nodeData) {
25296   // Removes nodes `u` and `v` from `cg` and makes any edges incident on them
25297   // incident on `w` instead.
25298   function collapseNodes(u, v, w) {
25299     // TODO original paper removes self loops, but it is not obvious when this would happen
25300     cg.inEdges(u).forEach(function(e) {
25301       cg.delEdge(e);
25302       cg.addEdge(null, cg.source(e), w);
25303     });
25304
25305     cg.outEdges(v).forEach(function(e) {
25306       cg.delEdge(e);
25307       cg.addEdge(null, w, cg.target(e));
25308     });
25309
25310     cg.delNode(u);
25311     cg.delNode(v);
25312   }
25313
25314   var violated;
25315   while ((violated = findViolatedConstraint(cg, nodeData)) !== undefined) {
25316     var source = cg.source(violated),
25317         target = cg.target(violated);
25318
25319     var v;
25320     while ((v = cg.addNode(null)) && g.hasNode(v)) {
25321       cg.delNode(v);
25322     }
25323
25324     // Collapse barycenter and list
25325     nodeData[v] = mergeNodeData(g, nodeData[source], nodeData[target]);
25326     delete nodeData[source];
25327     delete nodeData[target];
25328
25329     collapseNodes(source, target, v);
25330     if (cg.incidentEdges(v).length === 0) { cg.delNode(v); }
25331   }
25332 }
25333
25334 function findViolatedConstraint(cg, nodeData) {
25335   var us = topsort(cg);
25336   for (var i = 0; i < us.length; ++i) {
25337     var u = us[i];
25338     var inEdges = cg.inEdges(u);
25339     for (var j = 0; j < inEdges.length; ++j) {
25340       var e = inEdges[j];
25341       if (nodeData[cg.source(e)].barycenter >= nodeData[u].barycenter) {
25342         return e;
25343       }
25344     }
25345   }
25346 }
25347 */
25348
25349 },{"../util":17}],9:[function(require,module,exports){
25350 var util = require('./util');
25351
25352 /*
25353  * The algorithms here are based on Brandes and Köpf, "Fast and Simple
25354  * Horizontal Coordinate Assignment".
25355  */
25356 module.exports = function() {
25357   // External configuration
25358   var config = {
25359     nodeSep: 50,
25360     edgeSep: 10,
25361     universalSep: null,
25362     rankSep: 30
25363   };
25364
25365   var self = {};
25366
25367   self.nodeSep = util.propertyAccessor(self, config, 'nodeSep');
25368   self.edgeSep = util.propertyAccessor(self, config, 'edgeSep');
25369   // If not null this separation value is used for all nodes and edges
25370   // regardless of their widths. `nodeSep` and `edgeSep` are ignored with this
25371   // option.
25372   self.universalSep = util.propertyAccessor(self, config, 'universalSep');
25373   self.rankSep = util.propertyAccessor(self, config, 'rankSep');
25374   self.debugLevel = util.propertyAccessor(self, config, 'debugLevel');
25375
25376   self.run = run;
25377
25378   return self;
25379
25380   function run(g) {
25381     g = g.filterNodes(util.filterNonSubgraphs(g));
25382
25383     var layering = util.ordering(g);
25384
25385     var conflicts = findConflicts(g, layering);
25386
25387     var xss = {};
25388     ['u', 'd'].forEach(function(vertDir) {
25389       if (vertDir === 'd') layering.reverse();
25390
25391       ['l', 'r'].forEach(function(horizDir) {
25392         if (horizDir === 'r') reverseInnerOrder(layering);
25393
25394         var dir = vertDir + horizDir;
25395         var align = verticalAlignment(g, layering, conflicts, vertDir === 'u' ? 'predecessors' : 'successors');
25396         xss[dir]= horizontalCompaction(g, layering, align.pos, align.root, align.align);
25397
25398         if (config.debugLevel >= 3)
25399           debugPositioning(vertDir + horizDir, g, layering, xss[dir]);
25400
25401         if (horizDir === 'r') flipHorizontally(xss[dir]);
25402
25403         if (horizDir === 'r') reverseInnerOrder(layering);
25404       });
25405
25406       if (vertDir === 'd') layering.reverse();
25407     });
25408
25409     balance(g, layering, xss);
25410
25411     g.eachNode(function(v) {
25412       var xs = [];
25413       for (var alignment in xss) {
25414         var alignmentX = xss[alignment][v];
25415         posXDebug(alignment, g, v, alignmentX);
25416         xs.push(alignmentX);
25417       }
25418       xs.sort(function(x, y) { return x - y; });
25419       posX(g, v, (xs[1] + xs[2]) / 2);
25420     });
25421
25422     // Align y coordinates with ranks
25423     var y = 0, reverseY = g.graph().rankDir === 'BT' || g.graph().rankDir === 'RL';
25424     layering.forEach(function(layer) {
25425       var maxHeight = util.max(layer.map(function(u) { return height(g, u); }));
25426       y += maxHeight / 2;
25427       layer.forEach(function(u) {
25428         posY(g, u, reverseY ? -y : y);
25429       });
25430       y += maxHeight / 2 + config.rankSep;
25431     });
25432
25433     // Translate layout so that top left corner of bounding rectangle has
25434     // coordinate (0, 0).
25435     var minX = util.min(g.nodes().map(function(u) { return posX(g, u) - width(g, u) / 2; }));
25436     var minY = util.min(g.nodes().map(function(u) { return posY(g, u) - height(g, u) / 2; }));
25437     g.eachNode(function(u) {
25438       posX(g, u, posX(g, u) - minX);
25439       posY(g, u, posY(g, u) - minY);
25440     });
25441   }
25442
25443   /*
25444    * Generate an ID that can be used to represent any undirected edge that is
25445    * incident on `u` and `v`.
25446    */
25447   function undirEdgeId(u, v) {
25448     return u < v
25449       ? u.toString().length + ':' + u + '-' + v
25450       : v.toString().length + ':' + v + '-' + u;
25451   }
25452
25453   function findConflicts(g, layering) {
25454     var conflicts = {}, // Set of conflicting edge ids
25455         pos = {},       // Position of node in its layer
25456         prevLayer,
25457         currLayer,
25458         k0,     // Position of the last inner segment in the previous layer
25459         l,      // Current position in the current layer (for iteration up to `l1`)
25460         k1;     // Position of the next inner segment in the previous layer or
25461                 // the position of the last element in the previous layer
25462
25463     if (layering.length <= 2) return conflicts;
25464
25465     function updateConflicts(v) {
25466       var k = pos[v];
25467       if (k < k0 || k > k1) {
25468         conflicts[undirEdgeId(currLayer[l], v)] = true;
25469       }
25470     }
25471
25472     layering[1].forEach(function(u, i) { pos[u] = i; });
25473     for (var i = 1; i < layering.length - 1; ++i) {
25474       prevLayer = layering[i];
25475       currLayer = layering[i+1];
25476       k0 = 0;
25477       l = 0;
25478
25479       // Scan current layer for next node that is incident to an inner segement
25480       // between layering[i+1] and layering[i].
25481       for (var l1 = 0; l1 < currLayer.length; ++l1) {
25482         var u = currLayer[l1]; // Next inner segment in the current layer or
25483                                // last node in the current layer
25484         pos[u] = l1;
25485         k1 = undefined;
25486
25487         if (g.node(u).dummy) {
25488           var uPred = g.predecessors(u)[0];
25489           // Note: In the case of self loops and sideways edges it is possible
25490           // for a dummy not to have a predecessor.
25491           if (uPred !== undefined && g.node(uPred).dummy)
25492             k1 = pos[uPred];
25493         }
25494         if (k1 === undefined && l1 === currLayer.length - 1)
25495           k1 = prevLayer.length - 1;
25496
25497         if (k1 !== undefined) {
25498           for (; l <= l1; ++l) {
25499             g.predecessors(currLayer[l]).forEach(updateConflicts);
25500           }
25501           k0 = k1;
25502         }
25503       }
25504     }
25505
25506     return conflicts;
25507   }
25508
25509   function verticalAlignment(g, layering, conflicts, relationship) {
25510     var pos = {},   // Position for a node in its layer
25511         root = {},  // Root of the block that the node participates in
25512         align = {}; // Points to the next node in the block or, if the last
25513                     // element in the block, points to the first block's root
25514
25515     layering.forEach(function(layer) {
25516       layer.forEach(function(u, i) {
25517         root[u] = u;
25518         align[u] = u;
25519         pos[u] = i;
25520       });
25521     });
25522
25523     layering.forEach(function(layer) {
25524       var prevIdx = -1;
25525       layer.forEach(function(v) {
25526         var related = g[relationship](v), // Adjacent nodes from the previous layer
25527             mid;                          // The mid point in the related array
25528
25529         if (related.length > 0) {
25530           related.sort(function(x, y) { return pos[x] - pos[y]; });
25531           mid = (related.length - 1) / 2;
25532           related.slice(Math.floor(mid), Math.ceil(mid) + 1).forEach(function(u) {
25533             if (align[v] === v) {
25534               if (!conflicts[undirEdgeId(u, v)] && prevIdx < pos[u]) {
25535                 align[u] = v;
25536                 align[v] = root[v] = root[u];
25537                 prevIdx = pos[u];
25538               }
25539             }
25540           });
25541         }
25542       });
25543     });
25544
25545     return { pos: pos, root: root, align: align };
25546   }
25547
25548   // This function deviates from the standard BK algorithm in two ways. First
25549   // it takes into account the size of the nodes. Second it includes a fix to
25550   // the original algorithm that is described in Carstens, "Node and Label
25551   // Placement in a Layered Layout Algorithm".
25552   function horizontalCompaction(g, layering, pos, root, align) {
25553     var sink = {},       // Mapping of node id -> sink node id for class
25554         maybeShift = {}, // Mapping of sink node id -> { class node id, min shift }
25555         shift = {},      // Mapping of sink node id -> shift
25556         pred = {},       // Mapping of node id -> predecessor node (or null)
25557         xs = {};         // Calculated X positions
25558
25559     layering.forEach(function(layer) {
25560       layer.forEach(function(u, i) {
25561         sink[u] = u;
25562         maybeShift[u] = {};
25563         if (i > 0)
25564           pred[u] = layer[i - 1];
25565       });
25566     });
25567
25568     function updateShift(toShift, neighbor, delta) {
25569       if (!(neighbor in maybeShift[toShift])) {
25570         maybeShift[toShift][neighbor] = delta;
25571       } else {
25572         maybeShift[toShift][neighbor] = Math.min(maybeShift[toShift][neighbor], delta);
25573       }
25574     }
25575
25576     function placeBlock(v) {
25577       if (!(v in xs)) {
25578         xs[v] = 0;
25579         var w = v;
25580         do {
25581           if (pos[w] > 0) {
25582             var u = root[pred[w]];
25583             placeBlock(u);
25584             if (sink[v] === v) {
25585               sink[v] = sink[u];
25586             }
25587             var delta = sep(g, pred[w]) + sep(g, w);
25588             if (sink[v] !== sink[u]) {
25589               updateShift(sink[u], sink[v], xs[v] - xs[u] - delta);
25590             } else {
25591               xs[v] = Math.max(xs[v], xs[u] + delta);
25592             }
25593           }
25594           w = align[w];
25595         } while (w !== v);
25596       }
25597     }
25598
25599     // Root coordinates relative to sink
25600     util.values(root).forEach(function(v) {
25601       placeBlock(v);
25602     });
25603
25604     // Absolute coordinates
25605     // There is an assumption here that we've resolved shifts for any classes
25606     // that begin at an earlier layer. We guarantee this by visiting layers in
25607     // order.
25608     layering.forEach(function(layer) {
25609       layer.forEach(function(v) {
25610         xs[v] = xs[root[v]];
25611         if (v === root[v] && v === sink[v]) {
25612           var minShift = 0;
25613           if (v in maybeShift && Object.keys(maybeShift[v]).length > 0) {
25614             minShift = util.min(Object.keys(maybeShift[v])
25615                                  .map(function(u) {
25616                                       return maybeShift[v][u] + (u in shift ? shift[u] : 0);
25617                                       }
25618                                  ));
25619           }
25620           shift[v] = minShift;
25621         }
25622       });
25623     });
25624
25625     layering.forEach(function(layer) {
25626       layer.forEach(function(v) {
25627         xs[v] += shift[sink[root[v]]] || 0;
25628       });
25629     });
25630
25631     return xs;
25632   }
25633
25634   function findMinCoord(g, layering, xs) {
25635     return util.min(layering.map(function(layer) {
25636       var u = layer[0];
25637       return xs[u];
25638     }));
25639   }
25640
25641   function findMaxCoord(g, layering, xs) {
25642     return util.max(layering.map(function(layer) {
25643       var u = layer[layer.length - 1];
25644       return xs[u];
25645     }));
25646   }
25647
25648   function balance(g, layering, xss) {
25649     var min = {},                            // Min coordinate for the alignment
25650         max = {},                            // Max coordinate for the alginment
25651         smallestAlignment,
25652         shift = {};                          // Amount to shift a given alignment
25653
25654     function updateAlignment(v) {
25655       xss[alignment][v] += shift[alignment];
25656     }
25657
25658     var smallest = Number.POSITIVE_INFINITY;
25659     for (var alignment in xss) {
25660       var xs = xss[alignment];
25661       min[alignment] = findMinCoord(g, layering, xs);
25662       max[alignment] = findMaxCoord(g, layering, xs);
25663       var w = max[alignment] - min[alignment];
25664       if (w < smallest) {
25665         smallest = w;
25666         smallestAlignment = alignment;
25667       }
25668     }
25669
25670     // Determine how much to adjust positioning for each alignment
25671     ['u', 'd'].forEach(function(vertDir) {
25672       ['l', 'r'].forEach(function(horizDir) {
25673         var alignment = vertDir + horizDir;
25674         shift[alignment] = horizDir === 'l'
25675             ? min[smallestAlignment] - min[alignment]
25676             : max[smallestAlignment] - max[alignment];
25677       });
25678     });
25679
25680     // Find average of medians for xss array
25681     for (alignment in xss) {
25682       g.eachNode(updateAlignment);
25683     }
25684   }
25685
25686   function flipHorizontally(xs) {
25687     for (var u in xs) {
25688       xs[u] = -xs[u];
25689     }
25690   }
25691
25692   function reverseInnerOrder(layering) {
25693     layering.forEach(function(layer) {
25694       layer.reverse();
25695     });
25696   }
25697
25698   function width(g, u) {
25699     switch (g.graph().rankDir) {
25700       case 'LR': return g.node(u).height;
25701       case 'RL': return g.node(u).height;
25702       default:   return g.node(u).width;
25703     }
25704   }
25705
25706   function height(g, u) {
25707     switch(g.graph().rankDir) {
25708       case 'LR': return g.node(u).width;
25709       case 'RL': return g.node(u).width;
25710       default:   return g.node(u).height;
25711     }
25712   }
25713
25714   function sep(g, u) {
25715     if (config.universalSep !== null) {
25716       return config.universalSep;
25717     }
25718     var w = width(g, u);
25719     var s = g.node(u).dummy ? config.edgeSep : config.nodeSep;
25720     return (w + s) / 2;
25721   }
25722
25723   function posX(g, u, x) {
25724     if (g.graph().rankDir === 'LR' || g.graph().rankDir === 'RL') {
25725       if (arguments.length < 3) {
25726         return g.node(u).y;
25727       } else {
25728         g.node(u).y = x;
25729       }
25730     } else {
25731       if (arguments.length < 3) {
25732         return g.node(u).x;
25733       } else {
25734         g.node(u).x = x;
25735       }
25736     }
25737   }
25738
25739   function posXDebug(name, g, u, x) {
25740     if (g.graph().rankDir === 'LR' || g.graph().rankDir === 'RL') {
25741       if (arguments.length < 3) {
25742         return g.node(u)[name];
25743       } else {
25744         g.node(u)[name] = x;
25745       }
25746     } else {
25747       if (arguments.length < 3) {
25748         return g.node(u)[name];
25749       } else {
25750         g.node(u)[name] = x;
25751       }
25752     }
25753   }
25754
25755   function posY(g, u, y) {
25756     if (g.graph().rankDir === 'LR' || g.graph().rankDir === 'RL') {
25757       if (arguments.length < 3) {
25758         return g.node(u).x;
25759       } else {
25760         g.node(u).x = y;
25761       }
25762     } else {
25763       if (arguments.length < 3) {
25764         return g.node(u).y;
25765       } else {
25766         g.node(u).y = y;
25767       }
25768     }
25769   }
25770
25771   function debugPositioning(align, g, layering, xs) {
25772     layering.forEach(function(l, li) {
25773       var u, xU;
25774       l.forEach(function(v) {
25775         var xV = xs[v];
25776         if (u) {
25777           var s = sep(g, u) + sep(g, v);
25778           if (xV - xU < s)
25779             console.log('Position phase: sep violation. Align: ' + align + '. Layer: ' + li + '. ' +
25780               'U: ' + u + ' V: ' + v + '. Actual sep: ' + (xV - xU) + ' Expected sep: ' + s);
25781         }
25782         u = v;
25783         xU = xV;
25784       });
25785     });
25786   }
25787 };
25788
25789 },{"./util":17}],10:[function(require,module,exports){
25790 var util = require('./util'),
25791     acyclic = require('./rank/acyclic'),
25792     initRank = require('./rank/initRank'),
25793     feasibleTree = require('./rank/feasibleTree'),
25794     constraints = require('./rank/constraints'),
25795     simplex = require('./rank/simplex'),
25796     components = require('graphlib').alg.components,
25797     filter = require('graphlib').filter;
25798
25799 exports.run = run;
25800 exports.restoreEdges = restoreEdges;
25801
25802 /*
25803  * Heuristic function that assigns a rank to each node of the input graph with
25804  * the intent of minimizing edge lengths, while respecting the `minLen`
25805  * attribute of incident edges.
25806  *
25807  * Prerequisites:
25808  *
25809  *  * Each edge in the input graph must have an assigned 'minLen' attribute
25810  */
25811 function run(g, useSimplex) {
25812   expandSelfLoops(g);
25813
25814   // If there are rank constraints on nodes, then build a new graph that
25815   // encodes the constraints.
25816   util.time('constraints.apply', constraints.apply)(g);
25817
25818   expandSidewaysEdges(g);
25819
25820   // Reverse edges to get an acyclic graph, we keep the graph in an acyclic
25821   // state until the very end.
25822   util.time('acyclic', acyclic)(g);
25823
25824   // Convert the graph into a flat graph for ranking
25825   var flatGraph = g.filterNodes(util.filterNonSubgraphs(g));
25826
25827   // Assign an initial ranking using DFS.
25828   initRank(flatGraph);
25829
25830   // For each component improve the assigned ranks.
25831   components(flatGraph).forEach(function(cmpt) {
25832     var subgraph = flatGraph.filterNodes(filter.nodesFromList(cmpt));
25833     rankComponent(subgraph, useSimplex);
25834   });
25835
25836   // Relax original constraints
25837   util.time('constraints.relax', constraints.relax(g));
25838
25839   // When handling nodes with constrained ranks it is possible to end up with
25840   // edges that point to previous ranks. Most of the subsequent algorithms assume
25841   // that edges are pointing to successive ranks only. Here we reverse any "back
25842   // edges" and mark them as such. The acyclic algorithm will reverse them as a
25843   // post processing step.
25844   util.time('reorientEdges', reorientEdges)(g);
25845 }
25846
25847 function restoreEdges(g) {
25848   acyclic.undo(g);
25849 }
25850
25851 /*
25852  * Expand self loops into three dummy nodes. One will sit above the incident
25853  * node, one will be at the same level, and one below. The result looks like:
25854  *
25855  *         /--<--x--->--\
25856  *     node              y
25857  *         \--<--z--->--/
25858  *
25859  * Dummy nodes x, y, z give us the shape of a loop and node y is where we place
25860  * the label.
25861  *
25862  * TODO: consolidate knowledge of dummy node construction.
25863  * TODO: support minLen = 2
25864  */
25865 function expandSelfLoops(g) {
25866   g.eachEdge(function(e, u, v, a) {
25867     if (u === v) {
25868       var x = addDummyNode(g, e, u, v, a, 0, false),
25869           y = addDummyNode(g, e, u, v, a, 1, true),
25870           z = addDummyNode(g, e, u, v, a, 2, false);
25871       g.addEdge(null, x, u, {minLen: 1, selfLoop: true});
25872       g.addEdge(null, x, y, {minLen: 1, selfLoop: true});
25873       g.addEdge(null, u, z, {minLen: 1, selfLoop: true});
25874       g.addEdge(null, y, z, {minLen: 1, selfLoop: true});
25875       g.delEdge(e);
25876     }
25877   });
25878 }
25879
25880 function expandSidewaysEdges(g) {
25881   g.eachEdge(function(e, u, v, a) {
25882     if (u === v) {
25883       var origEdge = a.originalEdge,
25884           dummy = addDummyNode(g, origEdge.e, origEdge.u, origEdge.v, origEdge.value, 0, true);
25885       g.addEdge(null, u, dummy, {minLen: 1});
25886       g.addEdge(null, dummy, v, {minLen: 1});
25887       g.delEdge(e);
25888     }
25889   });
25890 }
25891
25892 function addDummyNode(g, e, u, v, a, index, isLabel) {
25893   return g.addNode(null, {
25894     width: isLabel ? a.width : 0,
25895     height: isLabel ? a.height : 0,
25896     edge: { id: e, source: u, target: v, attrs: a },
25897     dummy: true,
25898     index: index
25899   });
25900 }
25901
25902 function reorientEdges(g) {
25903   g.eachEdge(function(e, u, v, value) {
25904     if (g.node(u).rank > g.node(v).rank) {
25905       g.delEdge(e);
25906       value.reversed = true;
25907       g.addEdge(e, v, u, value);
25908     }
25909   });
25910 }
25911
25912 function rankComponent(subgraph, useSimplex) {
25913   var spanningTree = feasibleTree(subgraph);
25914
25915   if (useSimplex) {
25916     util.log(1, 'Using network simplex for ranking');
25917     simplex(subgraph, spanningTree);
25918   }
25919   normalize(subgraph);
25920 }
25921
25922 function normalize(g) {
25923   var m = util.min(g.nodes().map(function(u) { return g.node(u).rank; }));
25924   g.eachNode(function(u, node) { node.rank -= m; });
25925 }
25926
25927 },{"./rank/acyclic":11,"./rank/constraints":12,"./rank/feasibleTree":13,"./rank/initRank":14,"./rank/simplex":16,"./util":17,"graphlib":24}],11:[function(require,module,exports){
25928 var util = require('../util');
25929
25930 module.exports = acyclic;
25931 module.exports.undo = undo;
25932
25933 /*
25934  * This function takes a directed graph that may have cycles and reverses edges
25935  * as appropriate to break these cycles. Each reversed edge is assigned a
25936  * `reversed` attribute with the value `true`.
25937  *
25938  * There should be no self loops in the graph.
25939  */
25940 function acyclic(g) {
25941   var onStack = {},
25942       visited = {},
25943       reverseCount = 0;
25944   
25945   function dfs(u) {
25946     if (u in visited) return;
25947     visited[u] = onStack[u] = true;
25948     g.outEdges(u).forEach(function(e) {
25949       var t = g.target(e),
25950           value;
25951
25952       if (u === t) {
25953         console.error('Warning: found self loop "' + e + '" for node "' + u + '"');
25954       } else if (t in onStack) {
25955         value = g.edge(e);
25956         g.delEdge(e);
25957         value.reversed = true;
25958         ++reverseCount;
25959         g.addEdge(e, t, u, value);
25960       } else {
25961         dfs(t);
25962       }
25963     });
25964
25965     delete onStack[u];
25966   }
25967
25968   g.eachNode(function(u) { dfs(u); });
25969
25970   util.log(2, 'Acyclic Phase: reversed ' + reverseCount + ' edge(s)');
25971
25972   return reverseCount;
25973 }
25974
25975 /*
25976  * Given a graph that has had the acyclic operation applied, this function
25977  * undoes that operation. More specifically, any edge with the `reversed`
25978  * attribute is again reversed to restore the original direction of the edge.
25979  */
25980 function undo(g) {
25981   g.eachEdge(function(e, s, t, a) {
25982     if (a.reversed) {
25983       delete a.reversed;
25984       g.delEdge(e);
25985       g.addEdge(e, t, s, a);
25986     }
25987   });
25988 }
25989
25990 },{"../util":17}],12:[function(require,module,exports){
25991 exports.apply = function(g) {
25992   function dfs(sg) {
25993     var rankSets = {};
25994     g.children(sg).forEach(function(u) {
25995       if (g.children(u).length) {
25996         dfs(u);
25997         return;
25998       }
25999
26000       var value = g.node(u),
26001           prefRank = value.prefRank;
26002       if (prefRank !== undefined) {
26003         if (!checkSupportedPrefRank(prefRank)) { return; }
26004
26005         if (!(prefRank in rankSets)) {
26006           rankSets.prefRank = [u];
26007         } else {
26008           rankSets.prefRank.push(u);
26009         }
26010
26011         var newU = rankSets[prefRank];
26012         if (newU === undefined) {
26013           newU = rankSets[prefRank] = g.addNode(null, { originalNodes: [] });
26014           g.parent(newU, sg);
26015         }
26016
26017         redirectInEdges(g, u, newU, prefRank === 'min');
26018         redirectOutEdges(g, u, newU, prefRank === 'max');
26019
26020         // Save original node and remove it from reduced graph
26021         g.node(newU).originalNodes.push({ u: u, value: value, parent: sg });
26022         g.delNode(u);
26023       }
26024     });
26025
26026     addLightEdgesFromMinNode(g, sg, rankSets.min);
26027     addLightEdgesToMaxNode(g, sg, rankSets.max);
26028   }
26029
26030   dfs(null);
26031 };
26032
26033 function checkSupportedPrefRank(prefRank) {
26034   if (prefRank !== 'min' && prefRank !== 'max' && prefRank.indexOf('same_') !== 0) {
26035     console.error('Unsupported rank type: ' + prefRank);
26036     return false;
26037   }
26038   return true;
26039 }
26040
26041 function redirectInEdges(g, u, newU, reverse) {
26042   g.inEdges(u).forEach(function(e) {
26043     var origValue = g.edge(e),
26044         value;
26045     if (origValue.originalEdge) {
26046       value = origValue;
26047     } else {
26048       value =  {
26049         originalEdge: { e: e, u: g.source(e), v: g.target(e), value: origValue },
26050         minLen: g.edge(e).minLen
26051       };
26052     }
26053
26054     // Do not reverse edges for self-loops.
26055     if (origValue.selfLoop) {
26056       reverse = false;
26057     }
26058
26059     if (reverse) {
26060       // Ensure that all edges to min are reversed
26061       g.addEdge(null, newU, g.source(e), value);
26062       value.reversed = true;
26063     } else {
26064       g.addEdge(null, g.source(e), newU, value);
26065     }
26066   });
26067 }
26068
26069 function redirectOutEdges(g, u, newU, reverse) {
26070   g.outEdges(u).forEach(function(e) {
26071     var origValue = g.edge(e),
26072         value;
26073     if (origValue.originalEdge) {
26074       value = origValue;
26075     } else {
26076       value =  {
26077         originalEdge: { e: e, u: g.source(e), v: g.target(e), value: origValue },
26078         minLen: g.edge(e).minLen
26079       };
26080     }
26081
26082     // Do not reverse edges for self-loops.
26083     if (origValue.selfLoop) {
26084       reverse = false;
26085     }
26086
26087     if (reverse) {
26088       // Ensure that all edges from max are reversed
26089       g.addEdge(null, g.target(e), newU, value);
26090       value.reversed = true;
26091     } else {
26092       g.addEdge(null, newU, g.target(e), value);
26093     }
26094   });
26095 }
26096
26097 function addLightEdgesFromMinNode(g, sg, minNode) {
26098   if (minNode !== undefined) {
26099     g.children(sg).forEach(function(u) {
26100       // The dummy check ensures we don't add an edge if the node is involved
26101       // in a self loop or sideways edge.
26102       if (u !== minNode && !g.outEdges(minNode, u).length && !g.node(u).dummy) {
26103         g.addEdge(null, minNode, u, { minLen: 0 });
26104       }
26105     });
26106   }
26107 }
26108
26109 function addLightEdgesToMaxNode(g, sg, maxNode) {
26110   if (maxNode !== undefined) {
26111     g.children(sg).forEach(function(u) {
26112       // The dummy check ensures we don't add an edge if the node is involved
26113       // in a self loop or sideways edge.
26114       if (u !== maxNode && !g.outEdges(u, maxNode).length && !g.node(u).dummy) {
26115         g.addEdge(null, u, maxNode, { minLen: 0 });
26116       }
26117     });
26118   }
26119 }
26120
26121 /*
26122  * This function "relaxes" the constraints applied previously by the "apply"
26123  * function. It expands any nodes that were collapsed and assigns the rank of
26124  * the collapsed node to each of the expanded nodes. It also restores the
26125  * original edges and removes any dummy edges pointing at the collapsed nodes.
26126  *
26127  * Note that the process of removing collapsed nodes also removes dummy edges
26128  * automatically.
26129  */
26130 exports.relax = function(g) {
26131   // Save original edges
26132   var originalEdges = [];
26133   g.eachEdge(function(e, u, v, value) {
26134     var originalEdge = value.originalEdge;
26135     if (originalEdge) {
26136       originalEdges.push(originalEdge);
26137     }
26138   });
26139
26140   // Expand collapsed nodes
26141   g.eachNode(function(u, value) {
26142     var originalNodes = value.originalNodes;
26143     if (originalNodes) {
26144       originalNodes.forEach(function(originalNode) {
26145         originalNode.value.rank = value.rank;
26146         g.addNode(originalNode.u, originalNode.value);
26147         g.parent(originalNode.u, originalNode.parent);
26148       });
26149       g.delNode(u);
26150     }
26151   });
26152
26153   // Restore original edges
26154   originalEdges.forEach(function(edge) {
26155     g.addEdge(edge.e, edge.u, edge.v, edge.value);
26156   });
26157 };
26158
26159 },{}],13:[function(require,module,exports){
26160 /* jshint -W079 */
26161 var Set = require('cp-data').Set,
26162 /* jshint +W079 */
26163     Digraph = require('graphlib').Digraph,
26164     util = require('../util');
26165
26166 module.exports = feasibleTree;
26167
26168 /*
26169  * Given an acyclic graph with each node assigned a `rank` attribute, this
26170  * function constructs and returns a spanning tree. This function may reduce
26171  * the length of some edges from the initial rank assignment while maintaining
26172  * the `minLen` specified by each edge.
26173  *
26174  * Prerequisites:
26175  *
26176  * * The input graph is acyclic
26177  * * Each node in the input graph has an assigned `rank` attribute
26178  * * Each edge in the input graph has an assigned `minLen` attribute
26179  *
26180  * Outputs:
26181  *
26182  * A feasible spanning tree for the input graph (i.e. a spanning tree that
26183  * respects each graph edge's `minLen` attribute) represented as a Digraph with
26184  * a `root` attribute on graph.
26185  *
26186  * Nodes have the same id and value as that in the input graph.
26187  *
26188  * Edges in the tree have arbitrarily assigned ids. The attributes for edges
26189  * include `reversed`. `reversed` indicates that the edge is a
26190  * back edge in the input graph.
26191  */
26192 function feasibleTree(g) {
26193   var remaining = new Set(g.nodes()),
26194       tree = new Digraph();
26195
26196   if (remaining.size() === 1) {
26197     var root = g.nodes()[0];
26198     tree.addNode(root, {});
26199     tree.graph({ root: root });
26200     return tree;
26201   }
26202
26203   function addTightEdges(v) {
26204     var continueToScan = true;
26205     g.predecessors(v).forEach(function(u) {
26206       if (remaining.has(u) && !slack(g, u, v)) {
26207         if (remaining.has(v)) {
26208           tree.addNode(v, {});
26209           remaining.remove(v);
26210           tree.graph({ root: v });
26211         }
26212
26213         tree.addNode(u, {});
26214         tree.addEdge(null, u, v, { reversed: true });
26215         remaining.remove(u);
26216         addTightEdges(u);
26217         continueToScan = false;
26218       }
26219     });
26220
26221     g.successors(v).forEach(function(w)  {
26222       if (remaining.has(w) && !slack(g, v, w)) {
26223         if (remaining.has(v)) {
26224           tree.addNode(v, {});
26225           remaining.remove(v);
26226           tree.graph({ root: v });
26227         }
26228
26229         tree.addNode(w, {});
26230         tree.addEdge(null, v, w, {});
26231         remaining.remove(w);
26232         addTightEdges(w);
26233         continueToScan = false;
26234       }
26235     });
26236     return continueToScan;
26237   }
26238
26239   function createTightEdge() {
26240     var minSlack = Number.MAX_VALUE;
26241     remaining.keys().forEach(function(v) {
26242       g.predecessors(v).forEach(function(u) {
26243         if (!remaining.has(u)) {
26244           var edgeSlack = slack(g, u, v);
26245           if (Math.abs(edgeSlack) < Math.abs(minSlack)) {
26246             minSlack = -edgeSlack;
26247           }
26248         }
26249       });
26250
26251       g.successors(v).forEach(function(w) {
26252         if (!remaining.has(w)) {
26253           var edgeSlack = slack(g, v, w);
26254           if (Math.abs(edgeSlack) < Math.abs(minSlack)) {
26255             minSlack = edgeSlack;
26256           }
26257         }
26258       });
26259     });
26260
26261     tree.eachNode(function(u) { g.node(u).rank -= minSlack; });
26262   }
26263
26264   while (remaining.size()) {
26265     var nodesToSearch = !tree.order() ? remaining.keys() : tree.nodes();
26266     for (var i = 0, il = nodesToSearch.length;
26267          i < il && addTightEdges(nodesToSearch[i]);
26268          ++i);
26269     if (remaining.size()) {
26270       createTightEdge();
26271     }
26272   }
26273
26274   return tree;
26275 }
26276
26277 function slack(g, u, v) {
26278   var rankDiff = g.node(v).rank - g.node(u).rank;
26279   var maxMinLen = util.max(g.outEdges(u, v)
26280                             .map(function(e) { return g.edge(e).minLen; }));
26281   return rankDiff - maxMinLen;
26282 }
26283
26284 },{"../util":17,"cp-data":19,"graphlib":24}],14:[function(require,module,exports){
26285 var util = require('../util'),
26286     topsort = require('graphlib').alg.topsort;
26287
26288 module.exports = initRank;
26289
26290 /*
26291  * Assigns a `rank` attribute to each node in the input graph and ensures that
26292  * this rank respects the `minLen` attribute of incident edges.
26293  *
26294  * Prerequisites:
26295  *
26296  *  * The input graph must be acyclic
26297  *  * Each edge in the input graph must have an assigned 'minLen' attribute
26298  */
26299 function initRank(g) {
26300   var sorted = topsort(g);
26301
26302   sorted.forEach(function(u) {
26303     var inEdges = g.inEdges(u);
26304     if (inEdges.length === 0) {
26305       g.node(u).rank = 0;
26306       return;
26307     }
26308
26309     var minLens = inEdges.map(function(e) {
26310       return g.node(g.source(e)).rank + g.edge(e).minLen;
26311     });
26312     g.node(u).rank = util.max(minLens);
26313   });
26314 }
26315
26316 },{"../util":17,"graphlib":24}],15:[function(require,module,exports){
26317 module.exports = {
26318   slack: slack
26319 };
26320
26321 /*
26322  * A helper to calculate the slack between two nodes (`u` and `v`) given a
26323  * `minLen` constraint. The slack represents how much the distance between `u`
26324  * and `v` could shrink while maintaining the `minLen` constraint. If the value
26325  * is negative then the constraint is currently violated.
26326  *
26327   This function requires that `u` and `v` are in `graph` and they both have a
26328   `rank` attribute.
26329  */
26330 function slack(graph, u, v, minLen) {
26331   return Math.abs(graph.node(u).rank - graph.node(v).rank) - minLen;
26332 }
26333
26334 },{}],16:[function(require,module,exports){
26335 var util = require('../util'),
26336     rankUtil = require('./rankUtil');
26337
26338 module.exports = simplex;
26339
26340 function simplex(graph, spanningTree) {
26341   // The network simplex algorithm repeatedly replaces edges of
26342   // the spanning tree with negative cut values until no such
26343   // edge exists.
26344   initCutValues(graph, spanningTree);
26345   while (true) {
26346     var e = leaveEdge(spanningTree);
26347     if (e === null) break;
26348     var f = enterEdge(graph, spanningTree, e);
26349     exchange(graph, spanningTree, e, f);
26350   }
26351 }
26352
26353 /*
26354  * Set the cut values of edges in the spanning tree by a depth-first
26355  * postorder traversal.  The cut value corresponds to the cost, in
26356  * terms of a ranking's edge length sum, of lengthening an edge.
26357  * Negative cut values typically indicate edges that would yield a
26358  * smaller edge length sum if they were lengthened.
26359  */
26360 function initCutValues(graph, spanningTree) {
26361   computeLowLim(spanningTree);
26362
26363   spanningTree.eachEdge(function(id, u, v, treeValue) {
26364     treeValue.cutValue = 0;
26365   });
26366
26367   // Propagate cut values up the tree.
26368   function dfs(n) {
26369     var children = spanningTree.successors(n);
26370     for (var c in children) {
26371       var child = children[c];
26372       dfs(child);
26373     }
26374     if (n !== spanningTree.graph().root) {
26375       setCutValue(graph, spanningTree, n);
26376     }
26377   }
26378   dfs(spanningTree.graph().root);
26379 }
26380
26381 /*
26382  * Perform a DFS postorder traversal, labeling each node v with
26383  * its traversal order 'lim(v)' and the minimum traversal number
26384  * of any of its descendants 'low(v)'.  This provides an efficient
26385  * way to test whether u is an ancestor of v since
26386  * low(u) <= lim(v) <= lim(u) if and only if u is an ancestor.
26387  */
26388 function computeLowLim(tree) {
26389   var postOrderNum = 0;
26390   
26391   function dfs(n) {
26392     var children = tree.successors(n);
26393     var low = postOrderNum;
26394     for (var c in children) {
26395       var child = children[c];
26396       dfs(child);
26397       low = Math.min(low, tree.node(child).low);
26398     }
26399     tree.node(n).low = low;
26400     tree.node(n).lim = postOrderNum++;
26401   }
26402
26403   dfs(tree.graph().root);
26404 }
26405
26406 /*
26407  * To compute the cut value of the edge parent -> child, we consider
26408  * it and any other graph edges to or from the child.
26409  *          parent
26410  *             |
26411  *           child
26412  *          /      \
26413  *         u        v
26414  */
26415 function setCutValue(graph, tree, child) {
26416   var parentEdge = tree.inEdges(child)[0];
26417
26418   // List of child's children in the spanning tree.
26419   var grandchildren = [];
26420   var grandchildEdges = tree.outEdges(child);
26421   for (var gce in grandchildEdges) {
26422     grandchildren.push(tree.target(grandchildEdges[gce]));
26423   }
26424
26425   var cutValue = 0;
26426
26427   // TODO: Replace unit increment/decrement with edge weights.
26428   var E = 0;    // Edges from child to grandchild's subtree.
26429   var F = 0;    // Edges to child from grandchild's subtree.
26430   var G = 0;    // Edges from child to nodes outside of child's subtree.
26431   var H = 0;    // Edges from nodes outside of child's subtree to child.
26432
26433   // Consider all graph edges from child.
26434   var outEdges = graph.outEdges(child);
26435   var gc;
26436   for (var oe in outEdges) {
26437     var succ = graph.target(outEdges[oe]);
26438     for (gc in grandchildren) {
26439       if (inSubtree(tree, succ, grandchildren[gc])) {
26440         E++;
26441       }
26442     }
26443     if (!inSubtree(tree, succ, child)) {
26444       G++;
26445     }
26446   }
26447
26448   // Consider all graph edges to child.
26449   var inEdges = graph.inEdges(child);
26450   for (var ie in inEdges) {
26451     var pred = graph.source(inEdges[ie]);
26452     for (gc in grandchildren) {
26453       if (inSubtree(tree, pred, grandchildren[gc])) {
26454         F++;
26455       }
26456     }
26457     if (!inSubtree(tree, pred, child)) {
26458       H++;
26459     }
26460   }
26461
26462   // Contributions depend on the alignment of the parent -> child edge
26463   // and the child -> u or v edges.
26464   var grandchildCutSum = 0;
26465   for (gc in grandchildren) {
26466     var cv = tree.edge(grandchildEdges[gc]).cutValue;
26467     if (!tree.edge(grandchildEdges[gc]).reversed) {
26468       grandchildCutSum += cv;
26469     } else {
26470       grandchildCutSum -= cv;
26471     }
26472   }
26473
26474   if (!tree.edge(parentEdge).reversed) {
26475     cutValue += grandchildCutSum - E + F - G + H;
26476   } else {
26477     cutValue -= grandchildCutSum - E + F - G + H;
26478   }
26479
26480   tree.edge(parentEdge).cutValue = cutValue;
26481 }
26482
26483 /*
26484  * Return whether n is a node in the subtree with the given
26485  * root.
26486  */
26487 function inSubtree(tree, n, root) {
26488   return (tree.node(root).low <= tree.node(n).lim &&
26489           tree.node(n).lim <= tree.node(root).lim);
26490 }
26491
26492 /*
26493  * Return an edge from the tree with a negative cut value, or null if there
26494  * is none.
26495  */
26496 function leaveEdge(tree) {
26497   var edges = tree.edges();
26498   for (var n in edges) {
26499     var e = edges[n];
26500     var treeValue = tree.edge(e);
26501     if (treeValue.cutValue < 0) {
26502       return e;
26503     }
26504   }
26505   return null;
26506 }
26507
26508 /*
26509  * The edge e should be an edge in the tree, with an underlying edge
26510  * in the graph, with a negative cut value.  Of the two nodes incident
26511  * on the edge, take the lower one.  enterEdge returns an edge with
26512  * minimum slack going from outside of that node's subtree to inside
26513  * of that node's subtree.
26514  */
26515 function enterEdge(graph, tree, e) {
26516   var source = tree.source(e);
26517   var target = tree.target(e);
26518   var lower = tree.node(target).lim < tree.node(source).lim ? target : source;
26519
26520   // Is the tree edge aligned with the graph edge?
26521   var aligned = !tree.edge(e).reversed;
26522
26523   var minSlack = Number.POSITIVE_INFINITY;
26524   var minSlackEdge;
26525   if (aligned) {
26526     graph.eachEdge(function(id, u, v, value) {
26527       if (id !== e && inSubtree(tree, u, lower) && !inSubtree(tree, v, lower)) {
26528         var slack = rankUtil.slack(graph, u, v, value.minLen);
26529         if (slack < minSlack) {
26530           minSlack = slack;
26531           minSlackEdge = id;
26532         }
26533       }
26534     });
26535   } else {
26536     graph.eachEdge(function(id, u, v, value) {
26537       if (id !== e && !inSubtree(tree, u, lower) && inSubtree(tree, v, lower)) {
26538         var slack = rankUtil.slack(graph, u, v, value.minLen);
26539         if (slack < minSlack) {
26540           minSlack = slack;
26541           minSlackEdge = id;
26542         }
26543       }
26544     });
26545   }
26546
26547   if (minSlackEdge === undefined) {
26548     var outside = [];
26549     var inside = [];
26550     graph.eachNode(function(id) {
26551       if (!inSubtree(tree, id, lower)) {
26552         outside.push(id);
26553       } else {
26554         inside.push(id);
26555       }
26556     });
26557     throw new Error('No edge found from outside of tree to inside');
26558   }
26559
26560   return minSlackEdge;
26561 }
26562
26563 /*
26564  * Replace edge e with edge f in the tree, recalculating the tree root,
26565  * the nodes' low and lim properties and the edges' cut values.
26566  */
26567 function exchange(graph, tree, e, f) {
26568   tree.delEdge(e);
26569   var source = graph.source(f);
26570   var target = graph.target(f);
26571
26572   // Redirect edges so that target is the root of its subtree.
26573   function redirect(v) {
26574     var edges = tree.inEdges(v);
26575     for (var i in edges) {
26576       var e = edges[i];
26577       var u = tree.source(e);
26578       var value = tree.edge(e);
26579       redirect(u);
26580       tree.delEdge(e);
26581       value.reversed = !value.reversed;
26582       tree.addEdge(e, v, u, value);
26583     }
26584   }
26585
26586   redirect(target);
26587
26588   var root = source;
26589   var edges = tree.inEdges(root);
26590   while (edges.length > 0) {
26591     root = tree.source(edges[0]);
26592     edges = tree.inEdges(root);
26593   }
26594
26595   tree.graph().root = root;
26596
26597   tree.addEdge(null, source, target, {cutValue: 0});
26598
26599   initCutValues(graph, tree);
26600
26601   adjustRanks(graph, tree);
26602 }
26603
26604 /*
26605  * Reset the ranks of all nodes based on the current spanning tree.
26606  * The rank of the tree's root remains unchanged, while all other
26607  * nodes are set to the sum of minimum length constraints along
26608  * the path from the root.
26609  */
26610 function adjustRanks(graph, tree) {
26611   function dfs(p) {
26612     var children = tree.successors(p);
26613     children.forEach(function(c) {
26614       var minLen = minimumLength(graph, p, c);
26615       graph.node(c).rank = graph.node(p).rank + minLen;
26616       dfs(c);
26617     });
26618   }
26619
26620   dfs(tree.graph().root);
26621 }
26622
26623 /*
26624  * If u and v are connected by some edges in the graph, return the
26625  * minimum length of those edges, as a positive number if v succeeds
26626  * u and as a negative number if v precedes u.
26627  */
26628 function minimumLength(graph, u, v) {
26629   var outEdges = graph.outEdges(u, v);
26630   if (outEdges.length > 0) {
26631     return util.max(outEdges.map(function(e) {
26632       return graph.edge(e).minLen;
26633     }));
26634   }
26635
26636   var inEdges = graph.inEdges(u, v);
26637   if (inEdges.length > 0) {
26638     return -util.max(inEdges.map(function(e) {
26639       return graph.edge(e).minLen;
26640     }));
26641   }
26642 }
26643
26644 },{"../util":17,"./rankUtil":15}],17:[function(require,module,exports){
26645 /*
26646  * Returns the smallest value in the array.
26647  */
26648 exports.min = function(values) {
26649   return Math.min.apply(Math, values);
26650 };
26651
26652 /*
26653  * Returns the largest value in the array.
26654  */
26655 exports.max = function(values) {
26656   return Math.max.apply(Math, values);
26657 };
26658
26659 /*
26660  * Returns `true` only if `f(x)` is `true` for all `x` in `xs`. Otherwise
26661  * returns `false`. This function will return immediately if it finds a
26662  * case where `f(x)` does not hold.
26663  */
26664 exports.all = function(xs, f) {
26665   for (var i = 0; i < xs.length; ++i) {
26666     if (!f(xs[i])) {
26667       return false;
26668     }
26669   }
26670   return true;
26671 };
26672
26673 /*
26674  * Accumulates the sum of elements in the given array using the `+` operator.
26675  */
26676 exports.sum = function(values) {
26677   return values.reduce(function(acc, x) { return acc + x; }, 0);
26678 };
26679
26680 /*
26681  * Returns an array of all values in the given object.
26682  */
26683 exports.values = function(obj) {
26684   return Object.keys(obj).map(function(k) { return obj[k]; });
26685 };
26686
26687 exports.shuffle = function(array) {
26688   for (i = array.length - 1; i > 0; --i) {
26689     var j = Math.floor(Math.random() * (i + 1));
26690     var aj = array[j];
26691     array[j] = array[i];
26692     array[i] = aj;
26693   }
26694 };
26695
26696 exports.propertyAccessor = function(self, config, field, setHook) {
26697   return function(x) {
26698     if (!arguments.length) return config[field];
26699     config[field] = x;
26700     if (setHook) setHook(x);
26701     return self;
26702   };
26703 };
26704
26705 /*
26706  * Given a layered, directed graph with `rank` and `order` node attributes,
26707  * this function returns an array of ordered ranks. Each rank contains an array
26708  * of the ids of the nodes in that rank in the order specified by the `order`
26709  * attribute.
26710  */
26711 exports.ordering = function(g) {
26712   var ordering = [];
26713   g.eachNode(function(u, value) {
26714     var rank = ordering[value.rank] || (ordering[value.rank] = []);
26715     rank[value.order] = u;
26716   });
26717   return ordering;
26718 };
26719
26720 /*
26721  * A filter that can be used with `filterNodes` to get a graph that only
26722  * includes nodes that do not contain others nodes.
26723  */
26724 exports.filterNonSubgraphs = function(g) {
26725   return function(u) {
26726     return g.children(u).length === 0;
26727   };
26728 };
26729
26730 /*
26731  * Returns a new function that wraps `func` with a timer. The wrapper logs the
26732  * time it takes to execute the function.
26733  *
26734  * The timer will be enabled provided `log.level >= 1`.
26735  */
26736 function time(name, func) {
26737   return function() {
26738     var start = new Date().getTime();
26739     try {
26740       return func.apply(null, arguments);
26741     } finally {
26742       log(1, name + ' time: ' + (new Date().getTime() - start) + 'ms');
26743     }
26744   };
26745 }
26746 time.enabled = false;
26747
26748 exports.time = time;
26749
26750 /*
26751  * A global logger with the specification `log(level, message, ...)` that
26752  * will log a message to the console if `log.level >= level`.
26753  */
26754 function log(level) {
26755   if (log.level >= level) {
26756     console.log.apply(console, Array.prototype.slice.call(arguments, 1));
26757   }
26758 }
26759 log.level = 0;
26760
26761 exports.log = log;
26762
26763 },{}],18:[function(require,module,exports){
26764 module.exports = '0.4.5';
26765
26766 },{}],19:[function(require,module,exports){
26767 exports.Set = require('./lib/Set');
26768 exports.PriorityQueue = require('./lib/PriorityQueue');
26769 exports.version = require('./lib/version');
26770
26771 },{"./lib/PriorityQueue":20,"./lib/Set":21,"./lib/version":23}],20:[function(require,module,exports){
26772 module.exports = PriorityQueue;
26773
26774 /**
26775  * A min-priority queue data structure. This algorithm is derived from Cormen,
26776  * et al., "Introduction to Algorithms". The basic idea of a min-priority
26777  * queue is that you can efficiently (in O(1) time) get the smallest key in
26778  * the queue. Adding and removing elements takes O(log n) time. A key can
26779  * have its priority decreased in O(log n) time.
26780  */
26781 function PriorityQueue() {
26782   this._arr = [];
26783   this._keyIndices = {};
26784 }
26785
26786 /**
26787  * Returns the number of elements in the queue. Takes `O(1)` time.
26788  */
26789 PriorityQueue.prototype.size = function() {
26790   return this._arr.length;
26791 };
26792
26793 /**
26794  * Returns the keys that are in the queue. Takes `O(n)` time.
26795  */
26796 PriorityQueue.prototype.keys = function() {
26797   return this._arr.map(function(x) { return x.key; });
26798 };
26799
26800 /**
26801  * Returns `true` if **key** is in the queue and `false` if not.
26802  */
26803 PriorityQueue.prototype.has = function(key) {
26804   return key in this._keyIndices;
26805 };
26806
26807 /**
26808  * Returns the priority for **key**. If **key** is not present in the queue
26809  * then this function returns `undefined`. Takes `O(1)` time.
26810  *
26811  * @param {Object} key
26812  */
26813 PriorityQueue.prototype.priority = function(key) {
26814   var index = this._keyIndices[key];
26815   if (index !== undefined) {
26816     return this._arr[index].priority;
26817   }
26818 };
26819
26820 /**
26821  * Returns the key for the minimum element in this queue. If the queue is
26822  * empty this function throws an Error. Takes `O(1)` time.
26823  */
26824 PriorityQueue.prototype.min = function() {
26825   if (this.size() === 0) {
26826     throw new Error("Queue underflow");
26827   }
26828   return this._arr[0].key;
26829 };
26830
26831 /**
26832  * Inserts a new key into the priority queue. If the key already exists in
26833  * the queue this function returns `false`; otherwise it will return `true`.
26834  * Takes `O(n)` time.
26835  *
26836  * @param {Object} key the key to add
26837  * @param {Number} priority the initial priority for the key
26838  */
26839 PriorityQueue.prototype.add = function(key, priority) {
26840   var keyIndices = this._keyIndices;
26841   if (!(key in keyIndices)) {
26842     var arr = this._arr;
26843     var index = arr.length;
26844     keyIndices[key] = index;
26845     arr.push({key: key, priority: priority});
26846     this._decrease(index);
26847     return true;
26848   }
26849   return false;
26850 };
26851
26852 /**
26853  * Removes and returns the smallest key in the queue. Takes `O(log n)` time.
26854  */
26855 PriorityQueue.prototype.removeMin = function() {
26856   this._swap(0, this._arr.length - 1);
26857   var min = this._arr.pop();
26858   delete this._keyIndices[min.key];
26859   this._heapify(0);
26860   return min.key;
26861 };
26862
26863 /**
26864  * Decreases the priority for **key** to **priority**. If the new priority is
26865  * greater than the previous priority, this function will throw an Error.
26866  *
26867  * @param {Object} key the key for which to raise priority
26868  * @param {Number} priority the new priority for the key
26869  */
26870 PriorityQueue.prototype.decrease = function(key, priority) {
26871   var index = this._keyIndices[key];
26872   if (priority > this._arr[index].priority) {
26873     throw new Error("New priority is greater than current priority. " +
26874         "Key: " + key + " Old: " + this._arr[index].priority + " New: " + priority);
26875   }
26876   this._arr[index].priority = priority;
26877   this._decrease(index);
26878 };
26879
26880 PriorityQueue.prototype._heapify = function(i) {
26881   var arr = this._arr;
26882   var l = 2 * i,
26883       r = l + 1,
26884       largest = i;
26885   if (l < arr.length) {
26886     largest = arr[l].priority < arr[largest].priority ? l : largest;
26887     if (r < arr.length) {
26888       largest = arr[r].priority < arr[largest].priority ? r : largest;
26889     }
26890     if (largest !== i) {
26891       this._swap(i, largest);
26892       this._heapify(largest);
26893     }
26894   }
26895 };
26896
26897 PriorityQueue.prototype._decrease = function(index) {
26898   var arr = this._arr;
26899   var priority = arr[index].priority;
26900   var parent;
26901   while (index !== 0) {
26902     parent = index >> 1;
26903     if (arr[parent].priority < priority) {
26904       break;
26905     }
26906     this._swap(index, parent);
26907     index = parent;
26908   }
26909 };
26910
26911 PriorityQueue.prototype._swap = function(i, j) {
26912   var arr = this._arr;
26913   var keyIndices = this._keyIndices;
26914   var origArrI = arr[i];
26915   var origArrJ = arr[j];
26916   arr[i] = origArrJ;
26917   arr[j] = origArrI;
26918   keyIndices[origArrJ.key] = i;
26919   keyIndices[origArrI.key] = j;
26920 };
26921
26922 },{}],21:[function(require,module,exports){
26923 var util = require('./util');
26924
26925 module.exports = Set;
26926
26927 /**
26928  * Constructs a new Set with an optional set of `initialKeys`.
26929  *
26930  * It is important to note that keys are coerced to String for most purposes
26931  * with this object, similar to the behavior of JavaScript's Object. For
26932  * example, the following will add only one key:
26933  *
26934  *     var s = new Set();
26935  *     s.add(1);
26936  *     s.add("1");
26937  *
26938  * However, the type of the key is preserved internally so that `keys` returns
26939  * the original key set uncoerced. For the above example, `keys` would return
26940  * `[1]`.
26941  */
26942 function Set(initialKeys) {
26943   this._size = 0;
26944   this._keys = {};
26945
26946   if (initialKeys) {
26947     for (var i = 0, il = initialKeys.length; i < il; ++i) {
26948       this.add(initialKeys[i]);
26949     }
26950   }
26951 }
26952
26953 /**
26954  * Returns a new Set that represents the set intersection of the array of given
26955  * sets.
26956  */
26957 Set.intersect = function(sets) {
26958   if (sets.length === 0) {
26959     return new Set();
26960   }
26961
26962   var result = new Set(!util.isArray(sets[0]) ? sets[0].keys() : sets[0]);
26963   for (var i = 1, il = sets.length; i < il; ++i) {
26964     var resultKeys = result.keys(),
26965         other = !util.isArray(sets[i]) ? sets[i] : new Set(sets[i]);
26966     for (var j = 0, jl = resultKeys.length; j < jl; ++j) {
26967       var key = resultKeys[j];
26968       if (!other.has(key)) {
26969         result.remove(key);
26970       }
26971     }
26972   }
26973
26974   return result;
26975 };
26976
26977 /**
26978  * Returns a new Set that represents the set union of the array of given sets.
26979  */
26980 Set.union = function(sets) {
26981   var totalElems = util.reduce(sets, function(lhs, rhs) {
26982     return lhs + (rhs.size ? rhs.size() : rhs.length);
26983   }, 0);
26984   var arr = new Array(totalElems);
26985
26986   var k = 0;
26987   for (var i = 0, il = sets.length; i < il; ++i) {
26988     var cur = sets[i],
26989         keys = !util.isArray(cur) ? cur.keys() : cur;
26990     for (var j = 0, jl = keys.length; j < jl; ++j) {
26991       arr[k++] = keys[j];
26992     }
26993   }
26994
26995   return new Set(arr);
26996 };
26997
26998 /**
26999  * Returns the size of this set in `O(1)` time.
27000  */
27001 Set.prototype.size = function() {
27002   return this._size;
27003 };
27004
27005 /**
27006  * Returns the keys in this set. Takes `O(n)` time.
27007  */
27008 Set.prototype.keys = function() {
27009   return values(this._keys);
27010 };
27011
27012 /**
27013  * Tests if a key is present in this Set. Returns `true` if it is and `false`
27014  * if not. Takes `O(1)` time.
27015  */
27016 Set.prototype.has = function(key) {
27017   return key in this._keys;
27018 };
27019
27020 /**
27021  * Adds a new key to this Set if it is not already present. Returns `true` if
27022  * the key was added and `false` if it was already present. Takes `O(1)` time.
27023  */
27024 Set.prototype.add = function(key) {
27025   if (!(key in this._keys)) {
27026     this._keys[key] = key;
27027     ++this._size;
27028     return true;
27029   }
27030   return false;
27031 };
27032
27033 /**
27034  * Removes a key from this Set. If the key was removed this function returns
27035  * `true`. If not, it returns `false`. Takes `O(1)` time.
27036  */
27037 Set.prototype.remove = function(key) {
27038   if (key in this._keys) {
27039     delete this._keys[key];
27040     --this._size;
27041     return true;
27042   }
27043   return false;
27044 };
27045
27046 /*
27047  * Returns an array of all values for properties of **o**.
27048  */
27049 function values(o) {
27050   var ks = Object.keys(o),
27051       len = ks.length,
27052       result = new Array(len),
27053       i;
27054   for (i = 0; i < len; ++i) {
27055     result[i] = o[ks[i]];
27056   }
27057   return result;
27058 }
27059
27060 },{"./util":22}],22:[function(require,module,exports){
27061 /*
27062  * This polyfill comes from
27063  * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray
27064  */
27065 if(!Array.isArray) {
27066   exports.isArray = function (vArg) {
27067     return Object.prototype.toString.call(vArg) === '[object Array]';
27068   };
27069 } else {
27070   exports.isArray = Array.isArray;
27071 }
27072
27073 /*
27074  * Slightly adapted polyfill from
27075  * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
27076  */
27077 if ('function' !== typeof Array.prototype.reduce) {
27078   exports.reduce = function(array, callback, opt_initialValue) {
27079     'use strict';
27080     if (null === array || 'undefined' === typeof array) {
27081       // At the moment all modern browsers, that support strict mode, have
27082       // native implementation of Array.prototype.reduce. For instance, IE8
27083       // does not support strict mode, so this check is actually useless.
27084       throw new TypeError(
27085           'Array.prototype.reduce called on null or undefined');
27086     }
27087     if ('function' !== typeof callback) {
27088       throw new TypeError(callback + ' is not a function');
27089     }
27090     var index, value,
27091         length = array.length >>> 0,
27092         isValueSet = false;
27093     if (1 < arguments.length) {
27094       value = opt_initialValue;
27095       isValueSet = true;
27096     }
27097     for (index = 0; length > index; ++index) {
27098       if (array.hasOwnProperty(index)) {
27099         if (isValueSet) {
27100           value = callback(value, array[index], index, array);
27101         }
27102         else {
27103           value = array[index];
27104           isValueSet = true;
27105         }
27106       }
27107     }
27108     if (!isValueSet) {
27109       throw new TypeError('Reduce of empty array with no initial value');
27110     }
27111     return value;
27112   };
27113 } else {
27114   exports.reduce = function(array, callback, opt_initialValue) {
27115     return array.reduce(callback, opt_initialValue);
27116   };
27117 }
27118
27119 },{}],23:[function(require,module,exports){
27120 module.exports = '1.1.3';
27121
27122 },{}],24:[function(require,module,exports){
27123 exports.Graph = require("./lib/Graph");
27124 exports.Digraph = require("./lib/Digraph");
27125 exports.CGraph = require("./lib/CGraph");
27126 exports.CDigraph = require("./lib/CDigraph");
27127 require("./lib/graph-converters");
27128
27129 exports.alg = {
27130   isAcyclic: require("./lib/alg/isAcyclic"),
27131   components: require("./lib/alg/components"),
27132   dijkstra: require("./lib/alg/dijkstra"),
27133   dijkstraAll: require("./lib/alg/dijkstraAll"),
27134   findCycles: require("./lib/alg/findCycles"),
27135   floydWarshall: require("./lib/alg/floydWarshall"),
27136   postorder: require("./lib/alg/postorder"),
27137   preorder: require("./lib/alg/preorder"),
27138   prim: require("./lib/alg/prim"),
27139   tarjan: require("./lib/alg/tarjan"),
27140   topsort: require("./lib/alg/topsort")
27141 };
27142
27143 exports.converter = {
27144   json: require("./lib/converter/json.js")
27145 };
27146
27147 var filter = require("./lib/filter");
27148 exports.filter = {
27149   all: filter.all,
27150   nodesFromList: filter.nodesFromList
27151 };
27152
27153 exports.version = require("./lib/version");
27154
27155 },{"./lib/CDigraph":26,"./lib/CGraph":27,"./lib/Digraph":28,"./lib/Graph":29,"./lib/alg/components":30,"./lib/alg/dijkstra":31,"./lib/alg/dijkstraAll":32,"./lib/alg/findCycles":33,"./lib/alg/floydWarshall":34,"./lib/alg/isAcyclic":35,"./lib/alg/postorder":36,"./lib/alg/preorder":37,"./lib/alg/prim":38,"./lib/alg/tarjan":39,"./lib/alg/topsort":40,"./lib/converter/json.js":42,"./lib/filter":43,"./lib/graph-converters":44,"./lib/version":46}],25:[function(require,module,exports){
27156 /* jshint -W079 */
27157 var Set = require("cp-data").Set;
27158 /* jshint +W079 */
27159
27160 module.exports = BaseGraph;
27161
27162 function BaseGraph() {
27163   // The value assigned to the graph itself.
27164   this._value = undefined;
27165
27166   // Map of node id -> { id, value }
27167   this._nodes = {};
27168
27169   // Map of edge id -> { id, u, v, value }
27170   this._edges = {};
27171
27172   // Used to generate a unique id in the graph
27173   this._nextId = 0;
27174 }
27175
27176 // Number of nodes
27177 BaseGraph.prototype.order = function() {
27178   return Object.keys(this._nodes).length;
27179 };
27180
27181 // Number of edges
27182 BaseGraph.prototype.size = function() {
27183   return Object.keys(this._edges).length;
27184 };
27185
27186 // Accessor for graph level value
27187 BaseGraph.prototype.graph = function(value) {
27188   if (arguments.length === 0) {
27189     return this._value;
27190   }
27191   this._value = value;
27192 };
27193
27194 BaseGraph.prototype.hasNode = function(u) {
27195   return u in this._nodes;
27196 };
27197
27198 BaseGraph.prototype.node = function(u, value) {
27199   var node = this._strictGetNode(u);
27200   if (arguments.length === 1) {
27201     return node.value;
27202   }
27203   node.value = value;
27204 };
27205
27206 BaseGraph.prototype.nodes = function() {
27207   var nodes = [];
27208   this.eachNode(function(id) { nodes.push(id); });
27209   return nodes;
27210 };
27211
27212 BaseGraph.prototype.eachNode = function(func) {
27213   for (var k in this._nodes) {
27214     var node = this._nodes[k];
27215     func(node.id, node.value);
27216   }
27217 };
27218
27219 BaseGraph.prototype.hasEdge = function(e) {
27220   return e in this._edges;
27221 };
27222
27223 BaseGraph.prototype.edge = function(e, value) {
27224   var edge = this._strictGetEdge(e);
27225   if (arguments.length === 1) {
27226     return edge.value;
27227   }
27228   edge.value = value;
27229 };
27230
27231 BaseGraph.prototype.edges = function() {
27232   var es = [];
27233   this.eachEdge(function(id) { es.push(id); });
27234   return es;
27235 };
27236
27237 BaseGraph.prototype.eachEdge = function(func) {
27238   for (var k in this._edges) {
27239     var edge = this._edges[k];
27240     func(edge.id, edge.u, edge.v, edge.value);
27241   }
27242 };
27243
27244 BaseGraph.prototype.incidentNodes = function(e) {
27245   var edge = this._strictGetEdge(e);
27246   return [edge.u, edge.v];
27247 };
27248
27249 BaseGraph.prototype.addNode = function(u, value) {
27250   if (u === undefined || u === null) {
27251     do {
27252       u = "_" + (++this._nextId);
27253     } while (this.hasNode(u));
27254   } else if (this.hasNode(u)) {
27255     throw new Error("Graph already has node '" + u + "'");
27256   }
27257   this._nodes[u] = { id: u, value: value };
27258   return u;
27259 };
27260
27261 BaseGraph.prototype.delNode = function(u) {
27262   this._strictGetNode(u);
27263   this.incidentEdges(u).forEach(function(e) { this.delEdge(e); }, this);
27264   delete this._nodes[u];
27265 };
27266
27267 // inMap and outMap are opposite sides of an incidence map. For example, for
27268 // Graph these would both come from the _incidentEdges map, while for Digraph
27269 // they would come from _inEdges and _outEdges.
27270 BaseGraph.prototype._addEdge = function(e, u, v, value, inMap, outMap) {
27271   this._strictGetNode(u);
27272   this._strictGetNode(v);
27273
27274   if (e === undefined || e === null) {
27275     do {
27276       e = "_" + (++this._nextId);
27277     } while (this.hasEdge(e));
27278   }
27279   else if (this.hasEdge(e)) {
27280     throw new Error("Graph already has edge '" + e + "'");
27281   }
27282
27283   this._edges[e] = { id: e, u: u, v: v, value: value };
27284   addEdgeToMap(inMap[v], u, e);
27285   addEdgeToMap(outMap[u], v, e);
27286
27287   return e;
27288 };
27289
27290 // See note for _addEdge regarding inMap and outMap.
27291 BaseGraph.prototype._delEdge = function(e, inMap, outMap) {
27292   var edge = this._strictGetEdge(e);
27293   delEdgeFromMap(inMap[edge.v], edge.u, e);
27294   delEdgeFromMap(outMap[edge.u], edge.v, e);
27295   delete this._edges[e];
27296 };
27297
27298 BaseGraph.prototype.copy = function() {
27299   var copy = new this.constructor();
27300   copy.graph(this.graph());
27301   this.eachNode(function(u, value) { copy.addNode(u, value); });
27302   this.eachEdge(function(e, u, v, value) { copy.addEdge(e, u, v, value); });
27303   copy._nextId = this._nextId;
27304   return copy;
27305 };
27306
27307 BaseGraph.prototype.filterNodes = function(filter) {
27308   var copy = new this.constructor();
27309   copy.graph(this.graph());
27310   this.eachNode(function(u, value) {
27311     if (filter(u)) {
27312       copy.addNode(u, value);
27313     }
27314   });
27315   this.eachEdge(function(e, u, v, value) {
27316     if (copy.hasNode(u) && copy.hasNode(v)) {
27317       copy.addEdge(e, u, v, value);
27318     }
27319   });
27320   return copy;
27321 };
27322
27323 BaseGraph.prototype._strictGetNode = function(u) {
27324   var node = this._nodes[u];
27325   if (node === undefined) {
27326     throw new Error("Node '" + u + "' is not in graph");
27327   }
27328   return node;
27329 };
27330
27331 BaseGraph.prototype._strictGetEdge = function(e) {
27332   var edge = this._edges[e];
27333   if (edge === undefined) {
27334     throw new Error("Edge '" + e + "' is not in graph");
27335   }
27336   return edge;
27337 };
27338
27339 function addEdgeToMap(map, v, e) {
27340   (map[v] || (map[v] = new Set())).add(e);
27341 }
27342
27343 function delEdgeFromMap(map, v, e) {
27344   var vEntry = map[v];
27345   vEntry.remove(e);
27346   if (vEntry.size() === 0) {
27347     delete map[v];
27348   }
27349 }
27350
27351
27352 },{"cp-data":19}],26:[function(require,module,exports){
27353 var Digraph = require("./Digraph"),
27354     compoundify = require("./compoundify");
27355
27356 var CDigraph = compoundify(Digraph);
27357
27358 module.exports = CDigraph;
27359
27360 CDigraph.fromDigraph = function(src) {
27361   var g = new CDigraph(),
27362       graphValue = src.graph();
27363
27364   if (graphValue !== undefined) {
27365     g.graph(graphValue);
27366   }
27367
27368   src.eachNode(function(u, value) {
27369     if (value === undefined) {
27370       g.addNode(u);
27371     } else {
27372       g.addNode(u, value);
27373     }
27374   });
27375   src.eachEdge(function(e, u, v, value) {
27376     if (value === undefined) {
27377       g.addEdge(null, u, v);
27378     } else {
27379       g.addEdge(null, u, v, value);
27380     }
27381   });
27382   return g;
27383 };
27384
27385 CDigraph.prototype.toString = function() {
27386   return "CDigraph " + JSON.stringify(this, null, 2);
27387 };
27388
27389 },{"./Digraph":28,"./compoundify":41}],27:[function(require,module,exports){
27390 var Graph = require("./Graph"),
27391     compoundify = require("./compoundify");
27392
27393 var CGraph = compoundify(Graph);
27394
27395 module.exports = CGraph;
27396
27397 CGraph.fromGraph = function(src) {
27398   var g = new CGraph(),
27399       graphValue = src.graph();
27400
27401   if (graphValue !== undefined) {
27402     g.graph(graphValue);
27403   }
27404
27405   src.eachNode(function(u, value) {
27406     if (value === undefined) {
27407       g.addNode(u);
27408     } else {
27409       g.addNode(u, value);
27410     }
27411   });
27412   src.eachEdge(function(e, u, v, value) {
27413     if (value === undefined) {
27414       g.addEdge(null, u, v);
27415     } else {
27416       g.addEdge(null, u, v, value);
27417     }
27418   });
27419   return g;
27420 };
27421
27422 CGraph.prototype.toString = function() {
27423   return "CGraph " + JSON.stringify(this, null, 2);
27424 };
27425
27426 },{"./Graph":29,"./compoundify":41}],28:[function(require,module,exports){
27427 /*
27428  * This file is organized with in the following order:
27429  *
27430  * Exports
27431  * Graph constructors
27432  * Graph queries (e.g. nodes(), edges()
27433  * Graph mutators
27434  * Helper functions
27435  */
27436
27437 var util = require("./util"),
27438     BaseGraph = require("./BaseGraph"),
27439 /* jshint -W079 */
27440     Set = require("cp-data").Set;
27441 /* jshint +W079 */
27442
27443 module.exports = Digraph;
27444
27445 /*
27446  * Constructor to create a new directed multi-graph.
27447  */
27448 function Digraph() {
27449   BaseGraph.call(this);
27450
27451   /*! Map of sourceId -> {targetId -> Set of edge ids} */
27452   this._inEdges = {};
27453
27454   /*! Map of targetId -> {sourceId -> Set of edge ids} */
27455   this._outEdges = {};
27456 }
27457
27458 Digraph.prototype = new BaseGraph();
27459 Digraph.prototype.constructor = Digraph;
27460
27461 /*
27462  * Always returns `true`.
27463  */
27464 Digraph.prototype.isDirected = function() {
27465   return true;
27466 };
27467
27468 /*
27469  * Returns all successors of the node with the id `u`. That is, all nodes
27470  * that have the node `u` as their source are returned.
27471  * 
27472  * If no node `u` exists in the graph this function throws an Error.
27473  *
27474  * @param {String} u a node id
27475  */
27476 Digraph.prototype.successors = function(u) {
27477   this._strictGetNode(u);
27478   return Object.keys(this._outEdges[u])
27479                .map(function(v) { return this._nodes[v].id; }, this);
27480 };
27481
27482 /*
27483  * Returns all predecessors of the node with the id `u`. That is, all nodes
27484  * that have the node `u` as their target are returned.
27485  * 
27486  * If no node `u` exists in the graph this function throws an Error.
27487  *
27488  * @param {String} u a node id
27489  */
27490 Digraph.prototype.predecessors = function(u) {
27491   this._strictGetNode(u);
27492   return Object.keys(this._inEdges[u])
27493                .map(function(v) { return this._nodes[v].id; }, this);
27494 };
27495
27496 /*
27497  * Returns all nodes that are adjacent to the node with the id `u`. In other
27498  * words, this function returns the set of all successors and predecessors of
27499  * node `u`.
27500  *
27501  * @param {String} u a node id
27502  */
27503 Digraph.prototype.neighbors = function(u) {
27504   return Set.union([this.successors(u), this.predecessors(u)]).keys();
27505 };
27506
27507 /*
27508  * Returns all nodes in the graph that have no in-edges.
27509  */
27510 Digraph.prototype.sources = function() {
27511   var self = this;
27512   return this._filterNodes(function(u) {
27513     // This could have better space characteristics if we had an inDegree function.
27514     return self.inEdges(u).length === 0;
27515   });
27516 };
27517
27518 /*
27519  * Returns all nodes in the graph that have no out-edges.
27520  */
27521 Digraph.prototype.sinks = function() {
27522   var self = this;
27523   return this._filterNodes(function(u) {
27524     // This could have better space characteristics if we have an outDegree function.
27525     return self.outEdges(u).length === 0;
27526   });
27527 };
27528
27529 /*
27530  * Returns the source node incident on the edge identified by the id `e`. If no
27531  * such edge exists in the graph this function throws an Error.
27532  *
27533  * @param {String} e an edge id
27534  */
27535 Digraph.prototype.source = function(e) {
27536   return this._strictGetEdge(e).u;
27537 };
27538
27539 /*
27540  * Returns the target node incident on the edge identified by the id `e`. If no
27541  * such edge exists in the graph this function throws an Error.
27542  *
27543  * @param {String} e an edge id
27544  */
27545 Digraph.prototype.target = function(e) {
27546   return this._strictGetEdge(e).v;
27547 };
27548
27549 /*
27550  * Returns an array of ids for all edges in the graph that have the node
27551  * `target` as their target. If the node `target` is not in the graph this
27552  * function raises an Error.
27553  *
27554  * Optionally a `source` node can also be specified. This causes the results
27555  * to be filtered such that only edges from `source` to `target` are included.
27556  * If the node `source` is specified but is not in the graph then this function
27557  * raises an Error.
27558  *
27559  * @param {String} target the target node id
27560  * @param {String} [source] an optional source node id
27561  */
27562 Digraph.prototype.inEdges = function(target, source) {
27563   this._strictGetNode(target);
27564   var results = Set.union(util.values(this._inEdges[target])).keys();
27565   if (arguments.length > 1) {
27566     this._strictGetNode(source);
27567     results = results.filter(function(e) { return this.source(e) === source; }, this);
27568   }
27569   return results;
27570 };
27571
27572 /*
27573  * Returns an array of ids for all edges in the graph that have the node
27574  * `source` as their source. If the node `source` is not in the graph this
27575  * function raises an Error.
27576  *
27577  * Optionally a `target` node may also be specified. This causes the results
27578  * to be filtered such that only edges from `source` to `target` are included.
27579  * If the node `target` is specified but is not in the graph then this function
27580  * raises an Error.
27581  *
27582  * @param {String} source the source node id
27583  * @param {String} [target] an optional target node id
27584  */
27585 Digraph.prototype.outEdges = function(source, target) {
27586   this._strictGetNode(source);
27587   var results = Set.union(util.values(this._outEdges[source])).keys();
27588   if (arguments.length > 1) {
27589     this._strictGetNode(target);
27590     results = results.filter(function(e) { return this.target(e) === target; }, this);
27591   }
27592   return results;
27593 };
27594
27595 /*
27596  * Returns an array of ids for all edges in the graph that have the `u` as
27597  * their source or their target. If the node `u` is not in the graph this
27598  * function raises an Error.
27599  *
27600  * Optionally a `v` node may also be specified. This causes the results to be
27601  * filtered such that only edges between `u` and `v` - in either direction -
27602  * are included. IF the node `v` is specified but not in the graph then this
27603  * function raises an Error.
27604  *
27605  * @param {String} u the node for which to find incident edges
27606  * @param {String} [v] option node that must be adjacent to `u`
27607  */
27608 Digraph.prototype.incidentEdges = function(u, v) {
27609   if (arguments.length > 1) {
27610     return Set.union([this.outEdges(u, v), this.outEdges(v, u)]).keys();
27611   } else {
27612     return Set.union([this.inEdges(u), this.outEdges(u)]).keys();
27613   }
27614 };
27615
27616 /*
27617  * Returns a string representation of this graph.
27618  */
27619 Digraph.prototype.toString = function() {
27620   return "Digraph " + JSON.stringify(this, null, 2);
27621 };
27622
27623 /*
27624  * Adds a new node with the id `u` to the graph and assigns it the value
27625  * `value`. If a node with the id is already a part of the graph this function
27626  * throws an Error.
27627  *
27628  * @param {String} u a node id
27629  * @param {Object} [value] an optional value to attach to the node
27630  */
27631 Digraph.prototype.addNode = function(u, value) {
27632   u = BaseGraph.prototype.addNode.call(this, u, value);
27633   this._inEdges[u] = {};
27634   this._outEdges[u] = {};
27635   return u;
27636 };
27637
27638 /*
27639  * Removes a node from the graph that has the id `u`. Any edges incident on the
27640  * node are also removed. If the graph does not contain a node with the id this
27641  * function will throw an Error.
27642  *
27643  * @param {String} u a node id
27644  */
27645 Digraph.prototype.delNode = function(u) {
27646   BaseGraph.prototype.delNode.call(this, u);
27647   delete this._inEdges[u];
27648   delete this._outEdges[u];
27649 };
27650
27651 /*
27652  * Adds a new edge to the graph with the id `e` from a node with the id `source`
27653  * to a node with an id `target` and assigns it the value `value`. This graph
27654  * allows more than one edge from `source` to `target` as long as the id `e`
27655  * is unique in the set of edges. If `e` is `null` the graph will assign a
27656  * unique identifier to the edge.
27657  *
27658  * If `source` or `target` are not present in the graph this function will
27659  * throw an Error.
27660  *
27661  * @param {String} [e] an edge id
27662  * @param {String} source the source node id
27663  * @param {String} target the target node id
27664  * @param {Object} [value] an optional value to attach to the edge
27665  */
27666 Digraph.prototype.addEdge = function(e, source, target, value) {
27667   return BaseGraph.prototype._addEdge.call(this, e, source, target, value,
27668                                            this._inEdges, this._outEdges);
27669 };
27670
27671 /*
27672  * Removes an edge in the graph with the id `e`. If no edge in the graph has
27673  * the id `e` this function will throw an Error.
27674  *
27675  * @param {String} e an edge id
27676  */
27677 Digraph.prototype.delEdge = function(e) {
27678   BaseGraph.prototype._delEdge.call(this, e, this._inEdges, this._outEdges);
27679 };
27680
27681 // Unlike BaseGraph.filterNodes, this helper just returns nodes that
27682 // satisfy a predicate.
27683 Digraph.prototype._filterNodes = function(pred) {
27684   var filtered = [];
27685   this.eachNode(function(u) {
27686     if (pred(u)) {
27687       filtered.push(u);
27688     }
27689   });
27690   return filtered;
27691 };
27692
27693
27694 },{"./BaseGraph":25,"./util":45,"cp-data":19}],29:[function(require,module,exports){
27695 /*
27696  * This file is organized with in the following order:
27697  *
27698  * Exports
27699  * Graph constructors
27700  * Graph queries (e.g. nodes(), edges()
27701  * Graph mutators
27702  * Helper functions
27703  */
27704
27705 var util = require("./util"),
27706     BaseGraph = require("./BaseGraph"),
27707 /* jshint -W079 */
27708     Set = require("cp-data").Set;
27709 /* jshint +W079 */
27710
27711 module.exports = Graph;
27712
27713 /*
27714  * Constructor to create a new undirected multi-graph.
27715  */
27716 function Graph() {
27717   BaseGraph.call(this);
27718
27719   /*! Map of nodeId -> { otherNodeId -> Set of edge ids } */
27720   this._incidentEdges = {};
27721 }
27722
27723 Graph.prototype = new BaseGraph();
27724 Graph.prototype.constructor = Graph;
27725
27726 /*
27727  * Always returns `false`.
27728  */
27729 Graph.prototype.isDirected = function() {
27730   return false;
27731 };
27732
27733 /*
27734  * Returns all nodes that are adjacent to the node with the id `u`.
27735  *
27736  * @param {String} u a node id
27737  */
27738 Graph.prototype.neighbors = function(u) {
27739   this._strictGetNode(u);
27740   return Object.keys(this._incidentEdges[u])
27741                .map(function(v) { return this._nodes[v].id; }, this);
27742 };
27743
27744 /*
27745  * Returns an array of ids for all edges in the graph that are incident on `u`.
27746  * If the node `u` is not in the graph this function raises an Error.
27747  *
27748  * Optionally a `v` node may also be specified. This causes the results to be
27749  * filtered such that only edges between `u` and `v` are included. If the node
27750  * `v` is specified but not in the graph then this function raises an Error.
27751  *
27752  * @param {String} u the node for which to find incident edges
27753  * @param {String} [v] option node that must be adjacent to `u`
27754  */
27755 Graph.prototype.incidentEdges = function(u, v) {
27756   this._strictGetNode(u);
27757   if (arguments.length > 1) {
27758     this._strictGetNode(v);
27759     return v in this._incidentEdges[u] ? this._incidentEdges[u][v].keys() : [];
27760   } else {
27761     return Set.union(util.values(this._incidentEdges[u])).keys();
27762   }
27763 };
27764
27765 /*
27766  * Returns a string representation of this graph.
27767  */
27768 Graph.prototype.toString = function() {
27769   return "Graph " + JSON.stringify(this, null, 2);
27770 };
27771
27772 /*
27773  * Adds a new node with the id `u` to the graph and assigns it the value
27774  * `value`. If a node with the id is already a part of the graph this function
27775  * throws an Error.
27776  *
27777  * @param {String} u a node id
27778  * @param {Object} [value] an optional value to attach to the node
27779  */
27780 Graph.prototype.addNode = function(u, value) {
27781   u = BaseGraph.prototype.addNode.call(this, u, value);
27782   this._incidentEdges[u] = {};
27783   return u;
27784 };
27785
27786 /*
27787  * Removes a node from the graph that has the id `u`. Any edges incident on the
27788  * node are also removed. If the graph does not contain a node with the id this
27789  * function will throw an Error.
27790  *
27791  * @param {String} u a node id
27792  */
27793 Graph.prototype.delNode = function(u) {
27794   BaseGraph.prototype.delNode.call(this, u);
27795   delete this._incidentEdges[u];
27796 };
27797
27798 /*
27799  * Adds a new edge to the graph with the id `e` between a node with the id `u`
27800  * and a node with an id `v` and assigns it the value `value`. This graph
27801  * allows more than one edge between `u` and `v` as long as the id `e`
27802  * is unique in the set of edges. If `e` is `null` the graph will assign a
27803  * unique identifier to the edge.
27804  *
27805  * If `u` or `v` are not present in the graph this function will throw an
27806  * Error.
27807  *
27808  * @param {String} [e] an edge id
27809  * @param {String} u the node id of one of the adjacent nodes
27810  * @param {String} v the node id of the other adjacent node
27811  * @param {Object} [value] an optional value to attach to the edge
27812  */
27813 Graph.prototype.addEdge = function(e, u, v, value) {
27814   return BaseGraph.prototype._addEdge.call(this, e, u, v, value,
27815                                            this._incidentEdges, this._incidentEdges);
27816 };
27817
27818 /*
27819  * Removes an edge in the graph with the id `e`. If no edge in the graph has
27820  * the id `e` this function will throw an Error.
27821  *
27822  * @param {String} e an edge id
27823  */
27824 Graph.prototype.delEdge = function(e) {
27825   BaseGraph.prototype._delEdge.call(this, e, this._incidentEdges, this._incidentEdges);
27826 };
27827
27828
27829 },{"./BaseGraph":25,"./util":45,"cp-data":19}],30:[function(require,module,exports){
27830 /* jshint -W079 */
27831 var Set = require("cp-data").Set;
27832 /* jshint +W079 */
27833
27834 module.exports = components;
27835
27836 /**
27837  * Finds all [connected components][] in a graph and returns an array of these
27838  * components. Each component is itself an array that contains the ids of nodes
27839  * in the component.
27840  *
27841  * This function only works with undirected Graphs.
27842  *
27843  * [connected components]: http://en.wikipedia.org/wiki/Connected_component_(graph_theory)
27844  *
27845  * @param {Graph} g the graph to search for components
27846  */
27847 function components(g) {
27848   var results = [];
27849   var visited = new Set();
27850
27851   function dfs(v, component) {
27852     if (!visited.has(v)) {
27853       visited.add(v);
27854       component.push(v);
27855       g.neighbors(v).forEach(function(w) {
27856         dfs(w, component);
27857       });
27858     }
27859   }
27860
27861   g.nodes().forEach(function(v) {
27862     var component = [];
27863     dfs(v, component);
27864     if (component.length > 0) {
27865       results.push(component);
27866     }
27867   });
27868
27869   return results;
27870 }
27871
27872 },{"cp-data":19}],31:[function(require,module,exports){
27873 var PriorityQueue = require("cp-data").PriorityQueue;
27874
27875 module.exports = dijkstra;
27876
27877 /**
27878  * This function is an implementation of [Dijkstra's algorithm][] which finds
27879  * the shortest path from **source** to all other nodes in **g**. This
27880  * function returns a map of `u -> { distance, predecessor }`. The distance
27881  * property holds the sum of the weights from **source** to `u` along the
27882  * shortest path or `Number.POSITIVE_INFINITY` if there is no path from
27883  * **source**. The predecessor property can be used to walk the individual
27884  * elements of the path from **source** to **u** in reverse order.
27885  *
27886  * This function takes an optional `weightFunc(e)` which returns the
27887  * weight of the edge `e`. If no weightFunc is supplied then each edge is
27888  * assumed to have a weight of 1. This function throws an Error if any of
27889  * the traversed edges have a negative edge weight.
27890  *
27891  * This function takes an optional `incidentFunc(u)` which returns the ids of
27892  * all edges incident to the node `u` for the purposes of shortest path
27893  * traversal. By default this function uses the `g.outEdges` for Digraphs and
27894  * `g.incidentEdges` for Graphs.
27895  *
27896  * This function takes `O((|E| + |V|) * log |V|)` time.
27897  *
27898  * [Dijkstra's algorithm]: http://en.wikipedia.org/wiki/Dijkstra%27s_algorithm
27899  *
27900  * @param {Graph} g the graph to search for shortest paths from **source**
27901  * @param {Object} source the source from which to start the search
27902  * @param {Function} [weightFunc] optional weight function
27903  * @param {Function} [incidentFunc] optional incident function
27904  */
27905 function dijkstra(g, source, weightFunc, incidentFunc) {
27906   var results = {},
27907       pq = new PriorityQueue();
27908
27909   function updateNeighbors(e) {
27910     var incidentNodes = g.incidentNodes(e),
27911         v = incidentNodes[0] !== u ? incidentNodes[0] : incidentNodes[1],
27912         vEntry = results[v],
27913         weight = weightFunc(e),
27914         distance = uEntry.distance + weight;
27915
27916     if (weight < 0) {
27917       throw new Error("dijkstra does not allow negative edge weights. Bad edge: " + e + " Weight: " + weight);
27918     }
27919
27920     if (distance < vEntry.distance) {
27921       vEntry.distance = distance;
27922       vEntry.predecessor = u;
27923       pq.decrease(v, distance);
27924     }
27925   }
27926
27927   weightFunc = weightFunc || function() { return 1; };
27928   incidentFunc = incidentFunc || (g.isDirected()
27929       ? function(u) { return g.outEdges(u); }
27930       : function(u) { return g.incidentEdges(u); });
27931
27932   g.eachNode(function(u) {
27933     var distance = u === source ? 0 : Number.POSITIVE_INFINITY;
27934     results[u] = { distance: distance };
27935     pq.add(u, distance);
27936   });
27937
27938   var u, uEntry;
27939   while (pq.size() > 0) {
27940     u = pq.removeMin();
27941     uEntry = results[u];
27942     if (uEntry.distance === Number.POSITIVE_INFINITY) {
27943       break;
27944     }
27945
27946     incidentFunc(u).forEach(updateNeighbors);
27947   }
27948
27949   return results;
27950 }
27951
27952 },{"cp-data":19}],32:[function(require,module,exports){
27953 var dijkstra = require("./dijkstra");
27954
27955 module.exports = dijkstraAll;
27956
27957 /**
27958  * This function finds the shortest path from each node to every other
27959  * reachable node in the graph. It is similar to [alg.dijkstra][], but
27960  * instead of returning a single-source array, it returns a mapping of
27961  * of `source -> alg.dijksta(g, source, weightFunc, incidentFunc)`.
27962  *
27963  * This function takes an optional `weightFunc(e)` which returns the
27964  * weight of the edge `e`. If no weightFunc is supplied then each edge is
27965  * assumed to have a weight of 1. This function throws an Error if any of
27966  * the traversed edges have a negative edge weight.
27967  *
27968  * This function takes an optional `incidentFunc(u)` which returns the ids of
27969  * all edges incident to the node `u` for the purposes of shortest path
27970  * traversal. By default this function uses the `outEdges` function on the
27971  * supplied graph.
27972  *
27973  * This function takes `O(|V| * (|E| + |V|) * log |V|)` time.
27974  *
27975  * [alg.dijkstra]: dijkstra.js.html#dijkstra
27976  *
27977  * @param {Graph} g the graph to search for shortest paths from **source**
27978  * @param {Function} [weightFunc] optional weight function
27979  * @param {Function} [incidentFunc] optional incident function
27980  */
27981 function dijkstraAll(g, weightFunc, incidentFunc) {
27982   var results = {};
27983   g.eachNode(function(u) {
27984     results[u] = dijkstra(g, u, weightFunc, incidentFunc);
27985   });
27986   return results;
27987 }
27988
27989 },{"./dijkstra":31}],33:[function(require,module,exports){
27990 var tarjan = require("./tarjan");
27991
27992 module.exports = findCycles;
27993
27994 /*
27995  * Given a Digraph **g** this function returns all nodes that are part of a
27996  * cycle. Since there may be more than one cycle in a graph this function
27997  * returns an array of these cycles, where each cycle is itself represented
27998  * by an array of ids for each node involved in that cycle.
27999  *
28000  * [alg.isAcyclic][] is more efficient if you only need to determine whether
28001  * a graph has a cycle or not.
28002  *
28003  * [alg.isAcyclic]: isAcyclic.js.html#isAcyclic
28004  *
28005  * @param {Digraph} g the graph to search for cycles.
28006  */
28007 function findCycles(g) {
28008   return tarjan(g).filter(function(cmpt) { return cmpt.length > 1; });
28009 }
28010
28011 },{"./tarjan":39}],34:[function(require,module,exports){
28012 module.exports = floydWarshall;
28013
28014 /**
28015  * This function is an implementation of the [Floyd-Warshall algorithm][],
28016  * which finds the shortest path from each node to every other reachable node
28017  * in the graph. It is similar to [alg.dijkstraAll][], but it handles negative
28018  * edge weights and is more efficient for some types of graphs. This function
28019  * returns a map of `source -> { target -> { distance, predecessor }`. The
28020  * distance property holds the sum of the weights from `source` to `target`
28021  * along the shortest path of `Number.POSITIVE_INFINITY` if there is no path
28022  * from `source`. The predecessor property can be used to walk the individual
28023  * elements of the path from `source` to `target` in reverse order.
28024  *
28025  * This function takes an optional `weightFunc(e)` which returns the
28026  * weight of the edge `e`. If no weightFunc is supplied then each edge is
28027  * assumed to have a weight of 1.
28028  *
28029  * This function takes an optional `incidentFunc(u)` which returns the ids of
28030  * all edges incident to the node `u` for the purposes of shortest path
28031  * traversal. By default this function uses the `outEdges` function on the
28032  * supplied graph.
28033  *
28034  * This algorithm takes O(|V|^3) time.
28035  *
28036  * [Floyd-Warshall algorithm]: https://en.wikipedia.org/wiki/Floyd-Warshall_algorithm
28037  * [alg.dijkstraAll]: dijkstraAll.js.html#dijkstraAll
28038  *
28039  * @param {Graph} g the graph to search for shortest paths from **source**
28040  * @param {Function} [weightFunc] optional weight function
28041  * @param {Function} [incidentFunc] optional incident function
28042  */
28043 function floydWarshall(g, weightFunc, incidentFunc) {
28044   var results = {},
28045       nodes = g.nodes();
28046
28047   weightFunc = weightFunc || function() { return 1; };
28048   incidentFunc = incidentFunc || (g.isDirected()
28049       ? function(u) { return g.outEdges(u); }
28050       : function(u) { return g.incidentEdges(u); });
28051
28052   nodes.forEach(function(u) {
28053     results[u] = {};
28054     results[u][u] = { distance: 0 };
28055     nodes.forEach(function(v) {
28056       if (u !== v) {
28057         results[u][v] = { distance: Number.POSITIVE_INFINITY };
28058       }
28059     });
28060     incidentFunc(u).forEach(function(e) {
28061       var incidentNodes = g.incidentNodes(e),
28062           v = incidentNodes[0] !== u ? incidentNodes[0] : incidentNodes[1],
28063           d = weightFunc(e);
28064       if (d < results[u][v].distance) {
28065         results[u][v] = { distance: d, predecessor: u };
28066       }
28067     });
28068   });
28069
28070   nodes.forEach(function(k) {
28071     var rowK = results[k];
28072     nodes.forEach(function(i) {
28073       var rowI = results[i];
28074       nodes.forEach(function(j) {
28075         var ik = rowI[k];
28076         var kj = rowK[j];
28077         var ij = rowI[j];
28078         var altDistance = ik.distance + kj.distance;
28079         if (altDistance < ij.distance) {
28080           ij.distance = altDistance;
28081           ij.predecessor = kj.predecessor;
28082         }
28083       });
28084     });
28085   });
28086
28087   return results;
28088 }
28089
28090 },{}],35:[function(require,module,exports){
28091 var topsort = require("./topsort");
28092
28093 module.exports = isAcyclic;
28094
28095 /*
28096  * Given a Digraph **g** this function returns `true` if the graph has no
28097  * cycles and returns `false` if it does. This algorithm returns as soon as it
28098  * detects the first cycle.
28099  *
28100  * Use [alg.findCycles][] if you need the actual list of cycles in a graph.
28101  *
28102  * [alg.findCycles]: findCycles.js.html#findCycles
28103  *
28104  * @param {Digraph} g the graph to test for cycles
28105  */
28106 function isAcyclic(g) {
28107   try {
28108     topsort(g);
28109   } catch (e) {
28110     if (e instanceof topsort.CycleException) return false;
28111     throw e;
28112   }
28113   return true;
28114 }
28115
28116 },{"./topsort":40}],36:[function(require,module,exports){
28117 /* jshint -W079 */
28118 var Set = require("cp-data").Set;
28119 /* jshint +W079 */
28120
28121 module.exports = postorder;
28122
28123 // Postorder traversal of g, calling f for each visited node. Assumes the graph
28124 // is a tree.
28125 function postorder(g, root, f) {
28126   var visited = new Set();
28127   if (g.isDirected()) {
28128     throw new Error("This function only works for undirected graphs");
28129   }
28130   function dfs(u, prev) {
28131     if (visited.has(u)) {
28132       throw new Error("The input graph is not a tree: " + g);
28133     }
28134     visited.add(u);
28135     g.neighbors(u).forEach(function(v) {
28136       if (v !== prev) dfs(v, u);
28137     });
28138     f(u);
28139   }
28140   dfs(root);
28141 }
28142
28143 },{"cp-data":19}],37:[function(require,module,exports){
28144 /* jshint -W079 */
28145 var Set = require("cp-data").Set;
28146 /* jshint +W079 */
28147
28148 module.exports = preorder;
28149
28150 // Preorder traversal of g, calling f for each visited node. Assumes the graph
28151 // is a tree.
28152 function preorder(g, root, f) {
28153   var visited = new Set();
28154   if (g.isDirected()) {
28155     throw new Error("This function only works for undirected graphs");
28156   }
28157   function dfs(u, prev) {
28158     if (visited.has(u)) {
28159       throw new Error("The input graph is not a tree: " + g);
28160     }
28161     visited.add(u);
28162     f(u);
28163     g.neighbors(u).forEach(function(v) {
28164       if (v !== prev) dfs(v, u);
28165     });
28166   }
28167   dfs(root);
28168 }
28169
28170 },{"cp-data":19}],38:[function(require,module,exports){
28171 var Graph = require("../Graph"),
28172     PriorityQueue = require("cp-data").PriorityQueue;
28173
28174 module.exports = prim;
28175
28176 /**
28177  * [Prim's algorithm][] takes a connected undirected graph and generates a
28178  * [minimum spanning tree][]. This function returns the minimum spanning
28179  * tree as an undirected graph. This algorithm is derived from the description
28180  * in "Introduction to Algorithms", Third Edition, Cormen, et al., Pg 634.
28181  *
28182  * This function takes a `weightFunc(e)` which returns the weight of the edge
28183  * `e`. It throws an Error if the graph is not connected.
28184  *
28185  * This function takes `O(|E| log |V|)` time.
28186  *
28187  * [Prim's algorithm]: https://en.wikipedia.org/wiki/Prim's_algorithm
28188  * [minimum spanning tree]: https://en.wikipedia.org/wiki/Minimum_spanning_tree
28189  *
28190  * @param {Graph} g the graph used to generate the minimum spanning tree
28191  * @param {Function} weightFunc the weight function to use
28192  */
28193 function prim(g, weightFunc) {
28194   var result = new Graph(),
28195       parents = {},
28196       pq = new PriorityQueue(),
28197       u;
28198
28199   function updateNeighbors(e) {
28200     var incidentNodes = g.incidentNodes(e),
28201         v = incidentNodes[0] !== u ? incidentNodes[0] : incidentNodes[1],
28202         pri = pq.priority(v);
28203     if (pri !== undefined) {
28204       var edgeWeight = weightFunc(e);
28205       if (edgeWeight < pri) {
28206         parents[v] = u;
28207         pq.decrease(v, edgeWeight);
28208       }
28209     }
28210   }
28211
28212   if (g.order() === 0) {
28213     return result;
28214   }
28215
28216   g.eachNode(function(u) {
28217     pq.add(u, Number.POSITIVE_INFINITY);
28218     result.addNode(u);
28219   });
28220
28221   // Start from an arbitrary node
28222   pq.decrease(g.nodes()[0], 0);
28223
28224   var init = false;
28225   while (pq.size() > 0) {
28226     u = pq.removeMin();
28227     if (u in parents) {
28228       result.addEdge(null, u, parents[u]);
28229     } else if (init) {
28230       throw new Error("Input graph is not connected: " + g);
28231     } else {
28232       init = true;
28233     }
28234
28235     g.incidentEdges(u).forEach(updateNeighbors);
28236   }
28237
28238   return result;
28239 }
28240
28241 },{"../Graph":29,"cp-data":19}],39:[function(require,module,exports){
28242 module.exports = tarjan;
28243
28244 /**
28245  * This function is an implementation of [Tarjan's algorithm][] which finds
28246  * all [strongly connected components][] in the directed graph **g**. Each
28247  * strongly connected component is composed of nodes that can reach all other
28248  * nodes in the component via directed edges. A strongly connected component
28249  * can consist of a single node if that node cannot both reach and be reached
28250  * by any other specific node in the graph. Components of more than one node
28251  * are guaranteed to have at least one cycle.
28252  *
28253  * This function returns an array of components. Each component is itself an
28254  * array that contains the ids of all nodes in the component.
28255  *
28256  * [Tarjan's algorithm]: http://en.wikipedia.org/wiki/Tarjan's_strongly_connected_components_algorithm
28257  * [strongly connected components]: http://en.wikipedia.org/wiki/Strongly_connected_component
28258  *
28259  * @param {Digraph} g the graph to search for strongly connected components
28260  */
28261 function tarjan(g) {
28262   if (!g.isDirected()) {
28263     throw new Error("tarjan can only be applied to a directed graph. Bad input: " + g);
28264   }
28265
28266   var index = 0,
28267       stack = [],
28268       visited = {}, // node id -> { onStack, lowlink, index }
28269       results = [];
28270
28271   function dfs(u) {
28272     var entry = visited[u] = {
28273       onStack: true,
28274       lowlink: index,
28275       index: index++
28276     };
28277     stack.push(u);
28278
28279     g.successors(u).forEach(function(v) {
28280       if (!(v in visited)) {
28281         dfs(v);
28282         entry.lowlink = Math.min(entry.lowlink, visited[v].lowlink);
28283       } else if (visited[v].onStack) {
28284         entry.lowlink = Math.min(entry.lowlink, visited[v].index);
28285       }
28286     });
28287
28288     if (entry.lowlink === entry.index) {
28289       var cmpt = [],
28290           v;
28291       do {
28292         v = stack.pop();
28293         visited[v].onStack = false;
28294         cmpt.push(v);
28295       } while (u !== v);
28296       results.push(cmpt);
28297     }
28298   }
28299
28300   g.nodes().forEach(function(u) {
28301     if (!(u in visited)) {
28302       dfs(u);
28303     }
28304   });
28305
28306   return results;
28307 }
28308
28309 },{}],40:[function(require,module,exports){
28310 module.exports = topsort;
28311 topsort.CycleException = CycleException;
28312
28313 /*
28314  * Given a graph **g**, this function returns an ordered list of nodes such
28315  * that for each edge `u -> v`, `u` appears before `v` in the list. If the
28316  * graph has a cycle it is impossible to generate such a list and
28317  * **CycleException** is thrown.
28318  *
28319  * See [topological sorting](https://en.wikipedia.org/wiki/Topological_sorting)
28320  * for more details about how this algorithm works.
28321  *
28322  * @param {Digraph} g the graph to sort
28323  */
28324 function topsort(g) {
28325   if (!g.isDirected()) {
28326     throw new Error("topsort can only be applied to a directed graph. Bad input: " + g);
28327   }
28328
28329   var visited = {};
28330   var stack = {};
28331   var results = [];
28332
28333   function visit(node) {
28334     if (node in stack) {
28335       throw new CycleException();
28336     }
28337
28338     if (!(node in visited)) {
28339       stack[node] = true;
28340       visited[node] = true;
28341       g.predecessors(node).forEach(function(pred) {
28342         visit(pred);
28343       });
28344       delete stack[node];
28345       results.push(node);
28346     }
28347   }
28348
28349   var sinks = g.sinks();
28350   if (g.order() !== 0 && sinks.length === 0) {
28351     throw new CycleException();
28352   }
28353
28354   g.sinks().forEach(function(sink) {
28355     visit(sink);
28356   });
28357
28358   return results;
28359 }
28360
28361 function CycleException() {}
28362
28363 CycleException.prototype.toString = function() {
28364   return "Graph has at least one cycle";
28365 };
28366
28367 },{}],41:[function(require,module,exports){
28368 // This file provides a helper function that mixes-in Dot behavior to an
28369 // existing graph prototype.
28370
28371 /* jshint -W079 */
28372 var Set = require("cp-data").Set;
28373 /* jshint +W079 */
28374
28375 module.exports = compoundify;
28376
28377 // Extends the given SuperConstructor with the ability for nodes to contain
28378 // other nodes. A special node id `null` is used to indicate the root graph.
28379 function compoundify(SuperConstructor) {
28380   function Constructor() {
28381     SuperConstructor.call(this);
28382
28383     // Map of object id -> parent id (or null for root graph)
28384     this._parents = {};
28385
28386     // Map of id (or null) -> children set
28387     this._children = {};
28388     this._children[null] = new Set();
28389   }
28390
28391   Constructor.prototype = new SuperConstructor();
28392   Constructor.prototype.constructor = Constructor;
28393
28394   Constructor.prototype.parent = function(u, parent) {
28395     this._strictGetNode(u);
28396
28397     if (arguments.length < 2) {
28398       return this._parents[u];
28399     }
28400
28401     if (u === parent) {
28402       throw new Error("Cannot make " + u + " a parent of itself");
28403     }
28404     if (parent !== null) {
28405       this._strictGetNode(parent);
28406     }
28407
28408     this._children[this._parents[u]].remove(u);
28409     this._parents[u] = parent;
28410     this._children[parent].add(u);
28411   };
28412
28413   Constructor.prototype.children = function(u) {
28414     if (u !== null) {
28415       this._strictGetNode(u);
28416     }
28417     return this._children[u].keys();
28418   };
28419
28420   Constructor.prototype.addNode = function(u, value) {
28421     u = SuperConstructor.prototype.addNode.call(this, u, value);
28422     this._parents[u] = null;
28423     this._children[u] = new Set();
28424     this._children[null].add(u);
28425     return u;
28426   };
28427
28428   Constructor.prototype.delNode = function(u) {
28429     // Promote all children to the parent of the subgraph
28430     var parent = this.parent(u);
28431     this._children[u].keys().forEach(function(child) {
28432       this.parent(child, parent);
28433     }, this);
28434
28435     this._children[parent].remove(u);
28436     delete this._parents[u];
28437     delete this._children[u];
28438
28439     return SuperConstructor.prototype.delNode.call(this, u);
28440   };
28441
28442   Constructor.prototype.copy = function() {
28443     var copy = SuperConstructor.prototype.copy.call(this);
28444     this.nodes().forEach(function(u) {
28445       copy.parent(u, this.parent(u));
28446     }, this);
28447     return copy;
28448   };
28449
28450   Constructor.prototype.filterNodes = function(filter) {
28451     var self = this,
28452         copy = SuperConstructor.prototype.filterNodes.call(this, filter);
28453
28454     var parents = {};
28455     function findParent(u) {
28456       var parent = self.parent(u);
28457       if (parent === null || copy.hasNode(parent)) {
28458         parents[u] = parent;
28459         return parent;
28460       } else if (parent in parents) {
28461         return parents[parent];
28462       } else {
28463         return findParent(parent);
28464       }
28465     }
28466
28467     copy.eachNode(function(u) { copy.parent(u, findParent(u)); });
28468
28469     return copy;
28470   };
28471
28472   return Constructor;
28473 }
28474
28475 },{"cp-data":19}],42:[function(require,module,exports){
28476 var Graph = require("../Graph"),
28477     Digraph = require("../Digraph"),
28478     CGraph = require("../CGraph"),
28479     CDigraph = require("../CDigraph");
28480
28481 exports.decode = function(nodes, edges, Ctor) {
28482   Ctor = Ctor || Digraph;
28483
28484   if (typeOf(nodes) !== "Array") {
28485     throw new Error("nodes is not an Array");
28486   }
28487
28488   if (typeOf(edges) !== "Array") {
28489     throw new Error("edges is not an Array");
28490   }
28491
28492   if (typeof Ctor === "string") {
28493     switch(Ctor) {
28494       case "graph": Ctor = Graph; break;
28495       case "digraph": Ctor = Digraph; break;
28496       case "cgraph": Ctor = CGraph; break;
28497       case "cdigraph": Ctor = CDigraph; break;
28498       default: throw new Error("Unrecognized graph type: " + Ctor);
28499     }
28500   }
28501
28502   var graph = new Ctor();
28503
28504   nodes.forEach(function(u) {
28505     graph.addNode(u.id, u.value);
28506   });
28507
28508   // If the graph is compound, set up children...
28509   if (graph.parent) {
28510     nodes.forEach(function(u) {
28511       if (u.children) {
28512         u.children.forEach(function(v) {
28513           graph.parent(v, u.id);
28514         });
28515       }
28516     });
28517   }
28518
28519   edges.forEach(function(e) {
28520     graph.addEdge(e.id, e.u, e.v, e.value);
28521   });
28522
28523   return graph;
28524 };
28525
28526 exports.encode = function(graph) {
28527   var nodes = [];
28528   var edges = [];
28529
28530   graph.eachNode(function(u, value) {
28531     var node = {id: u, value: value};
28532     if (graph.children) {
28533       var children = graph.children(u);
28534       if (children.length) {
28535         node.children = children;
28536       }
28537     }
28538     nodes.push(node);
28539   });
28540
28541   graph.eachEdge(function(e, u, v, value) {
28542     edges.push({id: e, u: u, v: v, value: value});
28543   });
28544
28545   var type;
28546   if (graph instanceof CDigraph) {
28547     type = "cdigraph";
28548   } else if (graph instanceof CGraph) {
28549     type = "cgraph";
28550   } else if (graph instanceof Digraph) {
28551     type = "digraph";
28552   } else if (graph instanceof Graph) {
28553     type = "graph";
28554   } else {
28555     throw new Error("Couldn't determine type of graph: " + graph);
28556   }
28557
28558   return { nodes: nodes, edges: edges, type: type };
28559 };
28560
28561 function typeOf(obj) {
28562   return Object.prototype.toString.call(obj).slice(8, -1);
28563 }
28564
28565 },{"../CDigraph":26,"../CGraph":27,"../Digraph":28,"../Graph":29}],43:[function(require,module,exports){
28566 /* jshint -W079 */
28567 var Set = require("cp-data").Set;
28568 /* jshint +W079 */
28569
28570 exports.all = function() {
28571   return function() { return true; };
28572 };
28573
28574 exports.nodesFromList = function(nodes) {
28575   var set = new Set(nodes);
28576   return function(u) {
28577     return set.has(u);
28578   };
28579 };
28580
28581 },{"cp-data":19}],44:[function(require,module,exports){
28582 var Graph = require("./Graph"),
28583     Digraph = require("./Digraph");
28584
28585 // Side-effect based changes are lousy, but node doesn't seem to resolve the
28586 // requires cycle.
28587
28588 /**
28589  * Returns a new directed graph using the nodes and edges from this graph. The
28590  * new graph will have the same nodes, but will have twice the number of edges:
28591  * each edge is split into two edges with opposite directions. Edge ids,
28592  * consequently, are not preserved by this transformation.
28593  */
28594 Graph.prototype.toDigraph =
28595 Graph.prototype.asDirected = function() {
28596   var g = new Digraph();
28597   this.eachNode(function(u, value) { g.addNode(u, value); });
28598   this.eachEdge(function(e, u, v, value) {
28599     g.addEdge(null, u, v, value);
28600     g.addEdge(null, v, u, value);
28601   });
28602   return g;
28603 };
28604
28605 /**
28606  * Returns a new undirected graph using the nodes and edges from this graph.
28607  * The new graph will have the same nodes, but the edges will be made
28608  * undirected. Edge ids are preserved in this transformation.
28609  */
28610 Digraph.prototype.toGraph =
28611 Digraph.prototype.asUndirected = function() {
28612   var g = new Graph();
28613   this.eachNode(function(u, value) { g.addNode(u, value); });
28614   this.eachEdge(function(e, u, v, value) {
28615     g.addEdge(e, u, v, value);
28616   });
28617   return g;
28618 };
28619
28620 },{"./Digraph":28,"./Graph":29}],45:[function(require,module,exports){
28621 // Returns an array of all values for properties of **o**.
28622 exports.values = function(o) {
28623   var ks = Object.keys(o),
28624       len = ks.length,
28625       result = new Array(len),
28626       i;
28627   for (i = 0; i < len; ++i) {
28628     result[i] = o[ks[i]];
28629   }
28630   return result;
28631 };
28632
28633 },{}],46:[function(require,module,exports){
28634 module.exports = '0.7.4';
28635
28636 },{}]},{},[1])
28637 ;
28638 joint.layout.DirectedGraph = {
28639
28640     layout: function(graph, opt) {
28641
28642         opt = opt || {};
28643
28644         var inputGraph = this._prepareData(graph);
28645         var runner = dagre.layout();
28646
28647         if (opt.debugLevel) { runner.debugLevel(opt.debugLevel); }
28648         if (opt.rankDir) { runner.rankDir(opt.rankDir); }
28649         if (opt.rankSep) { runner.rankSep(opt.rankSep); }
28650         if (opt.edgeSep) { runner.edgeSep(opt.edgeSep); }
28651         if (opt.nodeSep) { runner.nodeSep(opt.nodeSep); }
28652
28653         var layoutGraph = runner.run(inputGraph);
28654         
28655         layoutGraph.eachNode(function(u, value) {
28656             if (!value.dummy) {
28657                 graph.get('cells').get(u).set('position', {
28658                     x: value.x - value.width/2,
28659                     y: value.y - value.height/2
28660                 });
28661             }
28662         });
28663
28664         if (opt.setLinkVertices) {
28665
28666             layoutGraph.eachEdge(function(e, u, v, value) {
28667                 var link = graph.get('cells').get(e);
28668                 if (link) {
28669                     graph.get('cells').get(e).set('vertices', value.points);
28670                 }
28671             });
28672         }
28673
28674         return { width: layoutGraph.graph().width, height: layoutGraph.graph().height };
28675     },
28676     
28677     _prepareData: function(graph) {
28678
28679         var dagreGraph = new dagre.Digraph();
28680
28681         // For each element.
28682         _.each(graph.getElements(), function(cell) {
28683
28684             if (dagreGraph.hasNode(cell.id)) return;
28685
28686             dagreGraph.addNode(cell.id, {
28687                 width: cell.get('size').width,
28688                 height: cell.get('size').height,
28689                 rank: cell.get('rank')
28690             });
28691         });
28692
28693         // For each link.
28694         _.each(graph.getLinks(), function(cell) {
28695
28696             if (dagreGraph.hasEdge(cell.id)) return;
28697
28698             var sourceId = cell.get('source').id;
28699             var targetId = cell.get('target').id;
28700
28701             dagreGraph.addEdge(cell.id, sourceId, targetId, { minLen: cell.get('minLen') || 1 });
28702         });
28703
28704         return dagreGraph;
28705     }
28706 };