立即执行函数(IIFE)的理解与运用

立即执行函数(IIFE)的理解与运用作为JavaScript的常用语法,立即执行函数IIFE(Immediately-InvokedFunctionExpression)是值得我们认真去学习探究的。一、创建函数的两种方式我们先从基础讲起,要创建一个JS函数,有两种方式。(一)函数定义(FunctionDeclaration)fu

大家好,欢迎来到IT知识分享网。

作为JavaScript的常用语法,立即执行函数IIFE(Immediately-Invoked Function Expression)是值得我们认真去学习探究的。

 

一、创建函数的两种方式

我们先从基础讲起,要创建一个JS函数,有两种方式。

 

(一)函数定义(Function Declaration)

function Identifier ( Parameters ){ FunctionBody }

函数定义中,参数(Parameters)标识符(Identifier )是必不可少的。如果遗漏,会报提示如下错误:Expected identifier

立即执行函数(IIFE)的理解与运用

 

(二)函数表达式(Function Expression)

function Identifier(Parameters){ FunctionBody }

函数表达式中,参数和标识符都是可选的。

那么我们是不是可以通过有无标识符来判断,创建函数的是一个函数定义,还是一个函数表达式呢?很遗憾,不行!

我们刚刚说过,函数表达式中标识符是可选的。那如果函数表达式有标识符,又该如何判断?

其实,”function Identifier(Parameters){ FunctionBody }”并不是一个完整的函数表达式,完整的函数的表达式,需要一个赋值操作。

比如: var name=function Identifier(Parameters){ FunctionBody }

这里的Identifier常常被省略,至于为什么,由于该主题内容涉及面较广,在此文中不作讨论。

好了。两种创建函数的方式实例如下:

//function expression
var myExpression = function () { return window.location }
//function declaration
function myDeclaration() { return window.location.hostname }

 

二、立即执行函数

顾名思义,立即执行函数可以让你的函数在创建后立即执行。

(一)基本结构

这样的函数有多常用呢,我们可以看看下面的代码:

(function( window, undefined ) {
//……
})(window);

这段代码,大家一定不会陌生。是的,它就是我们”Write less, do more”的jQuery。

jQuery整个文件就是一个立即执行函数。

(function(){})();  是立即执行函数常用的表现形式之一。

另一种也很常用:

(function(){}());

以上两种是比较常用的写法,但立即执行函数的写法因人而异。记住以下两点就可以了。

如果是函数表达式,可直接在其后加”()”立即执行。

如果是函数声明,可以通过”()”、”+”、”-“、”void”、”new”等运算符将其转换为函数表达式,然后再加”()”立即执行。

比如,下面的写法也是没有问题的。

void function(){}(alert("ok"));

在执行前,可以在最后调用的”()”传入我们需要的参数,比如jQuery就把window对象作为实参传入了立即函数内部。

(二)使用时机

什么时候需要用到立即执行函数呢?

1.当我们需要写一个js文件,并且复用率很高的时候,建议使用。

2.如果声明的函数只需要调用一次,建议使用。

3.独立模块,这个和第一点差不多。单独提出来,是想强调一下立即执行函数的好处,开发时,它能做到各模块的低耦合,减少对全局作用域的污染。

(三)实例及好处

无实例,无真相。找什么实例好呢?还是我们的jQuery吧。

立即执行函数(IIFE)的理解与运用
立即执行函数(IIFE)的理解与运用

   1 /*!
   2  * jQuery JavaScript Library v1.4.4
   3  * http://jquery.com/
   4  *
   5  * Copyright 2010, John Resig
   6  * Dual licensed under the MIT or GPL Version 2 licenses.
   7  * http://jquery.org/license
   8  *
   9  * Includes Sizzle.js
  10  * http://sizzlejs.com/
  11  * Copyright 2010, The Dojo Foundation
  12  * Released under the MIT, BSD, and GPL Licenses.
  13  *
  14  * Date: Thu Nov 11 19:04:53 2010 -0500
  15  */
  16 (function( window, undefined ) {
  17 
  18 // Use the correct document accordingly with window argument (sandbox)
  19 var document = window.document;
  20 var jQuery = (function() {
  21 
  22 // Define a local copy of jQuery
  23 var jQuery = function( selector, context ) {
  24         // The jQuery object is actually just the init constructor 'enhanced'
  25         return new jQuery.fn.init( selector, context );
  26     },
  27 
  28     // Map over jQuery in case of overwrite
  29     _jQuery = window.jQuery,
  30 
  31     // Map over the $ in case of overwrite
  32     _$ = window.$,
  33 
  34     // A central reference to the root jQuery(document)
  35     rootjQuery,
  36 
  37     // A simple way to check for HTML strings or ID strings
  38     // (both of which we optimize for)
  39     quickExpr = /^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/,
  40 
  41     // Is it a simple selector
  42     isSimple = /^.[^:#\[\.,]*$/,
  43 
  44     // Check if a string has a non-whitespace character in it
  45     rnotwhite = /\S/,
  46     rwhite = /\s/,
  47 
  48     // Used for trimming whitespace
  49     trimLeft = /^\s+/,
  50     trimRight = /\s+$/,
  51 
  52     // Check for non-word characters
  53     rnonword = /\W/,
  54 
  55     // Check for digits
  56     rdigit = /\d/,
  57 
  58     // Match a standalone tag
  59     rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/,
  60 
  61     // JSON RegExp
  62     rvalidchars = /^[\],:{}\s]*$/,
  63     rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,
  64     rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
  65     rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
  66 
  67     // Useragent RegExp
  68     rwebkit = /(webkit)[ \/]([\w.]+)/,
  69     ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/,
  70     rmsie = /(msie) ([\w.]+)/,
  71     rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/,
  72 
  73     // Keep a UserAgent string for use with jQuery.browser
  74     userAgent = navigator.userAgent,
  75 
  76     // For matching the engine and version of the browser
  77     browserMatch,
  78     
  79     // Has the ready events already been bound?
  80     readyBound = false,
  81     
  82     // The functions to execute on DOM ready
  83     readyList = [],
  84 
  85     // The ready event handler
  86     DOMContentLoaded,
  87 
  88     // Save a reference to some core methods
  89     toString = Object.prototype.toString,
  90     hasOwn = Object.prototype.hasOwnProperty,
  91     push = Array.prototype.push,
  92     slice = Array.prototype.slice,
  93     trim = String.prototype.trim,
  94     indexOf = Array.prototype.indexOf,
  95     
  96     // [[Class]] -> type pairs
  97     class2type = {};
  98 
  99 jQuery.fn = jQuery.prototype = {
 100     init: function( selector, context ) {
 101         var match, elem, ret, doc;
 102 
 103         // Handle $(""), $(null), or $(undefined)
 104         if ( !selector ) {
 105             return this;
 106         }
 107 
 108         // Handle $(DOMElement)
 109         if ( selector.nodeType ) {
 110             this.context = this[0] = selector;
 111             this.length = 1;
 112             return this;
 113         }
 114         
 115         // The body element only exists once, optimize finding it
 116         if ( selector === "body" && !context && document.body ) {
 117             this.context = document;
 118             this[0] = document.body;
 119             this.selector = "body";
 120             this.length = 1;
 121             return this;
 122         }
 123 
 124         // Handle HTML strings
 125         if ( typeof selector === "string" ) {
 126             // Are we dealing with HTML string or an ID?
 127             match = quickExpr.exec( selector );
 128 
 129             // Verify a match, and that no context was specified for #id
 130             if ( match && (match[1] || !context) ) {
 131 
 132                 // HANDLE: $(html) -> $(array)
 133                 if ( match[1] ) {
 134                     doc = (context ? context.ownerDocument || context : document);
 135 
 136                     // If a single string is passed in and it's a single tag
 137                     // just do a createElement and skip the rest
 138                     ret = rsingleTag.exec( selector );
 139 
 140                     if ( ret ) {
 141                         if ( jQuery.isPlainObject( context ) ) {
 142                             selector = [ document.createElement( ret[1] ) ];
 143                             jQuery.fn.attr.call( selector, context, true );
 144 
 145                         } else {
 146                             selector = [ doc.createElement( ret[1] ) ];
 147                         }
 148 
 149                     } else {
 150                         ret = jQuery.buildFragment( [ match[1] ], [ doc ] );
 151                         selector = (ret.cacheable ? ret.fragment.cloneNode(true) : ret.fragment).childNodes;
 152                     }
 153                     
 154                     return jQuery.merge( this, selector );
 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                         // Handle the case where IE and Opera return items
 164                         // by name instead of ID
 165                         if ( elem.id !== match[2] ) {
 166                             return rootjQuery.find( selector );
 167                         }
 168 
 169                         // Otherwise, we inject the element directly into the jQuery object
 170                         this.length = 1;
 171                         this[0] = elem;
 172                     }
 173 
 174                     this.context = document;
 175                     this.selector = selector;
 176                     return this;
 177                 }
 178 
 179             // HANDLE: $("TAG")
 180             } else if ( !context && !rnonword.test( selector ) ) {
 181                 this.selector = selector;
 182                 this.context = document;
 183                 selector = document.getElementsByTagName( selector );
 184                 return jQuery.merge( this, selector );
 185 
 186             // HANDLE: $(expr, $(...))
 187             } else if ( !context || context.jquery ) {
 188                 return (context || rootjQuery).find( selector );
 189 
 190             // HANDLE: $(expr, context)
 191             // (which is just equivalent to: $(context).find(expr)
 192             } else {
 193                 return jQuery( context ).find( selector );
 194             }
 195 
 196         // HANDLE: $(function)
 197         // Shortcut for document ready
 198         } else if ( jQuery.isFunction( selector ) ) {
 199             return rootjQuery.ready( selector );
 200         }
 201 
 202         if (selector.selector !== undefined) {
 203             this.selector = selector.selector;
 204             this.context = selector.context;
 205         }
 206 
 207         return jQuery.makeArray( selector, this );
 208     },
 209 
 210     // Start with an empty selector
 211     selector: "",
 212 
 213     // The current version of jQuery being used
 214     jquery: "1.4.4",
 215 
 216     // The default length of a jQuery object is 0
 217     length: 0,
 218 
 219     // The number of elements contained in the matched element set
 220     size: function() {
 221         return this.length;
 222     },
 223 
 224     toArray: function() {
 225         return slice.call( this, 0 );
 226     },
 227 
 228     // Get the Nth element in the matched element set OR
 229     // Get the whole matched element set as a clean array
 230     get: function( num ) {
 231         return num == null ?
 232 
 233             // Return a 'clean' array
 234             this.toArray() :
 235 
 236             // Return just the object
 237             ( num < 0 ? this.slice(num)[ 0 ] : this[ num ] );
 238     },
 239 
 240     // Take an array of elements and push it onto the stack
 241     // (returning the new matched element set)
 242     pushStack: function( elems, name, selector ) {
 243         // Build a new jQuery matched element set
 244         var ret = jQuery();
 245 
 246         if ( jQuery.isArray( elems ) ) {
 247             push.apply( ret, elems );
 248         
 249         } else {
 250             jQuery.merge( ret, elems );
 251         }
 252 
 253         // Add the old object onto the stack (as a reference)
 254         ret.prevObject = this;
 255 
 256         ret.context = this.context;
 257 
 258         if ( name === "find" ) {
 259             ret.selector = this.selector + (this.selector ? " " : "") + selector;
 260         } else if ( name ) {
 261             ret.selector = this.selector + "." + name + "(" + selector + ")";
 262         }
 263 
 264         // Return the newly-formed element set
 265         return ret;
 266     },
 267 
 268     // Execute a callback for every element in the matched set.
 269     // (You can seed the arguments with an array of args, but this is
 270     // only used internally.)
 271     each: function( callback, args ) {
 272         return jQuery.each( this, callback, args );
 273     },
 274     
 275     ready: function( fn ) {
 276         // Attach the listeners
 277         jQuery.bindReady();
 278 
 279         // If the DOM is already ready
 280         if ( jQuery.isReady ) {
 281             // Execute the function immediately
 282             fn.call( document, jQuery );
 283 
 284         // Otherwise, remember the function for later
 285         } else if ( readyList ) {
 286             // Add the function to the wait list
 287             readyList.push( fn );
 288         }
 289 
 290         return this;
 291     },
 292     
 293     eq: function( i ) {
 294         return i === -1 ?
 295             this.slice( i ) :
 296             this.slice( i, +i + 1 );
 297     },
 298 
 299     first: function() {
 300         return this.eq( 0 );
 301     },
 302 
 303     last: function() {
 304         return this.eq( -1 );
 305     },
 306 
 307     slice: function() {
 308         return this.pushStack( slice.apply( this, arguments ),
 309             "slice", slice.call(arguments).join(",") );
 310     },
 311 
 312     map: function( callback ) {
 313         return this.pushStack( jQuery.map(this, function( elem, i ) {
 314             return callback.call( elem, i, elem );
 315         }));
 316     },
 317     
 318     end: function() {
 319         return this.prevObject || jQuery(null);
 320     },
 321 
 322     // For internal use only.
 323     // Behaves like an Array's method, not like a jQuery method.
 324     push: push,
 325     sort: [].sort,
 326     splice: [].splice
 327 };
 328 
 329 // Give the init function the jQuery prototype for later instantiation
 330 jQuery.fn.init.prototype = jQuery.fn;
 331 
 332 jQuery.extend = jQuery.fn.extend = function() {
 333      var options, name, src, copy, copyIsArray, clone,
 334         target = arguments[0] || {},
 335         i = 1,
 336         length = arguments.length,
 337         deep = false;
 338 
 339     // Handle a deep copy situation
 340     if ( typeof target === "boolean" ) {
 341         deep = target;
 342         target = arguments[1] || {};
 343         // skip the boolean and the target
 344         i = 2;
 345     }
 346 
 347     // Handle case when target is a string or something (possible in deep copy)
 348     if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
 349         target = {};
 350     }
 351 
 352     // extend jQuery itself if only one argument is passed
 353     if ( length === i ) {
 354         target = this;
 355         --i;
 356     }
 357 
 358     for ( ; i < length; i++ ) {
 359         // Only deal with non-null/undefined values
 360         if ( (options = arguments[ i ]) != null ) {
 361             // Extend the base object
 362             for ( name in options ) {
 363                 src = target[ name ];
 364                 copy = options[ name ];
 365 
 366                 // Prevent never-ending loop
 367                 if ( target === copy ) {
 368                     continue;
 369                 }
 370 
 371                 // Recurse if we're merging plain objects or arrays
 372                 if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
 373                     if ( copyIsArray ) {
 374                         copyIsArray = false;
 375                         clone = src && jQuery.isArray(src) ? src : [];
 376 
 377                     } else {
 378                         clone = src && jQuery.isPlainObject(src) ? src : {};
 379                     }
 380 
 381                     // Never move original objects, clone them
 382                     target[ name ] = jQuery.extend( deep, clone, copy );
 383 
 384                 // Don't bring in undefined values
 385                 } else if ( copy !== undefined ) {
 386                     target[ name ] = copy;
 387                 }
 388             }
 389         }
 390     }
 391 
 392     // Return the modified object
 393     return target;
 394 };
 395 
 396 jQuery.extend({
 397     noConflict: function( deep ) {
 398         window.$ = _$;
 399 
 400         if ( deep ) {
 401             window.jQuery = _jQuery;
 402         }
 403 
 404         return jQuery;
 405     },
 406     
 407     // Is the DOM ready to be used? Set to true once it occurs.
 408     isReady: false,
 409 
 410     // A counter to track how many items to wait for before
 411     // the ready event fires. See #6781
 412     readyWait: 1,
 413     
 414     // Handle when the DOM is ready
 415     ready: function( wait ) {
 416         // A third-party is pushing the ready event forwards
 417         if ( wait === true ) {
 418             jQuery.readyWait--;
 419         }
 420 
 421         // Make sure that the DOM is not already loaded
 422         if ( !jQuery.readyWait || (wait !== true && !jQuery.isReady) ) {
 423             // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
 424             if ( !document.body ) {
 425                 return setTimeout( jQuery.ready, 1 );
 426             }
 427 
 428             // Remember that the DOM is ready
 429             jQuery.isReady = true;
 430 
 431             // If a normal DOM Ready event fired, decrement, and wait if need be
 432             if ( wait !== true && --jQuery.readyWait > 0 ) {
 433                 return;
 434             }
 435 
 436             // If there are functions bound, to execute
 437             if ( readyList ) {
 438                 // Execute all of them
 439                 var fn,
 440                     i = 0,
 441                     ready = readyList;
 442 
 443                 // Reset the list of functions
 444                 readyList = null;
 445 
 446                 while ( (fn = ready[ i++ ]) ) {
 447                     fn.call( document, jQuery );
 448                 }
 449 
 450                 // Trigger any bound ready events
 451                 if ( jQuery.fn.trigger ) {
 452                     jQuery( document ).trigger( "ready" ).unbind( "ready" );
 453                 }
 454             }
 455         }
 456     },
 457     
 458     bindReady: function() {
 459         if ( readyBound ) {
 460             return;
 461         }
 462 
 463         readyBound = true;
 464 
 465         // Catch cases where $(document).ready() is called after the
 466         // browser event has already occurred.
 467         if ( document.readyState === "complete" ) {
 468             // Handle it asynchronously to allow scripts the opportunity to delay ready
 469             return setTimeout( jQuery.ready, 1 );
 470         }
 471 
 472         // Mozilla, Opera and webkit nightlies currently support this event
 473         if ( document.addEventListener ) {
 474             // Use the handy event callback
 475             document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
 476             
 477             // A fallback to window.onload, that will always work
 478             window.addEventListener( "load", jQuery.ready, false );
 479 
 480         // If IE event model is used
 481         } else if ( document.attachEvent ) {
 482             // ensure firing before onload,
 483             // maybe late but safe also for iframes
 484             document.attachEvent("onreadystatechange", DOMContentLoaded);
 485             
 486             // A fallback to window.onload, that will always work
 487             window.attachEvent( "onload", jQuery.ready );
 488 
 489             // If IE and not a frame
 490             // continually check to see if the document is ready
 491             var toplevel = false;
 492 
 493             try {
 494                 toplevel = window.frameElement == null;
 495             } catch(e) {}
 496 
 497             if ( document.documentElement.doScroll && toplevel ) {
 498                 doScrollCheck();
 499             }
 500         }
 501     },
 502 
 503     // See test/unit/core.js for details concerning isFunction.
 504     // Since version 1.3, DOM methods and functions like alert
 505     // aren't supported. They return false on IE (#2968).
 506     isFunction: function( obj ) {
 507         return jQuery.type(obj) === "function";
 508     },
 509 
 510     isArray: Array.isArray || function( obj ) {
 511         return jQuery.type(obj) === "array";
 512     },
 513 
 514     // A crude way of determining if an object is a window
 515     isWindow: function( obj ) {
 516         return obj && typeof obj === "object" && "setInterval" in obj;
 517     },
 518 
 519     isNaN: function( obj ) {
 520         return obj == null || !rdigit.test( obj ) || isNaN( obj );
 521     },
 522 
 523     type: function( obj ) {
 524         return obj == null ?
 525             String( obj ) :
 526             class2type[ toString.call(obj) ] || "object";
 527     },
 528 
 529     isPlainObject: function( obj ) {
 530         // Must be an Object.
 531         // Because of IE, we also have to check the presence of the constructor property.
 532         // Make sure that DOM nodes and window objects don't pass through, as well
 533         if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
 534             return false;
 535         }
 536         
 537         // Not own constructor property must be Object
 538         if ( obj.constructor &&
 539             !hasOwn.call(obj, "constructor") &&
 540             !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
 541             return false;
 542         }
 543         
 544         // Own properties are enumerated firstly, so to speed up,
 545         // if last one is own, then all properties are own.
 546     
 547         var key;
 548         for ( key in obj ) {}
 549         
 550         return key === undefined || hasOwn.call( obj, key );
 551     },
 552 
 553     isEmptyObject: function( obj ) {
 554         for ( var name in obj ) {
 555             return false;
 556         }
 557         return true;
 558     },
 559     
 560     error: function( msg ) {
 561         throw msg;
 562     },
 563     
 564     parseJSON: function( data ) {
 565         if ( typeof data !== "string" || !data ) {
 566             return null;
 567         }
 568 
 569         // Make sure leading/trailing whitespace is removed (IE can't handle it)
 570         data = jQuery.trim( data );
 571         
 572         // Make sure the incoming data is actual JSON
 573         // Logic borrowed from http://json.org/json2.js
 574         if ( rvalidchars.test(data.replace(rvalidescape, "@")
 575             .replace(rvalidtokens, "]")
 576             .replace(rvalidbraces, "")) ) {
 577 
 578             // Try to use the native JSON parser first
 579             return window.JSON && window.JSON.parse ?
 580                 window.JSON.parse( data ) :
 581                 (new Function("return " + data))();
 582 
 583         } else {
 584             jQuery.error( "Invalid JSON: " + data );
 585         }
 586     },
 587 
 588     noop: function() {},
 589 
 590     // Evalulates a script in a global context
 591     globalEval: function( data ) {
 592         if ( data && rnotwhite.test(data) ) {
 593             // Inspired by code by Andrea Giammarchi
 594             // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html
 595             var head = document.getElementsByTagName("head")[0] || document.documentElement,
 596                 script = document.createElement("script");
 597 
 598             script.type = "text/javascript";
 599 
 600             if ( jQuery.support.scriptEval ) {
 601                 script.appendChild( document.createTextNode( data ) );
 602             } else {
 603                 script.text = data;
 604             }
 605 
 606             // Use insertBefore instead of appendChild to circumvent an IE6 bug.
 607             // This arises when a base node is used (#2709).
 608             head.insertBefore( script, head.firstChild );
 609             head.removeChild( script );
 610         }
 611     },
 612 
 613     nodeName: function( elem, name ) {
 614         return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();
 615     },
 616 
 617     // args is for internal usage only
 618     each: function( object, callback, args ) {
 619         var name, i = 0,
 620             length = object.length,
 621             isObj = length === undefined || jQuery.isFunction(object);
 622 
 623         if ( args ) {
 624             if ( isObj ) {
 625                 for ( name in object ) {
 626                     if ( callback.apply( object[ name ], args ) === false ) {
 627                         break;
 628                     }
 629                 }
 630             } else {
 631                 for ( ; i < length; ) {
 632                     if ( callback.apply( object[ i++ ], args ) === false ) {
 633                         break;
 634                     }
 635                 }
 636             }
 637 
 638         // A special, fast, case for the most common use of each
 639         } else {
 640             if ( isObj ) {
 641                 for ( name in object ) {
 642                     if ( callback.call( object[ name ], name, object[ name ] ) === false ) {
 643                         break;
 644                     }
 645                 }
 646             } else {
 647                 for ( var value = object[0];
 648                     i < length && callback.call( value, i, value ) !== false; value = object[++i] ) {}
 649             }
 650         }
 651 
 652         return object;
 653     },
 654 
 655     // Use native String.trim function wherever possible
 656     trim: trim ?
 657         function( text ) {
 658             return text == null ?
 659                 "" :
 660                 trim.call( text );
 661         } :
 662 
 663         // Otherwise use our own trimming functionality
 664         function( text ) {
 665             return text == null ?
 666                 "" :
 667                 text.toString().replace( trimLeft, "" ).replace( trimRight, "" );
 668         },
 669 
 670     // results is for internal usage only
 671     makeArray: function( array, results ) {
 672         var ret = results || [];
 673 
 674         if ( array != null ) {
 675             // The window, strings (and functions) also have 'length'
 676             // The extra typeof function check is to prevent crashes
 677             // in Safari 2 (See: #3039)
 678             // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930
 679             var type = jQuery.type(array);
 680 
 681             if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) {
 682                 push.call( ret, array );
 683             } else {
 684                 jQuery.merge( ret, array );
 685             }
 686         }
 687 
 688         return ret;
 689     },
 690 
 691     inArray: function( elem, array ) {
 692         if ( array.indexOf ) {
 693             return array.indexOf( elem );
 694         }
 695 
 696         for ( var i = 0, length = array.length; i < length; i++ ) {
 697             if ( array[ i ] === elem ) {
 698                 return i;
 699             }
 700         }
 701 
 702         return -1;
 703     },
 704 
 705     merge: function( first, second ) {
 706         var i = first.length,
 707             j = 0;
 708 
 709         if ( typeof second.length === "number" ) {
 710             for ( var l = second.length; j < l; j++ ) {
 711                 first[ i++ ] = second[ j ];
 712             }
 713         
 714         } else {
 715             while ( second[j] !== undefined ) {
 716                 first[ i++ ] = second[ j++ ];
 717             }
 718         }
 719 
 720         first.length = i;
 721 
 722         return first;
 723     },
 724 
 725     grep: function( elems, callback, inv ) {
 726         var ret = [], retVal;
 727         inv = !!inv;
 728 
 729         // Go through the array, only saving the items
 730         // that pass the validator function
 731         for ( var i = 0, length = elems.length; i < length; i++ ) {
 732             retVal = !!callback( elems[ i ], i );
 733             if ( inv !== retVal ) {
 734                 ret.push( elems[ i ] );
 735             }
 736         }
 737 
 738         return ret;
 739     },
 740 
 741     // arg is for internal usage only
 742     map: function( elems, callback, arg ) {
 743         var ret = [], value;
 744 
 745         // Go through the array, translating each of the items to their
 746         // new value (or values).
 747         for ( var i = 0, length = elems.length; i < length; i++ ) {
 748             value = callback( elems[ i ], i, arg );
 749 
 750             if ( value != null ) {
 751                 ret[ ret.length ] = value;
 752             }
 753         }
 754 
 755         return ret.concat.apply( [], ret );
 756     },
 757 
 758     // A global GUID counter for objects
 759     guid: 1,
 760 
 761     proxy: function( fn, proxy, thisObject ) {
 762         if ( arguments.length === 2 ) {
 763             if ( typeof proxy === "string" ) {
 764                 thisObject = fn;
 765                 fn = thisObject[ proxy ];
 766                 proxy = undefined;
 767 
 768             } else if ( proxy && !jQuery.isFunction( proxy ) ) {
 769                 thisObject = proxy;
 770                 proxy = undefined;
 771             }
 772         }
 773 
 774         if ( !proxy && fn ) {
 775             proxy = function() {
 776                 return fn.apply( thisObject || this, arguments );
 777             };
 778         }
 779 
 780         // Set the guid of unique handler to the same of original handler, so it can be removed
 781         if ( fn ) {
 782             proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++;
 783         }
 784 
 785         // So proxy can be declared as an argument
 786         return proxy;
 787     },
 788 
 789     // Mutifunctional method to get and set values to a collection
 790     // The value/s can be optionally by executed if its a function
 791     access: function( elems, key, value, exec, fn, pass ) {
 792         var length = elems.length;
 793     
 794         // Setting many attributes
 795         if ( typeof key === "object" ) {
 796             for ( var k in key ) {
 797                 jQuery.access( elems, k, key[k], exec, fn, value );
 798             }
 799             return elems;
 800         }
 801     
 802         // Setting one attribute
 803         if ( value !== undefined ) {
 804             // Optionally, function values get executed if exec is true
 805             exec = !pass && exec && jQuery.isFunction(value);
 806         
 807             for ( var i = 0; i < length; i++ ) {
 808                 fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );
 809             }
 810         
 811             return elems;
 812         }
 813     
 814         // Getting an attribute
 815         return length ? fn( elems[0], key ) : undefined;
 816     },
 817 
 818     now: function() {
 819         return (new Date()).getTime();
 820     },
 821 
 822     // Use of jQuery.browser is frowned upon.
 823     // More details: http://docs.jquery.com/Utilities/jQuery.browser
 824     uaMatch: function( ua ) {
 825         ua = ua.toLowerCase();
 826 
 827         var match = rwebkit.exec( ua ) ||
 828             ropera.exec( ua ) ||
 829             rmsie.exec( ua ) ||
 830             ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) ||
 831             [];
 832 
 833         return { browser: match[1] || "", version: match[2] || "0" };
 834     },
 835 
 836     browser: {}
 837 });
 838 
 839 // Populate the class2type map
 840 jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) {
 841     class2type[ "[object " + name + "]" ] = name.toLowerCase();
 842 });
 843 
 844 browserMatch = jQuery.uaMatch( userAgent );
 845 if ( browserMatch.browser ) {
 846     jQuery.browser[ browserMatch.browser ] = true;
 847     jQuery.browser.version = browserMatch.version;
 848 }
 849 
 850 // Deprecated, use jQuery.browser.webkit instead
 851 if ( jQuery.browser.webkit ) {
 852     jQuery.browser.safari = true;
 853 }
 854 
 855 if ( indexOf ) {
 856     jQuery.inArray = function( elem, array ) {
 857         return indexOf.call( array, elem );
 858     };
 859 }
 860 
 861 // Verify that \s matches non-breaking spaces
 862 // (IE fails on this test)
 863 if ( !rwhite.test( "\xA0" ) ) {
 864     trimLeft = /^[\s\xA0]+/;
 865     trimRight = /[\s\xA0]+$/;
 866 }
 867 
 868 // All jQuery objects should point back to these
 869 rootjQuery = jQuery(document);
 870 
 871 // Cleanup functions for the document ready method
 872 if ( document.addEventListener ) {
 873     DOMContentLoaded = function() {
 874         document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
 875         jQuery.ready();
 876     };
 877 
 878 } else if ( document.attachEvent ) {
 879     DOMContentLoaded = function() {
 880         // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
 881         if ( document.readyState === "complete" ) {
 882             document.detachEvent( "onreadystatechange", DOMContentLoaded );
 883             jQuery.ready();
 884         }
 885     };
 886 }
 887 
 888 // The DOM ready check for Internet Explorer
 889 function doScrollCheck() {
 890     if ( jQuery.isReady ) {
 891         return;
 892     }
 893 
 894     try {
 895         // If IE is used, use the trick by Diego Perini
 896         // http://javascript.nwbox.com/IEContentLoaded/
 897         document.documentElement.doScroll("left");
 898     } catch(e) {
 899         setTimeout( doScrollCheck, 1 );
 900         return;
 901     }
 902 
 903     // and execute any waiting functions
 904     jQuery.ready();
 905 }
 906 
 907 // Expose jQuery to the global object
 908 return (window.jQuery = window.$ = jQuery);
 909 
 910 })();
 911 
 912 
 913 (function() {
 914 
 915     jQuery.support = {};
 916 
 917     var root = document.documentElement,
 918         script = document.createElement("script"),
 919         div = document.createElement("div"),
 920         id = "script" + jQuery.now();
 921 
 922     div.style.display = "none";
 923     div.innerHTML = "   <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
 924 
 925     var all = div.getElementsByTagName("*"),
 926         a = div.getElementsByTagName("a")[0],
 927         select = document.createElement("select"),
 928         opt = select.appendChild( document.createElement("option") );
 929 
 930     // Can't get basic test support
 931     if ( !all || !all.length || !a ) {
 932         return;
 933     }
 934 
 935     jQuery.support = {
 936         // IE strips leading whitespace when .innerHTML is used
 937         leadingWhitespace: div.firstChild.nodeType === 3,
 938 
 939         // Make sure that tbody elements aren't automatically inserted
 940         // IE will insert them into empty tables
 941         tbody: !div.getElementsByTagName("tbody").length,
 942 
 943         // Make sure that link elements get serialized correctly by innerHTML
 944         // This requires a wrapper element in IE
 945         htmlSerialize: !!div.getElementsByTagName("link").length,
 946 
 947         // Get the style information from getAttribute
 948         // (IE uses .cssText insted)
 949         style: /red/.test( a.getAttribute("style") ),
 950 
 951         // Make sure that URLs aren't manipulated
 952         // (IE normalizes it by default)
 953         hrefNormalized: a.getAttribute("href") === "/a",
 954 
 955         // Make sure that element opacity exists
 956         // (IE uses filter instead)
 957         // Use a regex to work around a WebKit issue. See #5145
 958         opacity: /^0.55$/.test( a.style.opacity ),
 959 
 960         // Verify style float existence
 961         // (IE uses styleFloat instead of cssFloat)
 962         cssFloat: !!a.style.cssFloat,
 963 
 964         // Make sure that if no value is specified for a checkbox
 965         // that it defaults to "on".
 966         // (WebKit defaults to "" instead)
 967         checkOn: div.getElementsByTagName("input")[0].value === "on",
 968 
 969         // Make sure that a selected-by-default option has a working selected property.
 970         // (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
 971         optSelected: opt.selected,
 972 
 973         // Will be defined later
 974         deleteExpando: true,
 975         optDisabled: false,
 976         checkClone: false,
 977         scriptEval: false,
 978         noCloneEvent: true,
 979         boxModel: null,
 980         inlineBlockNeedsLayout: false,
 981         shrinkWrapBlocks: false,
 982         reliableHiddenOffsets: true
 983     };
 984 
 985     // Make sure that the options inside disabled selects aren't marked as disabled
 986     // (WebKit marks them as diabled)
 987     select.disabled = true;
 988     jQuery.support.optDisabled = !opt.disabled;
 989 
 990     script.type = "text/javascript";
 991     try {
 992         script.appendChild( document.createTextNode( "window." + id + "=1;" ) );
 993     } catch(e) {}
 994 
 995     root.insertBefore( script, root.firstChild );
 996 
 997     // Make sure that the execution of code works by injecting a script
 998     // tag with appendChild/createTextNode
 999     // (IE doesn't support this, fails, and uses .text instead)
1000     if ( window[ id ] ) {
1001         jQuery.support.scriptEval = true;
1002         delete window[ id ];
1003     }
1004 
1005     // Test to see if it's possible to delete an expando from an element
1006     // Fails in Internet Explorer
1007     try {
1008         delete script.test;
1009 
1010     } catch(e) {
1011         jQuery.support.deleteExpando = false;
1012     }
1013 
1014     root.removeChild( script );
1015 
1016     if ( div.attachEvent && div.fireEvent ) {
1017         div.attachEvent("onclick", function click() {
1018             // Cloning a node shouldn't copy over any
1019             // bound event handlers (IE does this)
1020             jQuery.support.noCloneEvent = false;
1021             div.detachEvent("onclick", click);
1022         });
1023         div.cloneNode(true).fireEvent("onclick");
1024     }
1025 
1026     div = document.createElement("div");
1027     div.innerHTML = "<input type='radio' name='radiotest' checked='checked'/>";
1028 
1029     var fragment = document.createDocumentFragment();
1030     fragment.appendChild( div.firstChild );
1031 
1032     // WebKit doesn't clone checked state correctly in fragments
1033     jQuery.support.checkClone = fragment.cloneNode(true).cloneNode(true).lastChild.checked;
1034 
1035     // Figure out if the W3C box model works as expected
1036     // document.body must exist before we can do this
1037     jQuery(function() {
1038         var div = document.createElement("div");
1039         div.style.width = div.style.paddingLeft = "1px";
1040 
1041         document.body.appendChild( div );
1042         jQuery.boxModel = jQuery.support.boxModel = div.offsetWidth === 2;
1043 
1044         if ( "zoom" in div.style ) {
1045             // Check if natively block-level elements act like inline-block
1046             // elements when setting their display to 'inline' and giving
1047             // them layout
1048             // (IE < 8 does this)
1049             div.style.display = "inline";
1050             div.style.zoom = 1;
1051             jQuery.support.inlineBlockNeedsLayout = div.offsetWidth === 2;
1052 
1053             // Check if elements with layout shrink-wrap their children
1054             // (IE 6 does this)
1055             div.style.display = "";
1056             div.innerHTML = "<div style='width:4px;'></div>";
1057             jQuery.support.shrinkWrapBlocks = div.offsetWidth !== 2;
1058         }
1059 
1060         div.innerHTML = "<table><tr><td style='padding:0;display:none'></td><td>t</td></tr></table>";
1061         var tds = div.getElementsByTagName("td");
1062 
1063         // Check if table cells still have offsetWidth/Height when they are set
1064         // to display:none and there are still other visible table cells in a
1065         // table row; if so, offsetWidth/Height are not reliable for use when
1066         // determining if an element has been hidden directly using
1067         // display:none (it is still safe to use offsets if a parent element is
1068         // hidden; don safety goggles and see bug #4512 for more information).
1069         // (only IE 8 fails this test)
1070         jQuery.support.reliableHiddenOffsets = tds[0].offsetHeight === 0;
1071 
1072         tds[0].style.display = "";
1073         tds[1].style.display = "none";
1074 
1075         // Check if empty table cells still have offsetWidth/Height
1076         // (IE < 8 fail this test)
1077         jQuery.support.reliableHiddenOffsets = jQuery.support.reliableHiddenOffsets && tds[0].offsetHeight === 0;
1078         div.innerHTML = "";
1079 
1080         document.body.removeChild( div ).style.display = "none";
1081         div = tds = null;
1082     });
1083 
1084     // Technique from Juriy Zaytsev
1085     // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/
1086     var eventSupported = function( eventName ) {
1087         var el = document.createElement("div");
1088         eventName = "on" + eventName;
1089 
1090         var isSupported = (eventName in el);
1091         if ( !isSupported ) {
1092             el.setAttribute(eventName, "return;");
1093             isSupported = typeof el[eventName] === "function";
1094         }
1095         el = null;
1096 
1097         return isSupported;
1098     };
1099 
1100     jQuery.support.submitBubbles = eventSupported("submit");
1101     jQuery.support.changeBubbles = eventSupported("change");
1102 
1103     // release memory in IE
1104     root = script = div = all = a = null;
1105 })();
1106 
1107 
1108 
1109 var windowData = {},
1110     rbrace = /^(?:\{.*\}|\[.*\])$/;
1111 
1112 jQuery.extend({
1113     cache: {},
1114 
1115     // Please use with caution
1116     uuid: 0,
1117 
1118     // Unique for each copy of jQuery on the page    
1119     expando: "jQuery" + jQuery.now(),
1120 
1121     // The following elements throw uncatchable exceptions if you
1122     // attempt to add expando properties to them.
1123     noData: {
1124         "embed": true,
1125         // Ban all objects except for Flash (which handle expandos)
1126         "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",
1127         "applet": true
1128     },
1129 
1130     data: function( elem, name, data ) {
1131         if ( !jQuery.acceptData( elem ) ) {
1132             return;
1133         }
1134 
1135         elem = elem == window ?
1136             windowData :
1137             elem;
1138 
1139         var isNode = elem.nodeType,
1140             id = isNode ? elem[ jQuery.expando ] : null,
1141             cache = jQuery.cache, thisCache;
1142 
1143         if ( isNode && !id && typeof name === "string" && data === undefined ) {
1144             return;
1145         }
1146 
1147         // Get the data from the object directly
1148         if ( !isNode ) {
1149             cache = elem;
1150 
1151         // Compute a unique ID for the element
1152         } else if ( !id ) {
1153             elem[ jQuery.expando ] = id = ++jQuery.uuid;
1154         }
1155 
1156         // Avoid generating a new cache unless none exists and we
1157         // want to manipulate it.
1158         if ( typeof name === "object" ) {
1159             if ( isNode ) {
1160                 cache[ id ] = jQuery.extend(cache[ id ], name);
1161 
1162             } else {
1163                 jQuery.extend( cache, name );
1164             }
1165 
1166         } else if ( isNode && !cache[ id ] ) {
1167             cache[ id ] = {};
1168         }
1169 
1170         thisCache = isNode ? cache[ id ] : cache;
1171 
1172         // Prevent overriding the named cache with undefined values
1173         if ( data !== undefined ) {
1174             thisCache[ name ] = data;
1175         }
1176 
1177         return typeof name === "string" ? thisCache[ name ] : thisCache;
1178     },
1179 
1180     removeData: function( elem, name ) {
1181         if ( !jQuery.acceptData( elem ) ) {
1182             return;
1183         }
1184 
1185         elem = elem == window ?
1186             windowData :
1187             elem;
1188 
1189         var isNode = elem.nodeType,
1190             id = isNode ? elem[ jQuery.expando ] : elem,
1191             cache = jQuery.cache,
1192             thisCache = isNode ? cache[ id ] : id;
1193 
1194         // If we want to remove a specific section of the element's data
1195         if ( name ) {
1196             if ( thisCache ) {
1197                 // Remove the section of cache data
1198                 delete thisCache[ name ];
1199 
1200                 // If we've removed all the data, remove the element's cache
1201                 if ( isNode && jQuery.isEmptyObject(thisCache) ) {
1202                     jQuery.removeData( elem );
1203                 }
1204             }
1205 
1206         // Otherwise, we want to remove all of the element's data
1207         } else {
1208             if ( isNode && jQuery.support.deleteExpando ) {
1209                 delete elem[ jQuery.expando ];
1210 
1211             } else if ( elem.removeAttribute ) {
1212                 elem.removeAttribute( jQuery.expando );
1213 
1214             // Completely remove the data cache
1215             } else if ( isNode ) {
1216                 delete cache[ id ];
1217 
1218             // Remove all fields from the object
1219             } else {
1220                 for ( var n in elem ) {
1221                     delete elem[ n ];
1222                 }
1223             }
1224         }
1225     },
1226 
1227     // A method for determining if a DOM node can handle the data expando
1228     acceptData: function( elem ) {
1229         if ( elem.nodeName ) {
1230             var match = jQuery.noData[ elem.nodeName.toLowerCase() ];
1231 
1232             if ( match ) {
1233                 return !(match === true || elem.getAttribute("classid") !== match);
1234             }
1235         }
1236 
1237         return true;
1238     }
1239 });
1240 
1241 jQuery.fn.extend({
1242     data: function( key, value ) {
1243         var data = null;
1244 
1245         if ( typeof key === "undefined" ) {
1246             if ( this.length ) {
1247                 var attr = this[0].attributes, name;
1248                 data = jQuery.data( this[0] );
1249 
1250                 for ( var i = 0, l = attr.length; i < l; i++ ) {
1251                     name = attr[i].name;
1252 
1253                     if ( name.indexOf( "data-" ) === 0 ) {
1254                         name = name.substr( 5 );
1255                         dataAttr( this[0], name, data[ name ] );
1256                     }
1257                 }
1258             }
1259 
1260             return data;
1261 
1262         } else if ( typeof key === "object" ) {
1263             return this.each(function() {
1264                 jQuery.data( this, key );
1265             });
1266         }
1267 
1268         var parts = key.split(".");
1269         parts[1] = parts[1] ? "." + parts[1] : "";
1270 
1271         if ( value === undefined ) {
1272             data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);
1273 
1274             // Try to fetch any internally stored data first
1275             if ( data === undefined && this.length ) {
1276                 data = jQuery.data( this[0], key );
1277                 data = dataAttr( this[0], key, data );
1278             }
1279 
1280             return data === undefined && parts[1] ?
1281                 this.data( parts[0] ) :
1282                 data;
1283 
1284         } else {
1285             return this.each(function() {
1286                 var $this = jQuery( this ),
1287                     args = [ parts[0], value ];
1288 
1289                 $this.triggerHandler( "setData" + parts[1] + "!", args );
1290                 jQuery.data( this, key, value );
1291                 $this.triggerHandler( "changeData" + parts[1] + "!", args );
1292             });
1293         }
1294     },
1295 
1296     removeData: function( key ) {
1297         return this.each(function() {
1298             jQuery.removeData( this, key );
1299         });
1300     }
1301 });
1302 
1303 function dataAttr( elem, key, data ) {
1304     // If nothing was found internally, try to fetch any
1305     // data from the HTML5 data-* attribute
1306     if ( data === undefined && elem.nodeType === 1 ) {
1307         data = elem.getAttribute( "data-" + key );
1308 
1309         if ( typeof data === "string" ) {
1310             try {
1311                 data = data === "true" ? true :
1312                 data === "false" ? false :
1313                 data === "null" ? null :
1314                 !jQuery.isNaN( data ) ? parseFloat( data ) :
1315                     rbrace.test( data ) ? jQuery.parseJSON( data ) :
1316                     data;
1317             } catch( e ) {}
1318 
1319             // Make sure we set the data so it isn't changed later
1320             jQuery.data( elem, key, data );
1321 
1322         } else {
1323             data = undefined;
1324         }
1325     }
1326 
1327     return data;
1328 }
1329 
1330 
1331 
1332 
1333 jQuery.extend({
1334     queue: function( elem, type, data ) {
1335         if ( !elem ) {
1336             return;
1337         }
1338 
1339         type = (type || "fx") + "queue";
1340         var q = jQuery.data( elem, type );
1341 
1342         // Speed up dequeue by getting out quickly if this is just a lookup
1343         if ( !data ) {
1344             return q || [];
1345         }
1346 
1347         if ( !q || jQuery.isArray(data) ) {
1348             q = jQuery.data( elem, type, jQuery.makeArray(data) );
1349 
1350         } else {
1351             q.push( data );
1352         }
1353 
1354         return q;
1355     },
1356 
1357     dequeue: function( elem, type ) {
1358         type = type || "fx";
1359 
1360         var queue = jQuery.queue( elem, type ),
1361             fn = queue.shift();
1362 
1363         // If the fx queue is dequeued, always remove the progress sentinel
1364         if ( fn === "inprogress" ) {
1365             fn = queue.shift();
1366         }
1367 
1368         if ( fn ) {
1369             // Add a progress sentinel to prevent the fx queue from being
1370             // automatically dequeued
1371             if ( type === "fx" ) {
1372                 queue.unshift("inprogress");
1373             }
1374 
1375             fn.call(elem, function() {
1376                 jQuery.dequeue(elem, type);
1377             });
1378         }
1379     }
1380 });
1381 
1382 jQuery.fn.extend({
1383     queue: function( type, data ) {
1384         if ( typeof type !== "string" ) {
1385             data = type;
1386             type = "fx";
1387         }
1388 
1389         if ( data === undefined ) {
1390             return jQuery.queue( this[0], type );
1391         }
1392         return this.each(function( i ) {
1393             var queue = jQuery.queue( this, type, data );
1394 
1395             if ( type === "fx" && queue[0] !== "inprogress" ) {
1396                 jQuery.dequeue( this, type );
1397             }
1398         });
1399     },
1400     dequeue: function( type ) {
1401         return this.each(function() {
1402             jQuery.dequeue( this, type );
1403         });
1404     },
1405 
1406     // Based off of the plugin by Clint Helfers, with permission.
1407     // http://blindsignals.com/index.php/2009/07/jquery-delay/
1408     delay: function( time, type ) {
1409         time = jQuery.fx ? jQuery.fx.speeds[time] || time : time;
1410         type = type || "fx";
1411 
1412         return this.queue( type, function() {
1413             var elem = this;
1414             setTimeout(function() {
1415                 jQuery.dequeue( elem, type );
1416             }, time );
1417         });
1418     },
1419 
1420     clearQueue: function( type ) {
1421         return this.queue( type || "fx", [] );
1422     }
1423 });
1424 
1425 
1426 
1427 
1428 var rclass = /[\n\t]/g,
1429     rspaces = /\s+/,
1430     rreturn = /\r/g,
1431     rspecialurl = /^(?:href|src|style)$/,
1432     rtype = /^(?:button|input)$/i,
1433     rfocusable = /^(?:button|input|object|select|textarea)$/i,
1434     rclickable = /^a(?:rea)?$/i,
1435     rradiocheck = /^(?:radio|checkbox)$/i;
1436 
1437 jQuery.props = {
1438     "for": "htmlFor",
1439     "class": "className",
1440     readonly: "readOnly",
1441     maxlength: "maxLength",
1442     cellspacing: "cellSpacing",
1443     rowspan: "rowSpan",
1444     colspan: "colSpan",
1445     tabindex: "tabIndex",
1446     usemap: "useMap",
1447     frameborder: "frameBorder"
1448 };
1449 
1450 jQuery.fn.extend({
1451     attr: function( name, value ) {
1452         return jQuery.access( this, name, value, true, jQuery.attr );
1453     },
1454 
1455     removeAttr: function( name, fn ) {
1456         return this.each(function(){
1457             jQuery.attr( this, name, "" );
1458             if ( this.nodeType === 1 ) {
1459                 this.removeAttribute( name );
1460             }
1461         });
1462     },
1463 
1464     addClass: function( value ) {
1465         if ( jQuery.isFunction(value) ) {
1466             return this.each(function(i) {
1467                 var self = jQuery(this);
1468                 self.addClass( value.call(this, i, self.attr("class")) );
1469             });
1470         }
1471 
1472         if ( value && typeof value === "string" ) {
1473             var classNames = (value || "").split( rspaces );
1474 
1475             for ( var i = 0, l = this.length; i < l; i++ ) {
1476                 var elem = this[i];
1477 
1478                 if ( elem.nodeType === 1 ) {
1479                     if ( !elem.className ) {
1480                         elem.className = value;
1481 
1482                     } else {
1483                         var className = " " + elem.className + " ",
1484                             setClass = elem.className;
1485 
1486                         for ( var c = 0, cl = classNames.length; c < cl; c++ ) {
1487                             if ( className.indexOf( " " + classNames[c] + " " ) < 0 ) {
1488                                 setClass += " " + classNames[c];
1489                             }
1490                         }
1491                         elem.className = jQuery.trim( setClass );
1492                     }
1493                 }
1494             }
1495         }
1496 
1497         return this;
1498     },
1499 
1500     removeClass: function( value ) {
1501         if ( jQuery.isFunction(value) ) {
1502             return this.each(function(i) {
1503                 var self = jQuery(this);
1504                 self.removeClass( value.call(this, i, self.attr("class")) );
1505             });
1506         }
1507 
1508         if ( (value && typeof value === "string") || value === undefined ) {
1509             var classNames = (value || "").split( rspaces );
1510 
1511             for ( var i = 0, l = this.length; i < l; i++ ) {
1512                 var elem = this[i];
1513 
1514                 if ( elem.nodeType === 1 && elem.className ) {
1515                     if ( value ) {
1516                         var className = (" " + elem.className + " ").replace(rclass, " ");
1517                         for ( var c = 0, cl = classNames.length; c < cl; c++ ) {
1518                             className = className.replace(" " + classNames[c] + " ", " ");
1519                         }
1520                         elem.className = jQuery.trim( className );
1521 
1522                     } else {
1523                         elem.className = "";
1524                     }
1525                 }
1526             }
1527         }
1528 
1529         return this;
1530     },
1531 
1532     toggleClass: function( value, stateVal ) {
1533         var type = typeof value,
1534             isBool = typeof stateVal === "boolean";
1535 
1536         if ( jQuery.isFunction( value ) ) {
1537             return this.each(function(i) {
1538                 var self = jQuery(this);
1539                 self.toggleClass( value.call(this, i, self.attr("class"), stateVal), stateVal );
1540             });
1541         }
1542 
1543         return this.each(function() {
1544             if ( type === "string" ) {
1545                 // toggle individual class names
1546                 var className,
1547                     i = 0,
1548                     self = jQuery( this ),
1549                     state = stateVal,
1550                     classNames = value.split( rspaces );
1551 
1552                 while ( (className = classNames[ i++ ]) ) {
1553                     // check each className given, space seperated list
1554                     state = isBool ? state : !self.hasClass( className );
1555                     self[ state ? "addClass" : "removeClass" ]( className );
1556                 }
1557 
1558             } else if ( type === "undefined" || type === "boolean" ) {
1559                 if ( this.className ) {
1560                     // store className if set
1561                     jQuery.data( this, "__className__", this.className );
1562                 }
1563 
1564                 // toggle whole className
1565                 this.className = this.className || value === false ? "" : jQuery.data( this, "__className__" ) || "";
1566             }
1567         });
1568     },
1569 
1570     hasClass: function( selector ) {
1571         var className = " " + selector + " ";
1572         for ( var i = 0, l = this.length; i < l; i++ ) {
1573             if ( (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) {
1574                 return true;
1575             }
1576         }
1577 
1578         return false;
1579     },
1580 
1581     val: function( value ) {
1582         if ( !arguments.length ) {
1583             var elem = this[0];
1584 
1585             if ( elem ) {
1586                 if ( jQuery.nodeName( elem, "option" ) ) {
1587                     // attributes.value is undefined in Blackberry 4.7 but
1588                     // uses .value. See #6932
1589                     var val = elem.attributes.value;
1590                     return !val || val.specified ? elem.value : elem.text;
1591                 }
1592 
1593                 // We need to handle select boxes special
1594                 if ( jQuery.nodeName( elem, "select" ) ) {
1595                     var index = elem.selectedIndex,
1596                         values = [],
1597                         options = elem.options,
1598                         one = elem.type === "select-one";
1599 
1600                     // Nothing was selected
1601                     if ( index < 0 ) {
1602                         return null;
1603                     }
1604 
1605                     // Loop through all the selected options
1606                     for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) {
1607                         var option = options[ i ];
1608 
1609                         // Don't return options that are disabled or in a disabled optgroup
1610                         if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && 
1611                                 (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) {
1612 
1613                             // Get the specific value for the option
1614                             value = jQuery(option).val();
1615 
1616                             // We don't need an array for one selects
1617                             if ( one ) {
1618                                 return value;
1619                             }
1620 
1621                             // Multi-Selects return an array
1622                             values.push( value );
1623                         }
1624                     }
1625 
1626                     return values;
1627                 }
1628 
1629                 // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
1630                 if ( rradiocheck.test( elem.type ) && !jQuery.support.checkOn ) {
1631                     return elem.getAttribute("value") === null ? "on" : elem.value;
1632                 }
1633                 
1634 
1635                 // Everything else, we just grab the value
1636                 return (elem.value || "").replace(rreturn, "");
1637 
1638             }
1639 
1640             return undefined;
1641         }
1642 
1643         var isFunction = jQuery.isFunction(value);
1644 
1645         return this.each(function(i) {
1646             var self = jQuery(this), val = value;
1647 
1648             if ( this.nodeType !== 1 ) {
1649                 return;
1650             }
1651 
1652             if ( isFunction ) {
1653                 val = value.call(this, i, self.val());
1654             }
1655 
1656             // Treat null/undefined as ""; convert numbers to string
1657             if ( val == null ) {
1658                 val = "";
1659             } else if ( typeof val === "number" ) {
1660                 val += "";
1661             } else if ( jQuery.isArray(val) ) {
1662                 val = jQuery.map(val, function (value) {
1663                     return value == null ? "" : value + "";
1664                 });
1665             }
1666 
1667             if ( jQuery.isArray(val) && rradiocheck.test( this.type ) ) {
1668                 this.checked = jQuery.inArray( self.val(), val ) >= 0;
1669 
1670             } else if ( jQuery.nodeName( this, "select" ) ) {
1671                 var values = jQuery.makeArray(val);
1672 
1673                 jQuery( "option", this ).each(function() {
1674                     this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;
1675                 });
1676 
1677                 if ( !values.length ) {
1678                     this.selectedIndex = -1;
1679                 }
1680 
1681             } else {
1682                 this.value = val;
1683             }
1684         });
1685     }
1686 });
1687 
1688 jQuery.extend({
1689     attrFn: {
1690         val: true,
1691         css: true,
1692         html: true,
1693         text: true,
1694         data: true,
1695         width: true,
1696         height: true,
1697         offset: true
1698     },
1699         
1700     attr: function( elem, name, value, pass ) {
1701         // don't set attributes on text and comment nodes
1702         if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) {
1703             return undefined;
1704         }
1705 
1706         if ( pass && name in jQuery.attrFn ) {
1707             return jQuery(elem)[name](value);
1708         }
1709 
1710         var notxml = elem.nodeType !== 1 || !jQuery.isXMLDoc( elem ),
1711             // Whether we are setting (or getting)
1712             set = value !== undefined;
1713 
1714         // Try to normalize/fix the name
1715         name = notxml && jQuery.props[ name ] || name;
1716 
1717         // These attributes require special treatment
1718         var special = rspecialurl.test( name );
1719 
1720         // Safari mis-reports the default selected property of an option
1721         // Accessing the parent's selectedIndex property fixes it
1722         if ( name === "selected" && !jQuery.support.optSelected ) {
1723             var parent = elem.parentNode;
1724             if ( parent ) {
1725                 parent.selectedIndex;
1726 
1727                 // Make sure that it also works with optgroups, see #5701
1728                 if ( parent.parentNode ) {
1729                     parent.parentNode.selectedIndex;
1730                 }
1731             }
1732         }
1733 
1734         // If applicable, access the attribute via the DOM 0 way
1735         // 'in' checks fail in Blackberry 4.7 #6931
1736         if ( (name in elem || elem[ name ] !== undefined) && notxml && !special ) {
1737             if ( set ) {
1738                 // We can't allow the type property to be changed (since it causes problems in IE)
1739                 if ( name === "type" && rtype.test( elem.nodeName ) && elem.parentNode ) {
1740                     jQuery.error( "type property can't be changed" );
1741                 }
1742 
1743                 if ( value === null ) {
1744                     if ( elem.nodeType === 1 ) {
1745                         elem.removeAttribute( name );
1746                     }
1747 
1748                 } else {
1749                     elem[ name ] = value;
1750                 }
1751             }
1752 
1753             // browsers index elements by id/name on forms, give priority to attributes.
1754             if ( jQuery.nodeName( elem, "form" ) && elem.getAttributeNode(name) ) {
1755                 return elem.getAttributeNode( name ).nodeValue;
1756             }
1757 
1758             // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
1759             // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
1760             if ( name === "tabIndex" ) {
1761                 var attributeNode = elem.getAttributeNode( "tabIndex" );
1762 
1763                 return attributeNode && attributeNode.specified ?
1764                     attributeNode.value :
1765                     rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
1766                         0 :
1767                         undefined;
1768             }
1769 
1770             return elem[ name ];
1771         }
1772 
1773         if ( !jQuery.support.style && notxml && name === "style" ) {
1774             if ( set ) {
1775                 elem.style.cssText = "" + value;
1776             }
1777 
1778             return elem.style.cssText;
1779         }
1780 
1781         if ( set ) {
1782             // convert the value to a string (all browsers do this but IE) see #1070
1783             elem.setAttribute( name, "" + value );
1784         }
1785 
1786         // Ensure that missing attributes return undefined
1787         // Blackberry 4.7 returns "" from getAttribute #6938
1788         if ( !elem.attributes[ name ] && (elem.hasAttribute && !elem.hasAttribute( name )) ) {
1789             return undefined;
1790         }
1791 
1792         var attr = !jQuery.support.hrefNormalized && notxml && special ?
1793                 // Some attributes require a special call on IE
1794                 elem.getAttribute( name, 2 ) :
1795                 elem.getAttribute( name );
1796 
1797         // Non-existent attributes return null, we normalize to undefined
1798         return attr === null ? undefined : attr;
1799     }
1800 });
1801 
1802 
1803 
1804 
1805 var rnamespaces = /\.(.*)$/,
1806     rformElems = /^(?:textarea|input|select)$/i,
1807     rperiod = /\./g,
1808     rspace = / /g,
1809     rescape = /[^\w\s.|`]/g,
1810     fcleanup = function( nm ) {
1811         return nm.replace(rescape, "\\$&");
1812     },
1813     focusCounts = { focusin: 0, focusout: 0 };
1814 
1815 /*
1816  * A number of helper functions used for managing events.
1817  * Many of the ideas behind this code originated from
1818  * Dean Edwards' addEvent library.
1819  */
1820 jQuery.event = {
1821 
1822     // Bind an event to an element
1823     // Original by Dean Edwards
1824     add: function( elem, types, handler, data ) {
1825         if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
1826             return;
1827         }
1828 
1829         // For whatever reason, IE has trouble passing the window object
1830         // around, causing it to be cloned in the process
1831         if ( jQuery.isWindow( elem ) && ( elem !== window && !elem.frameElement ) ) {
1832             elem = window;
1833         }
1834 
1835         if ( handler === false ) {
1836             handler = returnFalse;
1837         } else if ( !handler ) {
1838             // Fixes bug #7229. Fix recommended by jdalton
1839           return;
1840         }
1841 
1842         var handleObjIn, handleObj;
1843 
1844         if ( handler.handler ) {
1845             handleObjIn = handler;
1846             handler = handleObjIn.handler;
1847         }
1848 
1849         // Make sure that the function being executed has a unique ID
1850         if ( !handler.guid ) {
1851             handler.guid = jQuery.guid++;
1852         }
1853 
1854         // Init the element's event structure
1855         var elemData = jQuery.data( elem );
1856 
1857         // If no elemData is found then we must be trying to bind to one of the
1858         // banned noData elements
1859         if ( !elemData ) {
1860             return;
1861         }
1862 
1863         // Use a key less likely to result in collisions for plain JS objects.
1864         // Fixes bug #7150.
1865         var eventKey = elem.nodeType ? "events" : "__events__",
1866             events = elemData[ eventKey ],
1867             eventHandle = elemData.handle;
1868             
1869         if ( typeof events === "function" ) {
1870             // On plain objects events is a fn that holds the the data
1871             // which prevents this data from being JSON serialized
1872             // the function does not need to be called, it just contains the data
1873             eventHandle = events.handle;
1874             events = events.events;
1875 
1876         } else if ( !events ) {
1877             if ( !elem.nodeType ) {
1878                 // On plain objects, create a fn that acts as the holder
1879                 // of the values to avoid JSON serialization of event data
1880                 elemData[ eventKey ] = elemData = function(){};
1881             }
1882 
1883             elemData.events = events = {};
1884         }
1885 
1886         if ( !eventHandle ) {
1887             elemData.handle = eventHandle = function() {
1888                 // Handle the second event of a trigger and when
1889                 // an event is called after a page has unloaded
1890                 return typeof jQuery !== "undefined" && !jQuery.event.triggered ?
1891                     jQuery.event.handle.apply( eventHandle.elem, arguments ) :
1892                     undefined;
1893             };
1894         }
1895 
1896         // Add elem as a property of the handle function
1897         // This is to prevent a memory leak with non-native events in IE.
1898         eventHandle.elem = elem;
1899 
1900         // Handle multiple events separated by a space
1901         // jQuery(...).bind("mouseover mouseout", fn);
1902         types = types.split(" ");
1903 
1904         var type, i = 0, namespaces;
1905 
1906         while ( (type = types[ i++ ]) ) {
1907             handleObj = handleObjIn ?
1908                 jQuery.extend({}, handleObjIn) :
1909                 { handler: handler, data: data };
1910 
1911             // Namespaced event handlers
1912             if ( type.indexOf(".") > -1 ) {
1913                 namespaces = type.split(".");
1914                 type = namespaces.shift();
1915                 handleObj.namespace = namespaces.slice(0).sort().join(".");
1916 
1917             } else {
1918                 namespaces = [];
1919                 handleObj.namespace = "";
1920             }
1921 
1922             handleObj.type = type;
1923             if ( !handleObj.guid ) {
1924                 handleObj.guid = handler.guid;
1925             }
1926 
1927             // Get the current list of functions bound to this event
1928             var handlers = events[ type ],
1929                 special = jQuery.event.special[ type ] || {};
1930 
1931             // Init the event handler queue
1932             if ( !handlers ) {
1933                 handlers = events[ type ] = [];
1934 
1935                 // Check for a special event handler
1936                 // Only use addEventListener/attachEvent if the special
1937                 // events handler returns false
1938                 if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
1939                     // Bind the global event handler to the element
1940                     if ( elem.addEventListener ) {
1941                         elem.addEventListener( type, eventHandle, false );
1942 
1943                     } else if ( elem.attachEvent ) {
1944                         elem.attachEvent( "on" + type, eventHandle );
1945                     }
1946                 }
1947             }
1948             
1949             if ( special.add ) { 
1950                 special.add.call( elem, handleObj ); 
1951 
1952                 if ( !handleObj.handler.guid ) {
1953                     handleObj.handler.guid = handler.guid;
1954                 }
1955             }
1956 
1957             // Add the function to the element's handler list
1958             handlers.push( handleObj );
1959 
1960             // Keep track of which events have been used, for global triggering
1961             jQuery.event.global[ type ] = true;
1962         }
1963 
1964         // Nullify elem to prevent memory leaks in IE
1965         elem = null;
1966     },
1967 
1968     global: {},
1969 
1970     // Detach an event or set of events from an element
1971     remove: function( elem, types, handler, pos ) {
1972         // don't do events on text and comment nodes
1973         if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
1974             return;
1975         }
1976 
1977         if ( handler === false ) {
1978             handler = returnFalse;
1979         }
1980 
1981         var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType,
1982             eventKey = elem.nodeType ? "events" : "__events__",
1983             elemData = jQuery.data( elem ),
1984             events = elemData && elemData[ eventKey ];
1985 
1986         if ( !elemData || !events ) {
1987             return;
1988         }
1989         
1990         if ( typeof events === "function" ) {
1991             elemData = events;
1992             events = events.events;
1993         }
1994 
1995         // types is actually an event object here
1996         if ( types && types.type ) {
1997             handler = types.handler;
1998             types = types.type;
1999         }
2000 
2001         // Unbind all events for the element
2002         if ( !types || typeof types === "string" && types.charAt(0) === "." ) {
2003             types = types || "";
2004 
2005             for ( type in events ) {
2006                 jQuery.event.remove( elem, type + types );
2007             }
2008 
2009             return;
2010         }
2011 
2012         // Handle multiple events separated by a space
2013         // jQuery(...).unbind("mouseover mouseout", fn);
2014         types = types.split(" ");
2015 
2016         while ( (type = types[ i++ ]) ) {
2017             origType = type;
2018             handleObj = null;
2019             all = type.indexOf(".") < 0;
2020             namespaces = [];
2021 
2022             if ( !all ) {
2023                 // Namespaced event handlers
2024                 namespaces = type.split(".");
2025                 type = namespaces.shift();
2026 
2027                 namespace = new RegExp("(^|\\.)" + 
2028                     jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)");
2029             }
2030 
2031             eventType = events[ type ];
2032 
2033             if ( !eventType ) {
2034                 continue;
2035             }
2036 
2037             if ( !handler ) {
2038                 for ( j = 0; j < eventType.length; j++ ) {
2039                     handleObj = eventType[ j ];
2040 
2041                     if ( all || namespace.test( handleObj.namespace ) ) {
2042                         jQuery.event.remove( elem, origType, handleObj.handler, j );
2043                         eventType.splice( j--, 1 );
2044                     }
2045                 }
2046 
2047                 continue;
2048             }
2049 
2050             special = jQuery.event.special[ type ] || {};
2051 
2052             for ( j = pos || 0; j < eventType.length; j++ ) {
2053                 handleObj = eventType[ j ];
2054 
2055                 if ( handler.guid === handleObj.guid ) {
2056                     // remove the given handler for the given type
2057                     if ( all || namespace.test( handleObj.namespace ) ) {
2058                         if ( pos == null ) {
2059                             eventType.splice( j--, 1 );
2060                         }
2061 
2062                         if ( special.remove ) {
2063                             special.remove.call( elem, handleObj );
2064                         }
2065                     }
2066 
2067                     if ( pos != null ) {
2068                         break;
2069                     }
2070                 }
2071             }
2072 
2073             // remove generic event handler if no more handlers exist
2074             if ( eventType.length === 0 || pos != null && eventType.length === 1 ) {
2075                 if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
2076                     jQuery.removeEvent( elem, type, elemData.handle );
2077                 }
2078 
2079                 ret = null;
2080                 delete events[ type ];
2081             }
2082         }
2083 
2084         // Remove the expando if it's no longer used
2085         if ( jQuery.isEmptyObject( events ) ) {
2086             var handle = elemData.handle;
2087             if ( handle ) {
2088                 handle.elem = null;
2089             }
2090 
2091             delete elemData.events;
2092             delete elemData.handle;
2093 
2094             if ( typeof elemData === "function" ) {
2095                 jQuery.removeData( elem, eventKey );
2096 
2097             } else if ( jQuery.isEmptyObject( elemData ) ) {
2098                 jQuery.removeData( elem );
2099             }
2100         }
2101     },
2102 
2103     // bubbling is internal
2104     trigger: function( event, data, elem /*, bubbling */ ) {
2105         // Event object or event type
2106         var type = event.type || event,
2107             bubbling = arguments[3];
2108 
2109         if ( !bubbling ) {
2110             event = typeof event === "object" ?
2111                 // jQuery.Event object
2112                 event[ jQuery.expando ] ? event :
2113                 // Object literal
2114                 jQuery.extend( jQuery.Event(type), event ) :
2115                 // Just the event type (string)
2116                 jQuery.Event(type);
2117 
2118             if ( type.indexOf("!") >= 0 ) {
2119                 event.type = type = type.slice(0, -1);
2120                 event.exclusive = true;
2121             }
2122 
2123             // Handle a global trigger
2124             if ( !elem ) {
2125                 // Don't bubble custom events when global (to avoid too much overhead)
2126                 event.stopPropagation();
2127 
2128                 // Only trigger if we've ever bound an event for it
2129                 if ( jQuery.event.global[ type ] ) {
2130                     jQuery.each( jQuery.cache, function() {
2131                         if ( this.events && this.events[type] ) {
2132                             jQuery.event.trigger( event, data, this.handle.elem );
2133                         }
2134                     });
2135                 }
2136             }
2137 
2138             // Handle triggering a single element
2139 
2140             // don't do events on text and comment nodes
2141             if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) {
2142                 return undefined;
2143             }
2144 
2145             // Clean up in case it is reused
2146             event.result = undefined;
2147             event.target = elem;
2148 
2149             // Clone the incoming data, if any
2150             data = jQuery.makeArray( data );
2151             data.unshift( event );
2152         }
2153 
2154         event.currentTarget = elem;
2155 
2156         // Trigger the event, it is assumed that "handle" is a function
2157         var handle = elem.nodeType ?
2158             jQuery.data( elem, "handle" ) :
2159             (jQuery.data( elem, "__events__" ) || {}).handle;
2160 
2161         if ( handle ) {
2162             handle.apply( elem, data );
2163         }
2164 
2165         var parent = elem.parentNode || elem.ownerDocument;
2166 
2167         // Trigger an inline bound script
2168         try {
2169             if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) {
2170                 if ( elem[ "on" + type ] && elem[ "on" + type ].apply( elem, data ) === false ) {
2171                     event.result = false;
2172                     event.preventDefault();
2173                 }
2174             }
2175 
2176         // prevent IE from throwing an error for some elements with some event types, see #3533
2177         } catch (inlineError) {}
2178 
2179         if ( !event.isPropagationStopped() && parent ) {
2180             jQuery.event.trigger( event, data, parent, true );
2181 
2182         } else if ( !event.isDefaultPrevented() ) {
2183             var old,
2184                 target = event.target,
2185                 targetType = type.replace( rnamespaces, "" ),
2186                 isClick = jQuery.nodeName( target, "a" ) && targetType === "click",
2187                 special = jQuery.event.special[ targetType ] || {};
2188 
2189             if ( (!special._default || special._default.call( elem, event ) === false) && 
2190                 !isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) {
2191 
2192                 try {
2193                     if ( target[ targetType ] ) {
2194                         // Make sure that we don't accidentally re-trigger the onFOO events
2195                         old = target[ "on" + targetType ];
2196 
2197                         if ( old ) {
2198                             target[ "on" + targetType ] = null;
2199                         }
2200 
2201                         jQuery.event.triggered = true;
2202                         target[ targetType ]();
2203                     }
2204 
2205                 // prevent IE from throwing an error for some elements with some event types, see #3533
2206                 } catch (triggerError) {}
2207 
2208                 if ( old ) {
2209                     target[ "on" + targetType ] = old;
2210                 }
2211 
2212                 jQuery.event.triggered = false;
2213             }
2214         }
2215     },
2216 
2217     handle: function( event ) {
2218         var all, handlers, namespaces, namespace_re, events,
2219             namespace_sort = [],
2220             args = jQuery.makeArray( arguments );
2221 
2222         event = args[0] = jQuery.event.fix( event || window.event );
2223         event.currentTarget = this;
2224 
2225         // Namespaced event handlers
2226         all = event.type.indexOf(".") < 0 && !event.exclusive;
2227 
2228         if ( !all ) {
2229             namespaces = event.type.split(".");
2230             event.type = namespaces.shift();
2231             namespace_sort = namespaces.slice(0).sort();
2232             namespace_re = new RegExp("(^|\\.)" + namespace_sort.join("\\.(?:.*\\.)?") + "(\\.|$)");
2233         }
2234 
2235         event.namespace = event.namespace || namespace_sort.join(".");
2236 
2237         events = jQuery.data(this, this.nodeType ? "events" : "__events__");
2238 
2239         if ( typeof events === "function" ) {
2240             events = events.events;
2241         }
2242 
2243         handlers = (events || {})[ event.type ];
2244 
2245         if ( events && handlers ) {
2246             // Clone the handlers to prevent manipulation
2247             handlers = handlers.slice(0);
2248 
2249             for ( var j = 0, l = handlers.length; j < l; j++ ) {
2250                 var handleObj = handlers[ j ];
2251 
2252                 // Filter the functions by class
2253                 if ( all || namespace_re.test( handleObj.namespace ) ) {
2254                     // Pass in a reference to the handler function itself
2255                     // So that we can later remove it
2256                     event.handler = handleObj.handler;
2257                     event.data = handleObj.data;
2258                     event.handleObj = handleObj;
2259     
2260                     var ret = handleObj.handler.apply( this, args );
2261 
2262                     if ( ret !== undefined ) {
2263                         event.result = ret;
2264                         if ( ret === false ) {
2265                             event.preventDefault();
2266                             event.stopPropagation();
2267                         }
2268                     }
2269 
2270                     if ( event.isImmediatePropagationStopped() ) {
2271                         break;
2272                     }
2273                 }
2274             }
2275         }
2276 
2277         return event.result;
2278     },
2279 
2280     props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
2281 
2282     fix: function( event ) {
2283         if ( event[ jQuery.expando ] ) {
2284             return event;
2285         }
2286 
2287         // store a copy of the original event object
2288         // and "clone" to set read-only properties
2289         var originalEvent = event;
2290         event = jQuery.Event( originalEvent );
2291 
2292         for ( var i = this.props.length, prop; i; ) {
2293             prop = this.props[ --i ];
2294             event[ prop ] = originalEvent[ prop ];
2295         }
2296 
2297         // Fix target property, if necessary
2298         if ( !event.target ) {
2299             // Fixes #1925 where srcElement might not be defined either
2300             event.target = event.srcElement || document;
2301         }
2302 
2303         // check if target is a textnode (safari)
2304         if ( event.target.nodeType === 3 ) {
2305             event.target = event.target.parentNode;
2306         }
2307 
2308         // Add relatedTarget, if necessary
2309         if ( !event.relatedTarget && event.fromElement ) {
2310             event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
2311         }
2312 
2313         // Calculate pageX/Y if missing and clientX/Y available
2314         if ( event.pageX == null && event.clientX != null ) {
2315             var doc = document.documentElement,
2316                 body = document.body;
2317 
2318             event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
2319             event.pageY = event.clientY + (doc && doc.scrollTop  || body && body.scrollTop  || 0) - (doc && doc.clientTop  || body && body.clientTop  || 0);
2320         }
2321 
2322         // Add which for key events
2323         if ( event.which == null && (event.charCode != null || event.keyCode != null) ) {
2324             event.which = event.charCode != null ? event.charCode : event.keyCode;
2325         }
2326 
2327         // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
2328         if ( !event.metaKey && event.ctrlKey ) {
2329             event.metaKey = event.ctrlKey;
2330         }
2331 
2332         // Add which for click: 1 === left; 2 === middle; 3 === right
2333         // Note: button is not normalized, so don't use it
2334         if ( !event.which && event.button !== undefined ) {
2335             event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
2336         }
2337 
2338         return event;
2339     },
2340 
2341     // Deprecated, use jQuery.guid instead
2342     guid: 1E8,
2343 
2344     // Deprecated, use jQuery.proxy instead
2345     proxy: jQuery.proxy,
2346 
2347     special: {
2348         ready: {
2349             // Make sure the ready event is setup
2350             setup: jQuery.bindReady,
2351             teardown: jQuery.noop
2352         },
2353 
2354         live: {
2355             add: function( handleObj ) {
2356                 jQuery.event.add( this,
2357                     liveConvert( handleObj.origType, handleObj.selector ),
2358                     jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) ); 
2359             },
2360 
2361             remove: function( handleObj ) {
2362                 jQuery.event.remove( this, liveConvert( handleObj.origType, handleObj.selector ), handleObj );
2363             }
2364         },
2365 
2366         beforeunload: {
2367             setup: function( data, namespaces, eventHandle ) {
2368                 // We only want to do this special case on windows
2369                 if ( jQuery.isWindow( this ) ) {
2370                     this.onbeforeunload = eventHandle;
2371                 }
2372             },
2373 
2374             teardown: function( namespaces, eventHandle ) {
2375                 if ( this.onbeforeunload === eventHandle ) {
2376                     this.onbeforeunload = null;
2377                 }
2378             }
2379         }
2380     }
2381 };
2382 
2383 jQuery.removeEvent = document.removeEventListener ?
2384     function( elem, type, handle ) {
2385         if ( elem.removeEventListener ) {
2386             elem.removeEventListener( type, handle, false );
2387         }
2388     } : 
2389     function( elem, type, handle ) {
2390         if ( elem.detachEvent ) {
2391             elem.detachEvent( "on" + type, handle );
2392         }
2393     };
2394 
2395 jQuery.Event = function( src ) {
2396     // Allow instantiation without the 'new' keyword
2397     if ( !this.preventDefault ) {
2398         return new jQuery.Event( src );
2399     }
2400 
2401     // Event object
2402     if ( src && src.type ) {
2403         this.originalEvent = src;
2404         this.type = src.type;
2405     // Event type
2406     } else {
2407         this.type = src;
2408     }
2409 
2410     // timeStamp is buggy for some events on Firefox(#3843)
2411     // So we won't rely on the native value
2412     this.timeStamp = jQuery.now();
2413 
2414     // Mark it as fixed
2415     this[ jQuery.expando ] = true;
2416 };
2417 
2418 function returnFalse() {
2419     return false;
2420 }
2421 function returnTrue() {
2422     return true;
2423 }
2424 
2425 // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
2426 // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
2427 jQuery.Event.prototype = {
2428     preventDefault: function() {
2429         this.isDefaultPrevented = returnTrue;
2430 
2431         var e = this.originalEvent;
2432         if ( !e ) {
2433             return;
2434         }
2435         
2436         // if preventDefault exists run it on the original event
2437         if ( e.preventDefault ) {
2438             e.preventDefault();
2439 
2440         // otherwise set the returnValue property of the original event to false (IE)
2441         } else {
2442             e.returnValue = false;
2443         }
2444     },
2445     stopPropagation: function() {
2446         this.isPropagationStopped = returnTrue;
2447 
2448         var e = this.originalEvent;
2449         if ( !e ) {
2450             return;
2451         }
2452         // if stopPropagation exists run it on the original event
2453         if ( e.stopPropagation ) {
2454             e.stopPropagation();
2455         }
2456         // otherwise set the cancelBubble property of the original event to true (IE)
2457         e.cancelBubble = true;
2458     },
2459     stopImmediatePropagation: function() {
2460         this.isImmediatePropagationStopped = returnTrue;
2461         this.stopPropagation();
2462     },
2463     isDefaultPrevented: returnFalse,
2464     isPropagationStopped: returnFalse,
2465     isImmediatePropagationStopped: returnFalse
2466 };
2467 
2468 // Checks if an event happened on an element within another element
2469 // Used in jQuery.event.special.mouseenter and mouseleave handlers
2470 var withinElement = function( event ) {
2471     // Check if mouse(over|out) are still within the same parent element
2472     var parent = event.relatedTarget;
2473 
2474     // Firefox sometimes assigns relatedTarget a XUL element
2475     // which we cannot access the parentNode property of
2476     try {
2477         // Traverse up the tree
2478         while ( parent && parent !== this ) {
2479             parent = parent.parentNode;
2480         }
2481 
2482         if ( parent !== this ) {
2483             // set the correct event type
2484             event.type = event.data;
2485 
2486             // handle event if we actually just moused on to a non sub-element
2487             jQuery.event.handle.apply( this, arguments );
2488         }
2489 
2490     // assuming we've left the element since we most likely mousedover a xul element
2491     } catch(e) { }
2492 },
2493 
2494 // In case of event delegation, we only need to rename the event.type,
2495 // liveHandler will take care of the rest.
2496 delegate = function( event ) {
2497     event.type = event.data;
2498     jQuery.event.handle.apply( this, arguments );
2499 };
2500 
2501 // Create mouseenter and mouseleave events
2502 jQuery.each({
2503     mouseenter: "mouseover",
2504     mouseleave: "mouseout"
2505 }, function( orig, fix ) {
2506     jQuery.event.special[ orig ] = {
2507         setup: function( data ) {
2508             jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig );
2509         },
2510         teardown: function( data ) {
2511             jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement );
2512         }
2513     };
2514 });
2515 
2516 // submit delegation
2517 if ( !jQuery.support.submitBubbles ) {
2518 
2519     jQuery.event.special.submit = {
2520         setup: function( data, namespaces ) {
2521             if ( this.nodeName.toLowerCase() !== "form" ) {
2522                 jQuery.event.add(this, "click.specialSubmit", function( e ) {
2523                     var elem = e.target,
2524                         type = elem.type;
2525 
2526                     if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) {
2527                         e.liveFired = undefined;
2528                         return trigger( "submit", this, arguments );
2529                     }
2530                 });
2531      
2532                 jQuery.event.add(this, "keypress.specialSubmit", function( e ) {
2533                     var elem = e.target,
2534                         type = elem.type;
2535 
2536                     if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {
2537                         e.liveFired = undefined;
2538                         return trigger( "submit", this, arguments );
2539                     }
2540                 });
2541 
2542             } else {
2543                 return false;
2544             }
2545         },
2546 
2547         teardown: function( namespaces ) {
2548             jQuery.event.remove( this, ".specialSubmit" );
2549         }
2550     };
2551 
2552 }
2553 
2554 // change delegation, happens here so we have bind.
2555 if ( !jQuery.support.changeBubbles ) {
2556 
2557     var changeFilters,
2558 
2559     getVal = function( elem ) {
2560         var type = elem.type, val = elem.value;
2561 
2562         if ( type === "radio" || type === "checkbox" ) {
2563             val = elem.checked;
2564 
2565         } else if ( type === "select-multiple" ) {
2566             val = elem.selectedIndex > -1 ?
2567                 jQuery.map( elem.options, function( elem ) {
2568                     return elem.selected;
2569                 }).join("-") :
2570                 "";
2571 
2572         } else if ( elem.nodeName.toLowerCase() === "select" ) {
2573             val = elem.selectedIndex;
2574         }
2575 
2576         return val;
2577     },
2578 
2579     testChange = function testChange( e ) {
2580         var elem = e.target, data, val;
2581 
2582         if ( !rformElems.test( elem.nodeName ) || elem.readOnly ) {
2583             return;
2584         }
2585 
2586         data = jQuery.data( elem, "_change_data" );
2587         val = getVal(elem);
2588 
2589         // the current data will be also retrieved by beforeactivate
2590         if ( e.type !== "focusout" || elem.type !== "radio" ) {
2591             jQuery.data( elem, "_change_data", val );
2592         }
2593         
2594         if ( data === undefined || val === data ) {
2595             return;
2596         }
2597 
2598         if ( data != null || val ) {
2599             e.type = "change";
2600             e.liveFired = undefined;
2601             return jQuery.event.trigger( e, arguments[1], elem );
2602         }
2603     };
2604 
2605     jQuery.event.special.change = {
2606         filters: {
2607             focusout: testChange, 
2608 
2609             beforedeactivate: testChange,
2610 
2611             click: function( e ) {
2612                 var elem = e.target, type = elem.type;
2613 
2614                 if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) {
2615                     return testChange.call( this, e );
2616                 }
2617             },
2618 
2619             // Change has to be called before submit
2620             // Keydown will be called before keypress, which is used in submit-event delegation
2621             keydown: function( e ) {
2622                 var elem = e.target, type = elem.type;
2623 
2624                 if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") ||
2625                     (e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
2626                     type === "select-multiple" ) {
2627                     return testChange.call( this, e );
2628                 }
2629             },
2630 
2631             // Beforeactivate happens also before the previous element is blurred
2632             // with this event you can't trigger a change event, but you can store
2633             // information
2634             beforeactivate: function( e ) {
2635                 var elem = e.target;
2636                 jQuery.data( elem, "_change_data", getVal(elem) );
2637             }
2638         },
2639 
2640         setup: function( data, namespaces ) {
2641             if ( this.type === "file" ) {
2642                 return false;
2643             }
2644 
2645             for ( var type in changeFilters ) {
2646                 jQuery.event.add( this, type + ".specialChange", changeFilters[type] );
2647             }
2648 
2649             return rformElems.test( this.nodeName );
2650         },
2651 
2652         teardown: function( namespaces ) {
2653             jQuery.event.remove( this, ".specialChange" );
2654 
2655             return rformElems.test( this.nodeName );
2656         }
2657     };
2658 
2659     changeFilters = jQuery.event.special.change.filters;
2660 
2661     // Handle when the input is .focus()'d
2662     changeFilters.focus = changeFilters.beforeactivate;
2663 }
2664 
2665 function trigger( type, elem, args ) {
2666     args[0].type = type;
2667     return jQuery.event.handle.apply( elem, args );
2668 }
2669 
2670 // Create "bubbling" focus and blur events
2671 if ( document.addEventListener ) {
2672     jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
2673         jQuery.event.special[ fix ] = {
2674             setup: function() {
2675                 if ( focusCounts[fix]++ === 0 ) {
2676                     document.addEventListener( orig, handler, true );
2677                 }
2678             }, 
2679             teardown: function() { 
2680                 if ( --focusCounts[fix] === 0 ) {
2681                     document.removeEventListener( orig, handler, true );
2682                 }
2683             }
2684         };
2685 
2686         function handler( e ) { 
2687             e = jQuery.event.fix( e );
2688             e.type = fix;
2689             return jQuery.event.trigger( e, null, e.target );
2690         }
2691     });
2692 }
2693 
2694 jQuery.each(["bind", "one"], function( i, name ) {
2695     jQuery.fn[ name ] = function( type, data, fn ) {
2696         // Handle object literals
2697         if ( typeof type === "object" ) {
2698             for ( var key in type ) {
2699                 this[ name ](key, data, type[key], fn);
2700             }
2701             return this;
2702         }
2703         
2704         if ( jQuery.isFunction( data ) || data === false ) {
2705             fn = data;
2706             data = undefined;
2707         }
2708 
2709         var handler = name === "one" ? jQuery.proxy( fn, function( event ) {
2710             jQuery( this ).unbind( event, handler );
2711             return fn.apply( this, arguments );
2712         }) : fn;
2713 
2714         if ( type === "unload" && name !== "one" ) {
2715             this.one( type, data, fn );
2716 
2717         } else {
2718             for ( var i = 0, l = this.length; i < l; i++ ) {
2719                 jQuery.event.add( this[i], type, handler, data );
2720             }
2721         }
2722 
2723         return this;
2724     };
2725 });
2726 
2727 jQuery.fn.extend({
2728     unbind: function( type, fn ) {
2729         // Handle object literals
2730         if ( typeof type === "object" && !type.preventDefault ) {
2731             for ( var key in type ) {
2732                 this.unbind(key, type[key]);
2733             }
2734 
2735         } else {
2736             for ( var i = 0, l = this.length; i < l; i++ ) {
2737                 jQuery.event.remove( this[i], type, fn );
2738             }
2739         }
2740 
2741         return this;
2742     },
2743     
2744     delegate: function( selector, types, data, fn ) {
2745         return this.live( types, data, fn, selector );
2746     },
2747     
2748     undelegate: function( selector, types, fn ) {
2749         if ( arguments.length === 0 ) {
2750                 return this.unbind( "live" );
2751         
2752         } else {
2753             return this.die( types, null, fn, selector );
2754         }
2755     },
2756     
2757     trigger: function( type, data ) {
2758         return this.each(function() {
2759             jQuery.event.trigger( type, data, this );
2760         });
2761     },
2762 
2763     triggerHandler: function( type, data ) {
2764         if ( this[0] ) {
2765             var event = jQuery.Event( type );
2766             event.preventDefault();
2767             event.stopPropagation();
2768             jQuery.event.trigger( event, data, this[0] );
2769             return event.result;
2770         }
2771     },
2772 
2773     toggle: function( fn ) {
2774         // Save reference to arguments for access in closure
2775         var args = arguments,
2776             i = 1;
2777 
2778         // link all the functions, so any of them can unbind this click handler
2779         while ( i < args.length ) {
2780             jQuery.proxy( fn, args[ i++ ] );
2781         }
2782 
2783         return this.click( jQuery.proxy( fn, function( event ) {
2784             // Figure out which function to execute
2785             var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i;
2786             jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 );
2787 
2788             // Make sure that clicks stop
2789             event.preventDefault();
2790 
2791             // and execute the function
2792             return args[ lastToggle ].apply( this, arguments ) || false;
2793         }));
2794     },
2795 
2796     hover: function( fnOver, fnOut ) {
2797         return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
2798     }
2799 });
2800 
2801 var liveMap = {
2802     focus: "focusin",
2803     blur: "focusout",
2804     mouseenter: "mouseover",
2805     mouseleave: "mouseout"
2806 };
2807 
2808 jQuery.each(["live", "die"], function( i, name ) {
2809     jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) {
2810         var type, i = 0, match, namespaces, preType,
2811             selector = origSelector || this.selector,
2812             context = origSelector ? this : jQuery( this.context );
2813         
2814         if ( typeof types === "object" && !types.preventDefault ) {
2815             for ( var key in types ) {
2816                 context[ name ]( key, data, types[key], selector );
2817             }
2818             
2819             return this;
2820         }
2821 
2822         if ( jQuery.isFunction( data ) ) {
2823             fn = data;
2824             data = undefined;
2825         }
2826 
2827         types = (types || "").split(" ");
2828 
2829         while ( (type = types[ i++ ]) != null ) {
2830             match = rnamespaces.exec( type );
2831             namespaces = "";
2832 
2833             if ( match )  {
2834                 namespaces = match[0];
2835                 type = type.replace( rnamespaces, "" );
2836             }
2837 
2838             if ( type === "hover" ) {
2839                 types.push( "mouseenter" + namespaces, "mouseleave" + namespaces );
2840                 continue;
2841             }
2842 
2843             preType = type;
2844 
2845             if ( type === "focus" || type === "blur" ) {
2846                 types.push( liveMap[ type ] + namespaces );
2847                 type = type + namespaces;
2848 
2849             } else {
2850                 type = (liveMap[ type ] || type) + namespaces;
2851             }
2852 
2853             if ( name === "live" ) {
2854                 // bind live handler
2855                 for ( var j = 0, l = context.length; j < l; j++ ) {
2856                     jQuery.event.add( context[j], "live." + liveConvert( type, selector ),
2857                         { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } );
2858                 }
2859 
2860             } else {
2861                 // unbind live handler
2862                 context.unbind( "live." + liveConvert( type, selector ), fn );
2863             }
2864         }
2865         
2866         return this;
2867     };
2868 });
2869 
2870 function liveHandler( event ) {
2871     var stop, maxLevel, related, match, handleObj, elem, j, i, l, data, close, namespace, ret,
2872         elems = [],
2873         selectors = [],
2874         events = jQuery.data( this, this.nodeType ? "events" : "__events__" );
2875 
2876     if ( typeof events === "function" ) {
2877         events = events.events;
2878     }
2879 
2880     // Make sure we avoid non-left-click bubbling in Firefox (#3861)
2881     if ( event.liveFired === this || !events || !events.live || event.button && event.type === "click" ) {
2882         return;
2883     }
2884     
2885     if ( event.namespace ) {
2886         namespace = new RegExp("(^|\\.)" + event.namespace.split(".").join("\\.(?:.*\\.)?") + "(\\.|$)");
2887     }
2888 
2889     event.liveFired = this;
2890 
2891     var live = events.live.slice(0);
2892 
2893     for ( j = 0; j < live.length; j++ ) {
2894         handleObj = live[j];
2895 
2896         if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) {
2897             selectors.push( handleObj.selector );
2898 
2899         } else {
2900             live.splice( j--, 1 );
2901         }
2902     }
2903 
2904     match = jQuery( event.target ).closest( selectors, event.currentTarget );
2905 
2906     for ( i = 0, l = match.length; i < l; i++ ) {
2907         close = match[i];
2908 
2909         for ( j = 0; j < live.length; j++ ) {
2910             handleObj = live[j];
2911 
2912             if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) ) {
2913                 elem = close.elem;
2914                 related = null;
2915 
2916                 // Those two events require additional checking
2917                 if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) {
2918                     event.type = handleObj.preType;
2919                     related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0];
2920                 }
2921 
2922                 if ( !related || related !== elem ) {
2923                     elems.push({ elem: elem, handleObj: handleObj, level: close.level });
2924                 }
2925             }
2926         }
2927     }
2928 
2929     for ( i = 0, l = elems.length; i < l; i++ ) {
2930         match = elems[i];
2931 
2932         if ( maxLevel && match.level > maxLevel ) {
2933             break;
2934         }
2935 
2936         event.currentTarget = match.elem;
2937         event.data = match.handleObj.data;
2938         event.handleObj = match.handleObj;
2939 
2940         ret = match.handleObj.origHandler.apply( match.elem, arguments );
2941 
2942         if ( ret === false || event.isPropagationStopped() ) {
2943             maxLevel = match.level;
2944 
2945             if ( ret === false ) {
2946                 stop = false;
2947             }
2948             if ( event.isImmediatePropagationStopped() ) {
2949                 break;
2950             }
2951         }
2952     }
2953 
2954     return stop;
2955 }
2956 
2957 function liveConvert( type, selector ) {
2958     return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspace, "&");
2959 }
2960 
2961 jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
2962     "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
2963     "change select submit keydown keypress keyup error").split(" "), function( i, name ) {
2964 
2965     // Handle event binding
2966     jQuery.fn[ name ] = function( data, fn ) {
2967         if ( fn == null ) {
2968             fn = data;
2969             data = null;
2970         }
2971 
2972         return arguments.length > 0 ?
2973             this.bind( name, data, fn ) :
2974             this.trigger( name );
2975     };
2976 
2977     if ( jQuery.attrFn ) {
2978         jQuery.attrFn[ name ] = true;
2979     }
2980 });
2981 
2982 // Prevent memory leaks in IE
2983 // Window isn't included so as not to unbind existing unload events
2984 // More info:
2985 //  - http://isaacschlueter.com/2006/10/msie-memory-leaks/
2986 if ( window.attachEvent && !window.addEventListener ) {
2987     jQuery(window).bind("unload", function() {
2988         for ( var id in jQuery.cache ) {
2989             if ( jQuery.cache[ id ].handle ) {
2990                 // Try/Catch is to handle iframes being unloaded, see #4280
2991                 try {
2992                     jQuery.event.remove( jQuery.cache[ id ].handle.elem );
2993                 } catch(e) {}
2994             }
2995         }
2996     });
2997 }
2998 
2999 
3000 /*!
3001  * Sizzle CSS Selector Engine - v1.0
3002  *  Copyright 2009, The Dojo Foundation
3003  *  Released under the MIT, BSD, and GPL Licenses.
3004  *  More information: http://sizzlejs.com/
3005  */
3006 (function(){
3007 
3008 var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
3009     done = 0,
3010     toString = Object.prototype.toString,
3011     hasDuplicate = false,
3012     baseHasDuplicate = true;
3013 
3014 // Here we check if the JavaScript engine is using some sort of
3015 // optimization where it does not always call our comparision
3016 // function. If that is the case, discard the hasDuplicate value.
3017 //   Thus far that includes Google Chrome.
3018 [0, 0].sort(function() {
3019     baseHasDuplicate = false;
3020     return 0;
3021 });
3022 
3023 var Sizzle = function( selector, context, results, seed ) {
3024     results = results || [];
3025     context = context || document;
3026 
3027     var origContext = context;
3028 
3029     if ( context.nodeType !== 1 && context.nodeType !== 9 ) {
3030         return [];
3031     }
3032     
3033     if ( !selector || typeof selector !== "string" ) {
3034         return results;
3035     }
3036 
3037     var m, set, checkSet, extra, ret, cur, pop, i,
3038         prune = true,
3039         contextXML = Sizzle.isXML( context ),
3040         parts = [],
3041         soFar = selector;
3042     
3043     // Reset the position of the chunker regexp (start from head)
3044     do {
3045         chunker.exec( "" );
3046         m = chunker.exec( soFar );
3047 
3048         if ( m ) {
3049             soFar = m[3];
3050         
3051             parts.push( m[1] );
3052         
3053             if ( m[2] ) {
3054                 extra = m[3];
3055                 break;
3056             }
3057         }
3058     } while ( m );
3059 
3060     if ( parts.length > 1 && origPOS.exec( selector ) ) {
3061 
3062         if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
3063             set = posProcess( parts[0] + parts[1], context );
3064 
3065         } else {
3066             set = Expr.relative[ parts[0] ] ?
3067                 [ context ] :
3068                 Sizzle( parts.shift(), context );
3069 
3070             while ( parts.length ) {
3071                 selector = parts.shift();
3072 
3073                 if ( Expr.relative[ selector ] ) {
3074                     selector += parts.shift();
3075                 }
3076                 
3077                 set = posProcess( selector, set );
3078             }
3079         }
3080 
3081     } else {
3082         // Take a shortcut and set the context if the root selector is an ID
3083         // (but not if it'll be faster if the inner selector is an ID)
3084         if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
3085                 Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {
3086 
3087             ret = Sizzle.find( parts.shift(), context, contextXML );
3088             context = ret.expr ?
3089                 Sizzle.filter( ret.expr, ret.set )[0] :
3090                 ret.set[0];
3091         }
3092 
3093         if ( context ) {
3094             ret = seed ?
3095                 { expr: parts.pop(), set: makeArray(seed) } :
3096                 Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );
3097 
3098             set = ret.expr ?
3099                 Sizzle.filter( ret.expr, ret.set ) :
3100                 ret.set;
3101 
3102             if ( parts.length > 0 ) {
3103                 checkSet = makeArray( set );
3104 
3105             } else {
3106                 prune = false;
3107             }
3108 
3109             while ( parts.length ) {
3110                 cur = parts.pop();
3111                 pop = cur;
3112 
3113                 if ( !Expr.relative[ cur ] ) {
3114                     cur = "";
3115                 } else {
3116                     pop = parts.pop();
3117                 }
3118 
3119                 if ( pop == null ) {
3120                     pop = context;
3121                 }
3122 
3123                 Expr.relative[ cur ]( checkSet, pop, contextXML );
3124             }
3125 
3126         } else {
3127             checkSet = parts = [];
3128         }
3129     }
3130 
3131     if ( !checkSet ) {
3132         checkSet = set;
3133     }
3134 
3135     if ( !checkSet ) {
3136         Sizzle.error( cur || selector );
3137     }
3138 
3139     if ( toString.call(checkSet) === "[object Array]" ) {
3140         if ( !prune ) {
3141             results.push.apply( results, checkSet );
3142 
3143         } else if ( context && context.nodeType === 1 ) {
3144             for ( i = 0; checkSet[i] != null; i++ ) {
3145                 if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) {
3146                     results.push( set[i] );
3147                 }
3148             }
3149 
3150         } else {
3151             for ( i = 0; checkSet[i] != null; i++ ) {
3152                 if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
3153                     results.push( set[i] );
3154                 }
3155             }
3156         }
3157 
3158     } else {
3159         makeArray( checkSet, results );
3160     }
3161 
3162     if ( extra ) {
3163         Sizzle( extra, origContext, results, seed );
3164         Sizzle.uniqueSort( results );
3165     }
3166 
3167     return results;
3168 };
3169 
3170 Sizzle.uniqueSort = function( results ) {
3171     if ( sortOrder ) {
3172         hasDuplicate = baseHasDuplicate;
3173         results.sort( sortOrder );
3174 
3175         if ( hasDuplicate ) {
3176             for ( var i = 1; i < results.length; i++ ) {
3177                 if ( results[i] === results[ i - 1 ] ) {
3178                     results.splice( i--, 1 );
3179                 }
3180             }
3181         }
3182     }
3183 
3184     return results;
3185 };
3186 
3187 Sizzle.matches = function( expr, set ) {
3188     return Sizzle( expr, null, null, set );
3189 };
3190 
3191 Sizzle.matchesSelector = function( node, expr ) {
3192     return Sizzle( expr, null, null, [node] ).length > 0;
3193 };
3194 
3195 Sizzle.find = function( expr, context, isXML ) {
3196     var set;
3197 
3198     if ( !expr ) {
3199         return [];
3200     }
3201 
3202     for ( var i = 0, l = Expr.order.length; i < l; i++ ) {
3203         var match,
3204             type = Expr.order[i];
3205         
3206         if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {
3207             var left = match[1];
3208             match.splice( 1, 1 );
3209 
3210             if ( left.substr( left.length - 1 ) !== "\\" ) {
3211                 match[1] = (match[1] || "").replace(/\\/g, "");
3212                 set = Expr.find[ type ]( match, context, isXML );
3213 
3214                 if ( set != null ) {
3215                     expr = expr.replace( Expr.match[ type ], "" );
3216                     break;
3217                 }
3218             }
3219         }
3220     }
3221 
3222     if ( !set ) {
3223         set = context.getElementsByTagName( "*" );
3224     }
3225 
3226     return { set: set, expr: expr };
3227 };
3228 
3229 Sizzle.filter = function( expr, set, inplace, not ) {
3230     var match, anyFound,
3231         old = expr,
3232         result = [],
3233         curLoop = set,
3234         isXMLFilter = set && set[0] && Sizzle.isXML( set[0] );
3235 
3236     while ( expr && set.length ) {
3237         for ( var type in Expr.filter ) {
3238             if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {
3239                 var found, item,
3240                     filter = Expr.filter[ type ],
3241                     left = match[1];
3242 
3243                 anyFound = false;
3244 
3245                 match.splice(1,1);
3246 
3247                 if ( left.substr( left.length - 1 ) === "\\" ) {
3248                     continue;
3249                 }
3250 
3251                 if ( curLoop === result ) {
3252                     result = [];
3253                 }
3254 
3255                 if ( Expr.preFilter[ type ] ) {
3256                     match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );
3257 
3258                     if ( !match ) {
3259                         anyFound = found = true;
3260 
3261                     } else if ( match === true ) {
3262                         continue;
3263                     }
3264                 }
3265 
3266                 if ( match ) {
3267                     for ( var i = 0; (item = curLoop[i]) != null; i++ ) {
3268                         if ( item ) {
3269                             found = filter( item, match, i, curLoop );
3270                             var pass = not ^ !!found;
3271 
3272                             if ( inplace && found != null ) {
3273                                 if ( pass ) {
3274                                     anyFound = true;
3275 
3276                                 } else {
3277                                     curLoop[i] = false;
3278                                 }
3279 
3280                             } else if ( pass ) {
3281                                 result.push( item );
3282                                 anyFound = true;
3283                             }
3284                         }
3285                     }
3286                 }
3287 
3288                 if ( found !== undefined ) {
3289                     if ( !inplace ) {
3290                         curLoop = result;
3291                     }
3292 
3293                     expr = expr.replace( Expr.match[ type ], "" );
3294 
3295                     if ( !anyFound ) {
3296                         return [];
3297                     }
3298 
3299                     break;
3300                 }
3301             }
3302         }
3303 
3304         // Improper expression
3305         if ( expr === old ) {
3306             if ( anyFound == null ) {
3307                 Sizzle.error( expr );
3308 
3309             } else {
3310                 break;
3311             }
3312         }
3313 
3314         old = expr;
3315     }
3316 
3317     return curLoop;
3318 };
3319 
3320 Sizzle.error = function( msg ) {
3321     throw "Syntax error, unrecognized expression: " + msg;
3322 };
3323 
3324 var Expr = Sizzle.selectors = {
3325     order: [ "ID", "NAME", "TAG" ],
3326 
3327     match: {
3328         ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
3329         CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
3330         NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,
3331         ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,
3332         TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,
3333         CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+\-]*)\))?/,
3334         POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,
3335         PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/
3336     },
3337 
3338     leftMatch: {},
3339 
3340     attrMap: {
3341         "class": "className",
3342         "for": "htmlFor"
3343     },
3344 
3345     attrHandle: {
3346         href: function( elem ) {
3347             return elem.getAttribute( "href" );
3348         }
3349     },
3350 
3351     relative: {
3352         "+": function(checkSet, part){
3353             var isPartStr = typeof part === "string",
3354                 isTag = isPartStr && !/\W/.test( part ),
3355                 isPartStrNotTag = isPartStr && !isTag;
3356 
3357             if ( isTag ) {
3358                 part = part.toLowerCase();
3359             }
3360 
3361             for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
3362                 if ( (elem = checkSet[i]) ) {
3363                     while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}
3364 
3365                     checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ?
3366                         elem || false :
3367                         elem === part;
3368                 }
3369             }
3370 
3371             if ( isPartStrNotTag ) {
3372                 Sizzle.filter( part, checkSet, true );
3373             }
3374         },
3375 
3376         ">": function( checkSet, part ) {
3377             var elem,
3378                 isPartStr = typeof part === "string",
3379                 i = 0,
3380                 l = checkSet.length;
3381 
3382             if ( isPartStr && !/\W/.test( part ) ) {
3383                 part = part.toLowerCase();
3384 
3385                 for ( ; i < l; i++ ) {
3386                     elem = checkSet[i];
3387 
3388                     if ( elem ) {
3389                         var parent = elem.parentNode;
3390                         checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false;
3391                     }
3392                 }
3393 
3394             } else {
3395                 for ( ; i < l; i++ ) {
3396                     elem = checkSet[i];
3397 
3398                     if ( elem ) {
3399                         checkSet[i] = isPartStr ?
3400                             elem.parentNode :
3401                             elem.parentNode === part;
3402                     }
3403                 }
3404 
3405                 if ( isPartStr ) {
3406                     Sizzle.filter( part, checkSet, true );
3407                 }
3408             }
3409         },
3410 
3411         "": function(checkSet, part, isXML){
3412             var nodeCheck,
3413                 doneName = done++,
3414                 checkFn = dirCheck;
3415 
3416             if ( typeof part === "string" && !/\W/.test(part) ) {
3417                 part = part.toLowerCase();
3418                 nodeCheck = part;
3419                 checkFn = dirNodeCheck;
3420             }
3421 
3422             checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML );
3423         },
3424 
3425         "~": function( checkSet, part, isXML ) {
3426             var nodeCheck,
3427                 doneName = done++,
3428                 checkFn = dirCheck;
3429 
3430             if ( typeof part === "string" && !/\W/.test( part ) ) {
3431                 part = part.toLowerCase();
3432                 nodeCheck = part;
3433                 checkFn = dirNodeCheck;
3434             }
3435 
3436             checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML );
3437         }
3438     },
3439 
3440     find: {
3441         ID: function( match, context, isXML ) {
3442             if ( typeof context.getElementById !== "undefined" && !isXML ) {
3443                 var m = context.getElementById(match[1]);
3444                 // Check parentNode to catch when Blackberry 4.6 returns
3445                 // nodes that are no longer in the document #6963
3446                 return m && m.parentNode ? [m] : [];
3447             }
3448         },
3449 
3450         NAME: function( match, context ) {
3451             if ( typeof context.getElementsByName !== "undefined" ) {
3452                 var ret = [],
3453                     results = context.getElementsByName( match[1] );
3454 
3455                 for ( var i = 0, l = results.length; i < l; i++ ) {
3456                     if ( results[i].getAttribute("name") === match[1] ) {
3457                         ret.push( results[i] );
3458                     }
3459                 }
3460 
3461                 return ret.length === 0 ? null : ret;
3462             }
3463         },
3464 
3465         TAG: function( match, context ) {
3466             return context.getElementsByTagName( match[1] );
3467         }
3468     },
3469     preFilter: {
3470         CLASS: function( match, curLoop, inplace, result, not, isXML ) {
3471             match = " " + match[1].replace(/\\/g, "") + " ";
3472 
3473             if ( isXML ) {
3474                 return match;
3475             }
3476 
3477             for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
3478                 if ( elem ) {
3479                     if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n]/g, " ").indexOf(match) >= 0) ) {
3480                         if ( !inplace ) {
3481                             result.push( elem );
3482                         }
3483 
3484                     } else if ( inplace ) {
3485                         curLoop[i] = false;
3486                     }
3487                 }
3488             }
3489 
3490             return false;
3491         },
3492 
3493         ID: function( match ) {
3494             return match[1].replace(/\\/g, "");
3495         },
3496 
3497         TAG: function( match, curLoop ) {
3498             return match[1].toLowerCase();
3499         },
3500 
3501         CHILD: function( match ) {
3502             if ( match[1] === "nth" ) {
3503                 // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
3504                 var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
3505                     match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" ||
3506                     !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
3507 
3508                 // calculate the numbers (first)n+(last) including if they are negative
3509                 match[2] = (test[1] + (test[2] || 1)) - 0;
3510                 match[3] = test[3] - 0;
3511             }
3512 
3513             // TODO: Move to normal caching system
3514             match[0] = done++;
3515 
3516             return match;
3517         },
3518 
3519         ATTR: function( match, curLoop, inplace, result, not, isXML ) {
3520             var name = match[1].replace(/\\/g, "");
3521             
3522             if ( !isXML && Expr.attrMap[name] ) {
3523                 match[1] = Expr.attrMap[name];
3524             }
3525 
3526             if ( match[2] === "~=" ) {
3527                 match[4] = " " + match[4] + " ";
3528             }
3529 
3530             return match;
3531         },
3532 
3533         PSEUDO: function( match, curLoop, inplace, result, not ) {
3534             if ( match[1] === "not" ) {
3535                 // If we're dealing with a complex expression, or a simple one
3536                 if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) {
3537                     match[3] = Sizzle(match[3], null, null, curLoop);
3538 
3539                 } else {
3540                     var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
3541 
3542                     if ( !inplace ) {
3543                         result.push.apply( result, ret );
3544                     }
3545 
3546                     return false;
3547                 }
3548 
3549             } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
3550                 return true;
3551             }
3552             
3553             return match;
3554         },
3555 
3556         POS: function( match ) {
3557             match.unshift( true );
3558 
3559             return match;
3560         }
3561     },
3562     
3563     filters: {
3564         enabled: function( elem ) {
3565             return elem.disabled === false && elem.type !== "hidden";
3566         },
3567 
3568         disabled: function( elem ) {
3569             return elem.disabled === true;
3570         },
3571 
3572         checked: function( elem ) {
3573             return elem.checked === true;
3574         },
3575         
3576         selected: function( elem ) {
3577             // Accessing this property makes selected-by-default
3578             // options in Safari work properly
3579             elem.parentNode.selectedIndex;
3580             
3581             return elem.selected === true;
3582         },
3583 
3584         parent: function( elem ) {
3585             return !!elem.firstChild;
3586         },
3587 
3588         empty: function( elem ) {
3589             return !elem.firstChild;
3590         },
3591 
3592         has: function( elem, i, match ) {
3593             return !!Sizzle( match[3], elem ).length;
3594         },
3595 
3596         header: function( elem ) {
3597             return (/h\d/i).test( elem.nodeName );
3598         },
3599 
3600         text: function( elem ) {
3601             return "text" === elem.type;
3602         },
3603         radio: function( elem ) {
3604             return "radio" === elem.type;
3605         },
3606 
3607         checkbox: function( elem ) {
3608             return "checkbox" === elem.type;
3609         },
3610 
3611         file: function( elem ) {
3612             return "file" === elem.type;
3613         },
3614         password: function( elem ) {
3615             return "password" === elem.type;
3616         },
3617 
3618         submit: function( elem ) {
3619             return "submit" === elem.type;
3620         },
3621 
3622         image: function( elem ) {
3623             return "image" === elem.type;
3624         },
3625 
3626         reset: function( elem ) {
3627             return "reset" === elem.type;
3628         },
3629 
3630         button: function( elem ) {
3631             return "button" === elem.type || elem.nodeName.toLowerCase() === "button";
3632         },
3633 
3634         input: function( elem ) {
3635             return (/input|select|textarea|button/i).test( elem.nodeName );
3636         }
3637     },
3638     setFilters: {
3639         first: function( elem, i ) {
3640             return i === 0;
3641         },
3642 
3643         last: function( elem, i, match, array ) {
3644             return i === array.length - 1;
3645         },
3646 
3647         even: function( elem, i ) {
3648             return i % 2 === 0;
3649         },
3650 
3651         odd: function( elem, i ) {
3652             return i % 2 === 1;
3653         },
3654 
3655         lt: function( elem, i, match ) {
3656             return i < match[3] - 0;
3657         },
3658 
3659         gt: function( elem, i, match ) {
3660             return i > match[3] - 0;
3661         },
3662 
3663         nth: function( elem, i, match ) {
3664             return match[3] - 0 === i;
3665         },
3666 
3667         eq: function( elem, i, match ) {
3668             return match[3] - 0 === i;
3669         }
3670     },
3671     filter: {
3672         PSEUDO: function( elem, match, i, array ) {
3673             var name = match[1],
3674                 filter = Expr.filters[ name ];
3675 
3676             if ( filter ) {
3677                 return filter( elem, i, match, array );
3678 
3679             } else if ( name === "contains" ) {
3680                 return (elem.textContent || elem.innerText || Sizzle.getText([ elem ]) || "").indexOf(match[3]) >= 0;
3681 
3682             } else if ( name === "not" ) {
3683                 var not = match[3];
3684 
3685                 for ( var j = 0, l = not.length; j < l; j++ ) {
3686                     if ( not[j] === elem ) {
3687                         return false;
3688                     }
3689                 }
3690 
3691                 return true;
3692 
3693             } else {
3694                 Sizzle.error( "Syntax error, unrecognized expression: " + name );
3695             }
3696         },
3697 
3698         CHILD: function( elem, match ) {
3699             var type = match[1],
3700                 node = elem;
3701 
3702             switch ( type ) {
3703                 case "only":
3704                 case "first":
3705                     while ( (node = node.previousSibling) )     {
3706                         if ( node.nodeType === 1 ) { 
3707                             return false; 
3708                         }
3709                     }
3710 
3711                     if ( type === "first" ) { 
3712                         return true; 
3713                     }
3714 
3715                     node = elem;
3716 
3717                 case "last":
3718                     while ( (node = node.nextSibling) )     {
3719                         if ( node.nodeType === 1 ) { 
3720                             return false; 
3721                         }
3722                     }
3723 
3724                     return true;
3725 
3726                 case "nth":
3727                     var first = match[2],
3728                         last = match[3];
3729 
3730                     if ( first === 1 && last === 0 ) {
3731                         return true;
3732                     }
3733                     
3734                     var doneName = match[0],
3735                         parent = elem.parentNode;
3736     
3737                     if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) {
3738                         var count = 0;
3739                         
3740                         for ( node = parent.firstChild; node; node = node.nextSibling ) {
3741                             if ( node.nodeType === 1 ) {
3742                                 node.nodeIndex = ++count;
3743                             }
3744                         } 
3745 
3746                         parent.sizcache = doneName;
3747                     }
3748                     
3749                     var diff = elem.nodeIndex - last;
3750 
3751                     if ( first === 0 ) {
3752                         return diff === 0;
3753 
3754                     } else {
3755                         return ( diff % first === 0 && diff / first >= 0 );
3756                     }
3757             }
3758         },
3759 
3760         ID: function( elem, match ) {
3761             return elem.nodeType === 1 && elem.getAttribute("id") === match;
3762         },
3763 
3764         TAG: function( elem, match ) {
3765             return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match;
3766         },
3767         
3768         CLASS: function( elem, match ) {
3769             return (" " + (elem.className || elem.getAttribute("class")) + " ")
3770                 .indexOf( match ) > -1;
3771         },
3772 
3773         ATTR: function( elem, match ) {
3774             var name = match[1],
3775                 result = Expr.attrHandle[ name ] ?
3776                     Expr.attrHandle[ name ]( elem ) :
3777                     elem[ name ] != null ?
3778                         elem[ name ] :
3779                         elem.getAttribute( name ),
3780                 value = result + "",
3781                 type = match[2],
3782                 check = match[4];
3783 
3784             return result == null ?
3785                 type === "!=" :
3786                 type === "=" ?
3787                 value === check :
3788                 type === "*=" ?
3789                 value.indexOf(check) >= 0 :
3790                 type === "~=" ?
3791                 (" " + value + " ").indexOf(check) >= 0 :
3792                 !check ?
3793                 value && result !== false :
3794                 type === "!=" ?
3795                 value !== check :
3796                 type === "^=" ?
3797                 value.indexOf(check) === 0 :
3798                 type === "$=" ?
3799                 value.substr(value.length - check.length) === check :
3800                 type === "|=" ?
3801                 value === check || value.substr(0, check.length + 1) === check + "-" :
3802                 false;
3803         },
3804 
3805         POS: function( elem, match, i, array ) {
3806             var name = match[2],
3807                 filter = Expr.setFilters[ name ];
3808 
3809             if ( filter ) {
3810                 return filter( elem, i, match, array );
3811             }
3812         }
3813     }
3814 };
3815 
3816 var origPOS = Expr.match.POS,
3817     fescape = function(all, num){
3818         return "\\" + (num - 0 + 1);
3819     };
3820 
3821 for ( var type in Expr.match ) {
3822     Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) );
3823     Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) );
3824 }
3825 
3826 var makeArray = function( array, results ) {
3827     array = Array.prototype.slice.call( array, 0 );
3828 
3829     if ( results ) {
3830         results.push.apply( results, array );
3831         return results;
3832     }
3833     
3834     return array;
3835 };
3836 
3837 // Perform a simple check to determine if the browser is capable of
3838 // converting a NodeList to an array using builtin methods.
3839 // Also verifies that the returned array holds DOM nodes
3840 // (which is not the case in the Blackberry browser)
3841 try {
3842     Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType;
3843 
3844 // Provide a fallback method if it does not work
3845 } catch( e ) {
3846     makeArray = function( array, results ) {
3847         var i = 0,
3848             ret = results || [];
3849 
3850         if ( toString.call(array) === "[object Array]" ) {
3851             Array.prototype.push.apply( ret, array );
3852 
3853         } else {
3854             if ( typeof array.length === "number" ) {
3855                 for ( var l = array.length; i < l; i++ ) {
3856                     ret.push( array[i] );
3857                 }
3858 
3859             } else {
3860                 for ( ; array[i]; i++ ) {
3861                     ret.push( array[i] );
3862                 }
3863             }
3864         }
3865 
3866         return ret;
3867     };
3868 }
3869 
3870 var sortOrder, siblingCheck;
3871 
3872 if ( document.documentElement.compareDocumentPosition ) {
3873     sortOrder = function( a, b ) {
3874         if ( a === b ) {
3875             hasDuplicate = true;
3876             return 0;
3877         }
3878 
3879         if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {
3880             return a.compareDocumentPosition ? -1 : 1;
3881         }
3882 
3883         return a.compareDocumentPosition(b) & 4 ? -1 : 1;
3884     };
3885 
3886 } else {
3887     sortOrder = function( a, b ) {
3888         var al, bl,
3889             ap = [],
3890             bp = [],
3891             aup = a.parentNode,
3892             bup = b.parentNode,
3893             cur = aup;
3894 
3895         // The nodes are identical, we can exit early
3896         if ( a === b ) {
3897             hasDuplicate = true;
3898             return 0;
3899 
3900         // If the nodes are siblings (or identical) we can do a quick check
3901         } else if ( aup === bup ) {
3902             return siblingCheck( a, b );
3903 
3904         // If no parents were found then the nodes are disconnected
3905         } else if ( !aup ) {
3906             return -1;
3907 
3908         } else if ( !bup ) {
3909             return 1;
3910         }
3911 
3912         // Otherwise they're somewhere else in the tree so we need
3913         // to build up a full list of the parentNodes for comparison
3914         while ( cur ) {
3915             ap.unshift( cur );
3916             cur = cur.parentNode;
3917         }
3918 
3919         cur = bup;
3920 
3921         while ( cur ) {
3922             bp.unshift( cur );
3923             cur = cur.parentNode;
3924         }
3925 
3926         al = ap.length;
3927         bl = bp.length;
3928 
3929         // Start walking down the tree looking for a discrepancy
3930         for ( var i = 0; i < al && i < bl; i++ ) {
3931             if ( ap[i] !== bp[i] ) {
3932                 return siblingCheck( ap[i], bp[i] );
3933             }
3934         }
3935 
3936         // We ended someplace up the tree so do a sibling check
3937         return i === al ?
3938             siblingCheck( a, bp[i], -1 ) :
3939             siblingCheck( ap[i], b, 1 );
3940     };
3941 
3942     siblingCheck = function( a, b, ret ) {
3943         if ( a === b ) {
3944             return ret;
3945         }
3946 
3947         var cur = a.nextSibling;
3948 
3949         while ( cur ) {
3950             if ( cur === b ) {
3951                 return -1;
3952             }
3953 
3954             cur = cur.nextSibling;
3955         }
3956 
3957         return 1;
3958     };
3959 }
3960 
3961 // Utility function for retreiving the text value of an array of DOM nodes
3962 Sizzle.getText = function( elems ) {
3963     var ret = "", elem;
3964 
3965     for ( var i = 0; elems[i]; i++ ) {
3966         elem = elems[i];
3967 
3968         // Get the text from text nodes and CDATA nodes
3969         if ( elem.nodeType === 3 || elem.nodeType === 4 ) {
3970             ret += elem.nodeValue;
3971 
3972         // Traverse everything else, except comment nodes
3973         } else if ( elem.nodeType !== 8 ) {
3974             ret += Sizzle.getText( elem.childNodes );
3975         }
3976     }
3977 
3978     return ret;
3979 };
3980 
3981 // Check to see if the browser returns elements by name when
3982 // querying by getElementById (and provide a workaround)
3983 (function(){
3984     // We're going to inject a fake input element with a specified name
3985     var form = document.createElement("div"),
3986         id = "script" + (new Date()).getTime(),
3987         root = document.documentElement;
3988 
3989     form.innerHTML = "<a name='" + id + "'/>";
3990 
3991     // Inject it into the root element, check its status, and remove it quickly
3992     root.insertBefore( form, root.firstChild );
3993 
3994     // The workaround has to do additional checks after a getElementById
3995     // Which slows things down for other browsers (hence the branching)
3996     if ( document.getElementById( id ) ) {
3997         Expr.find.ID = function( match, context, isXML ) {
3998             if ( typeof context.getElementById !== "undefined" && !isXML ) {
3999                 var m = context.getElementById(match[1]);
4000 
4001                 return m ?
4002                     m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ?
4003                         [m] :
4004                         undefined :
4005                     [];
4006             }
4007         };
4008 
4009         Expr.filter.ID = function( elem, match ) {
4010             var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
4011 
4012             return elem.nodeType === 1 && node && node.nodeValue === match;
4013         };
4014     }
4015 
4016     root.removeChild( form );
4017 
4018     // release memory in IE
4019     root = form = null;
4020 })();
4021 
4022 (function(){
4023     // Check to see if the browser returns only elements
4024     // when doing getElementsByTagName("*")
4025 
4026     // Create a fake element
4027     var div = document.createElement("div");
4028     div.appendChild( document.createComment("") );
4029 
4030     // Make sure no comments are found
4031     if ( div.getElementsByTagName("*").length > 0 ) {
4032         Expr.find.TAG = function( match, context ) {
4033             var results = context.getElementsByTagName( match[1] );
4034 
4035             // Filter out possible comments
4036             if ( match[1] === "*" ) {
4037                 var tmp = [];
4038 
4039                 for ( var i = 0; results[i]; i++ ) {
4040                     if ( results[i].nodeType === 1 ) {
4041                         tmp.push( results[i] );
4042                     }
4043                 }
4044 
4045                 results = tmp;
4046             }
4047 
4048             return results;
4049         };
4050     }
4051 
4052     // Check to see if an attribute returns normalized href attributes
4053     div.innerHTML = "<a href='#'></a>";
4054 
4055     if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
4056             div.firstChild.getAttribute("href") !== "#" ) {
4057 
4058         Expr.attrHandle.href = function( elem ) {
4059             return elem.getAttribute( "href", 2 );
4060         };
4061     }
4062 
4063     // release memory in IE
4064     div = null;
4065 })();
4066 
4067 if ( document.querySelectorAll ) {
4068     (function(){
4069         var oldSizzle = Sizzle,
4070             div = document.createElement("div"),
4071             id = "__sizzle__";
4072 
4073         div.innerHTML = "<p class='TEST'></p>";
4074 
4075         // Safari can't handle uppercase or unicode characters when
4076         // in quirks mode.
4077         if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
4078             return;
4079         }
4080     
4081         Sizzle = function( query, context, extra, seed ) {
4082             context = context || document;
4083 
4084             // Make sure that attribute selectors are quoted
4085             query = query.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']");
4086 
4087             // Only use querySelectorAll on non-XML documents
4088             // (ID selectors don't work in non-HTML documents)
4089             if ( !seed && !Sizzle.isXML(context) ) {
4090                 if ( context.nodeType === 9 ) {
4091                     try {
4092                         return makeArray( context.querySelectorAll(query), extra );
4093                     } catch(qsaError) {}
4094 
4095                 // qSA works strangely on Element-rooted queries
4096                 // We can work around this by specifying an extra ID on the root
4097                 // and working up from there (Thanks to Andrew Dupont for the technique)
4098                 // IE 8 doesn't work on object elements
4099                 } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
4100                     var old = context.getAttribute( "id" ),
4101                         nid = old || id;
4102 
4103                     if ( !old ) {
4104                         context.setAttribute( "id", nid );
4105                     }
4106 
4107                     try {
4108                         return makeArray( context.querySelectorAll( "#" + nid + " " + query ), extra );
4109 
4110                     } catch(pseudoError) {
4111                     } finally {
4112                         if ( !old ) {
4113                             context.removeAttribute( "id" );
4114                         }
4115                     }
4116                 }
4117             }
4118         
4119             return oldSizzle(query, context, extra, seed);
4120         };
4121 
4122         for ( var prop in oldSizzle ) {
4123             Sizzle[ prop ] = oldSizzle[ prop ];
4124         }
4125 
4126         // release memory in IE
4127         div = null;
4128     })();
4129 }
4130 
4131 (function(){
4132     var html = document.documentElement,
4133         matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector,
4134         pseudoWorks = false;
4135 
4136     try {
4137         // This should fail with an exception
4138         // Gecko does not error, returns false instead
4139         matches.call( document.documentElement, "[test!='']:sizzle" );
4140     
4141     } catch( pseudoError ) {
4142         pseudoWorks = true;
4143     }
4144 
4145     if ( matches ) {
4146         Sizzle.matchesSelector = function( node, expr ) {
4147             // Make sure that attribute selectors are quoted
4148             expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']");
4149 
4150             if ( !Sizzle.isXML( node ) ) {
4151                 try { 
4152                     if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) {
4153                         return matches.call( node, expr );
4154                     }
4155                 } catch(e) {}
4156             }
4157 
4158             return Sizzle(expr, null, null, [node]).length > 0;
4159         };
4160     }
4161 })();
4162 
4163 (function(){
4164     var div = document.createElement("div");
4165 
4166     div.innerHTML = "<div class='test e'></div><div class='test'></div>";
4167 
4168     // Opera can't find a second classname (in 9.6)
4169     // Also, make sure that getElementsByClassName actually exists
4170     if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) {
4171         return;
4172     }
4173 
4174     // Safari caches class attributes, doesn't catch changes (in 3.2)
4175     div.lastChild.className = "e";
4176 
4177     if ( div.getElementsByClassName("e").length === 1 ) {
4178         return;
4179     }
4180     
4181     Expr.order.splice(1, 0, "CLASS");
4182     Expr.find.CLASS = function( match, context, isXML ) {
4183         if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
4184             return context.getElementsByClassName(match[1]);
4185         }
4186     };
4187 
4188     // release memory in IE
4189     div = null;
4190 })();
4191 
4192 function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
4193     for ( var i = 0, l = checkSet.length; i < l; i++ ) {
4194         var elem = checkSet[i];
4195 
4196         if ( elem ) {
4197             var match = false;
4198 
4199             elem = elem[dir];
4200 
4201             while ( elem ) {
4202                 if ( elem.sizcache === doneName ) {
4203                     match = checkSet[elem.sizset];
4204                     break;
4205                 }
4206 
4207                 if ( elem.nodeType === 1 && !isXML ){
4208                     elem.sizcache = doneName;
4209                     elem.sizset = i;
4210                 }
4211 
4212                 if ( elem.nodeName.toLowerCase() === cur ) {
4213                     match = elem;
4214                     break;
4215                 }
4216 
4217                 elem = elem[dir];
4218             }
4219 
4220             checkSet[i] = match;
4221         }
4222     }
4223 }
4224 
4225 function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
4226     for ( var i = 0, l = checkSet.length; i < l; i++ ) {
4227         var elem = checkSet[i];
4228 
4229         if ( elem ) {
4230             var match = false;
4231             
4232             elem = elem[dir];
4233 
4234             while ( elem ) {
4235                 if ( elem.sizcache === doneName ) {
4236                     match = checkSet[elem.sizset];
4237                     break;
4238                 }
4239 
4240                 if ( elem.nodeType === 1 ) {
4241                     if ( !isXML ) {
4242                         elem.sizcache = doneName;
4243                         elem.sizset = i;
4244                     }
4245 
4246                     if ( typeof cur !== "string" ) {
4247                         if ( elem === cur ) {
4248                             match = true;
4249                             break;
4250                         }
4251 
4252                     } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
4253                         match = elem;
4254                         break;
4255                     }
4256                 }
4257 
4258                 elem = elem[dir];
4259             }
4260 
4261             checkSet[i] = match;
4262         }
4263     }
4264 }
4265 
4266 if ( document.documentElement.contains ) {
4267     Sizzle.contains = function( a, b ) {
4268         return a !== b && (a.contains ? a.contains(b) : true);
4269     };
4270 
4271 } else if ( document.documentElement.compareDocumentPosition ) {
4272     Sizzle.contains = function( a, b ) {
4273         return !!(a.compareDocumentPosition(b) & 16);
4274     };
4275 
4276 } else {
4277     Sizzle.contains = function() {
4278         return false;
4279     };
4280 }
4281 
4282 Sizzle.isXML = function( elem ) {
4283     // documentElement is verified for cases where it doesn't yet exist
4284     // (such as loading iframes in IE - #4833) 
4285     var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement;
4286 
4287     return documentElement ? documentElement.nodeName !== "HTML" : false;
4288 };
4289 
4290 var posProcess = function( selector, context ) {
4291     var match,
4292         tmpSet = [],
4293         later = "",
4294         root = context.nodeType ? [context] : context;
4295 
4296     // Position selectors must be done after the filter
4297     // And so must :not(positional) so we move all PSEUDOs to the end
4298     while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
4299         later += match[0];
4300         selector = selector.replace( Expr.match.PSEUDO, "" );
4301     }
4302 
4303     selector = Expr.relative[selector] ? selector + "*" : selector;
4304 
4305     for ( var i = 0, l = root.length; i < l; i++ ) {
4306         Sizzle( selector, root[i], tmpSet );
4307     }
4308 
4309     return Sizzle.filter( later, tmpSet );
4310 };
4311 
4312 // EXPOSE
4313 jQuery.find = Sizzle;
4314 jQuery.expr = Sizzle.selectors;
4315 jQuery.expr[":"] = jQuery.expr.filters;
4316 jQuery.unique = Sizzle.uniqueSort;
4317 jQuery.text = Sizzle.getText;
4318 jQuery.isXMLDoc = Sizzle.isXML;
4319 jQuery.contains = Sizzle.contains;
4320 
4321 
4322 })();
4323 
4324 
4325 var runtil = /Until$/,
4326     rparentsprev = /^(?:parents|prevUntil|prevAll)/,
4327     // Note: This RegExp should be improved, or likely pulled from Sizzle
4328     rmultiselector = /,/,
4329     isSimple = /^.[^:#\[\.,]*$/,
4330     slice = Array.prototype.slice,
4331     POS = jQuery.expr.match.POS;
4332 
4333 jQuery.fn.extend({
4334     find: function( selector ) {
4335         var ret = this.pushStack( "", "find", selector ),
4336             length = 0;
4337 
4338         for ( var i = 0, l = this.length; i < l; i++ ) {
4339             length = ret.length;
4340             jQuery.find( selector, this[i], ret );
4341 
4342             if ( i > 0 ) {
4343                 // Make sure that the results are unique
4344                 for ( var n = length; n < ret.length; n++ ) {
4345                     for ( var r = 0; r < length; r++ ) {
4346                         if ( ret[r] === ret[n] ) {
4347                             ret.splice(n--, 1);
4348                             break;
4349                         }
4350                     }
4351                 }
4352             }
4353         }
4354 
4355         return ret;
4356     },
4357 
4358     has: function( target ) {
4359         var targets = jQuery( target );
4360         return this.filter(function() {
4361             for ( var i = 0, l = targets.length; i < l; i++ ) {
4362                 if ( jQuery.contains( this, targets[i] ) ) {
4363                     return true;
4364                 }
4365             }
4366         });
4367     },
4368 
4369     not: function( selector ) {
4370         return this.pushStack( winnow(this, selector, false), "not", selector);
4371     },
4372 
4373     filter: function( selector ) {
4374         return this.pushStack( winnow(this, selector, true), "filter", selector );
4375     },
4376     
4377     is: function( selector ) {
4378         return !!selector && jQuery.filter( selector, this ).length > 0;
4379     },
4380 
4381     closest: function( selectors, context ) {
4382         var ret = [], i, l, cur = this[0];
4383 
4384         if ( jQuery.isArray( selectors ) ) {
4385             var match, selector,
4386                 matches = {},
4387                 level = 1;
4388 
4389             if ( cur && selectors.length ) {
4390                 for ( i = 0, l = selectors.length; i < l; i++ ) {
4391                     selector = selectors[i];
4392 
4393                     if ( !matches[selector] ) {
4394                         matches[selector] = jQuery.expr.match.POS.test( selector ) ? 
4395                             jQuery( selector, context || this.context ) :
4396                             selector;
4397                     }
4398                 }
4399 
4400                 while ( cur && cur.ownerDocument && cur !== context ) {
4401                     for ( selector in matches ) {
4402                         match = matches[selector];
4403 
4404                         if ( match.jquery ? match.index(cur) > -1 : jQuery(cur).is(match) ) {
4405                             ret.push({ selector: selector, elem: cur, level: level });
4406                         }
4407                     }
4408 
4409                     cur = cur.parentNode;
4410                     level++;
4411                 }
4412             }
4413 
4414             return ret;
4415         }
4416 
4417         var pos = POS.test( selectors ) ? 
4418             jQuery( selectors, context || this.context ) : null;
4419 
4420         for ( i = 0, l = this.length; i < l; i++ ) {
4421             cur = this[i];
4422 
4423             while ( cur ) {
4424                 if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {
4425                     ret.push( cur );
4426                     break;
4427 
4428                 } else {
4429                     cur = cur.parentNode;
4430                     if ( !cur || !cur.ownerDocument || cur === context ) {
4431                         break;
4432                     }
4433                 }
4434             }
4435         }
4436 
4437         ret = ret.length > 1 ? jQuery.unique(ret) : ret;
4438         
4439         return this.pushStack( ret, "closest", selectors );
4440     },
4441     
4442     // Determine the position of an element within
4443     // the matched set of elements
4444     index: function( elem ) {
4445         if ( !elem || typeof elem === "string" ) {
4446             return jQuery.inArray( this[0],
4447                 // If it receives a string, the selector is used
4448                 // If it receives nothing, the siblings are used
4449                 elem ? jQuery( elem ) : this.parent().children() );
4450         }
4451         // Locate the position of the desired element
4452         return jQuery.inArray(
4453             // If it receives a jQuery object, the first element is used
4454             elem.jquery ? elem[0] : elem, this );
4455     },
4456 
4457     add: function( selector, context ) {
4458         var set = typeof selector === "string" ?
4459                 jQuery( selector, context || this.context ) :
4460                 jQuery.makeArray( selector ),
4461             all = jQuery.merge( this.get(), set );
4462 
4463         return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ?
4464             all :
4465             jQuery.unique( all ) );
4466     },
4467 
4468     andSelf: function() {
4469         return this.add( this.prevObject );
4470     }
4471 });
4472 
4473 // A painfully simple check to see if an element is disconnected
4474 // from a document (should be improved, where feasible).
4475 function isDisconnected( node ) {
4476     return !node || !node.parentNode || node.parentNode.nodeType === 11;
4477 }
4478 
4479 jQuery.each({
4480     parent: function( elem ) {
4481         var parent = elem.parentNode;
4482         return parent && parent.nodeType !== 11 ? parent : null;
4483     },
4484     parents: function( elem ) {
4485         return jQuery.dir( elem, "parentNode" );
4486     },
4487     parentsUntil: function( elem, i, until ) {
4488         return jQuery.dir( elem, "parentNode", until );
4489     },
4490     next: function( elem ) {
4491         return jQuery.nth( elem, 2, "nextSibling" );
4492     },
4493     prev: function( elem ) {
4494         return jQuery.nth( elem, 2, "previousSibling" );
4495     },
4496     nextAll: function( elem ) {
4497         return jQuery.dir( elem, "nextSibling" );
4498     },
4499     prevAll: function( elem ) {
4500         return jQuery.dir( elem, "previousSibling" );
4501     },
4502     nextUntil: function( elem, i, until ) {
4503         return jQuery.dir( elem, "nextSibling", until );
4504     },
4505     prevUntil: function( elem, i, until ) {
4506         return jQuery.dir( elem, "previousSibling", until );
4507     },
4508     siblings: function( elem ) {
4509         return jQuery.sibling( elem.parentNode.firstChild, elem );
4510     },
4511     children: function( elem ) {
4512         return jQuery.sibling( elem.firstChild );
4513     },
4514     contents: function( elem ) {
4515         return jQuery.nodeName( elem, "iframe" ) ?
4516             elem.contentDocument || elem.contentWindow.document :
4517             jQuery.makeArray( elem.childNodes );
4518     }
4519 }, function( name, fn ) {
4520     jQuery.fn[ name ] = function( until, selector ) {
4521         var ret = jQuery.map( this, fn, until );
4522         
4523         if ( !runtil.test( name ) ) {
4524             selector = until;
4525         }
4526 
4527         if ( selector && typeof selector === "string" ) {
4528             ret = jQuery.filter( selector, ret );
4529         }
4530 
4531         ret = this.length > 1 ? jQuery.unique( ret ) : ret;
4532 
4533         if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {
4534             ret = ret.reverse();
4535         }
4536 
4537         return this.pushStack( ret, name, slice.call(arguments).join(",") );
4538     };
4539 });
4540 
4541 jQuery.extend({
4542     filter: function( expr, elems, not ) {
4543         if ( not ) {
4544             expr = ":not(" + expr + ")";
4545         }
4546 
4547         return elems.length === 1 ?
4548             jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :
4549             jQuery.find.matches(expr, elems);
4550     },
4551     
4552     dir: function( elem, dir, until ) {
4553         var matched = [],
4554             cur = elem[ dir ];
4555 
4556         while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
4557             if ( cur.nodeType === 1 ) {
4558                 matched.push( cur );
4559             }
4560             cur = cur[dir];
4561         }
4562         return matched;
4563     },
4564 
4565     nth: function( cur, result, dir, elem ) {
4566         result = result || 1;
4567         var num = 0;
4568 
4569         for ( ; cur; cur = cur[dir] ) {
4570             if ( cur.nodeType === 1 && ++num === result ) {
4571                 break;
4572             }
4573         }
4574 
4575         return cur;
4576     },
4577 
4578     sibling: function( n, elem ) {
4579         var r = [];
4580 
4581         for ( ; n; n = n.nextSibling ) {
4582             if ( n.nodeType === 1 && n !== elem ) {
4583                 r.push( n );
4584             }
4585         }
4586 
4587         return r;
4588     }
4589 });
4590 
4591 // Implement the identical functionality for filter and not
4592 function winnow( elements, qualifier, keep ) {
4593     if ( jQuery.isFunction( qualifier ) ) {
4594         return jQuery.grep(elements, function( elem, i ) {
4595             var retVal = !!qualifier.call( elem, i, elem );
4596             return retVal === keep;
4597         });
4598 
4599     } else if ( qualifier.nodeType ) {
4600         return jQuery.grep(elements, function( elem, i ) {
4601             return (elem === qualifier) === keep;
4602         });
4603 
4604     } else if ( typeof qualifier === "string" ) {
4605         var filtered = jQuery.grep(elements, function( elem ) {
4606             return elem.nodeType === 1;
4607         });
4608 
4609         if ( isSimple.test( qualifier ) ) {
4610             return jQuery.filter(qualifier, filtered, !keep);
4611         } else {
4612             qualifier = jQuery.filter( qualifier, filtered );
4613         }
4614     }
4615 
4616     return jQuery.grep(elements, function( elem, i ) {
4617         return (jQuery.inArray( elem, qualifier ) >= 0) === keep;
4618     });
4619 }
4620 
4621 
4622 
4623 
4624 var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g,
4625     rleadingWhitespace = /^\s+/,
4626     rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,
4627     rtagName = /<([\w:]+)/,
4628     rtbody = /<tbody/i,
4629     rhtml = /<|&#?\w+;/,
4630     rnocache = /<(?:script|object|embed|option|style)/i,
4631     // checked="checked" or checked (html5)
4632     rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
4633     raction = /\=([^="'>\s]+\/)>/g,
4634     wrapMap = {
4635         option: [ 1, "<select multiple='multiple'>", "</select>" ],
4636         legend: [ 1, "<fieldset>", "</fieldset>" ],
4637         thead: [ 1, "<table>", "</table>" ],
4638         tr: [ 2, "<table><tbody>", "</tbody></table>" ],
4639         td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
4640         col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
4641         area: [ 1, "<map>", "</map>" ],
4642         _default: [ 0, "", "" ]
4643     };
4644 
4645 wrapMap.optgroup = wrapMap.option;
4646 wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
4647 wrapMap.th = wrapMap.td;
4648 
4649 // IE can't serialize <link> and <script> tags normally
4650 if ( !jQuery.support.htmlSerialize ) {
4651     wrapMap._default = [ 1, "div<div>", "</div>" ];
4652 }
4653 
4654 jQuery.fn.extend({
4655     text: function( text ) {
4656         if ( jQuery.isFunction(text) ) {
4657             return this.each(function(i) {
4658                 var self = jQuery( this );
4659 
4660                 self.text( text.call(this, i, self.text()) );
4661             });
4662         }
4663 
4664         if ( typeof text !== "object" && text !== undefined ) {
4665             return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) );
4666         }
4667 
4668         return jQuery.text( this );
4669     },
4670 
4671     wrapAll: function( html ) {
4672         if ( jQuery.isFunction( html ) ) {
4673             return this.each(function(i) {
4674                 jQuery(this).wrapAll( html.call(this, i) );
4675             });
4676         }
4677 
4678         if ( this[0] ) {
4679             // The elements to wrap the target around
4680             var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
4681 
4682             if ( this[0].parentNode ) {
4683                 wrap.insertBefore( this[0] );
4684             }
4685 
4686             wrap.map(function() {
4687                 var elem = this;
4688 
4689                 while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
4690                     elem = elem.firstChild;
4691                 }
4692 
4693                 return elem;
4694             }).append(this);
4695         }
4696 
4697         return this;
4698     },
4699 
4700     wrapInner: function( html ) {
4701         if ( jQuery.isFunction( html ) ) {
4702             return this.each(function(i) {
4703                 jQuery(this).wrapInner( html.call(this, i) );
4704             });
4705         }
4706 
4707         return this.each(function() {
4708             var self = jQuery( this ),
4709                 contents = self.contents();
4710 
4711             if ( contents.length ) {
4712                 contents.wrapAll( html );
4713 
4714             } else {
4715                 self.append( html );
4716             }
4717         });
4718     },
4719 
4720     wrap: function( html ) {
4721         return this.each(function() {
4722             jQuery( this ).wrapAll( html );
4723         });
4724     },
4725 
4726     unwrap: function() {
4727         return this.parent().each(function() {
4728             if ( !jQuery.nodeName( this, "body" ) ) {
4729                 jQuery( this ).replaceWith( this.childNodes );
4730             }
4731         }).end();
4732     },
4733 
4734     append: function() {
4735         return this.domManip(arguments, true, function( elem ) {
4736             if ( this.nodeType === 1 ) {
4737                 this.appendChild( elem );
4738             }
4739         });
4740     },
4741 
4742     prepend: function() {
4743         return this.domManip(arguments, true, function( elem ) {
4744             if ( this.nodeType === 1 ) {
4745                 this.insertBefore( elem, this.firstChild );
4746             }
4747         });
4748     },
4749 
4750     before: function() {
4751         if ( this[0] && this[0].parentNode ) {
4752             return this.domManip(arguments, false, function( elem ) {
4753                 this.parentNode.insertBefore( elem, this );
4754             });
4755         } else if ( arguments.length ) {
4756             var set = jQuery(arguments[0]);
4757             set.push.apply( set, this.toArray() );
4758             return this.pushStack( set, "before", arguments );
4759         }
4760     },
4761 
4762     after: function() {
4763         if ( this[0] && this[0].parentNode ) {
4764             return this.domManip(arguments, false, function( elem ) {
4765                 this.parentNode.insertBefore( elem, this.nextSibling );
4766             });
4767         } else if ( arguments.length ) {
4768             var set = this.pushStack( this, "after", arguments );
4769             set.push.apply( set, jQuery(arguments[0]).toArray() );
4770             return set;
4771         }
4772     },
4773     
4774     // keepData is for internal use only--do not document
4775     remove: function( selector, keepData ) {
4776         for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
4777             if ( !selector || jQuery.filter( selector, [ elem ] ).length ) {
4778                 if ( !keepData && elem.nodeType === 1 ) {
4779                     jQuery.cleanData( elem.getElementsByTagName("*") );
4780                     jQuery.cleanData( [ elem ] );
4781                 }
4782 
4783                 if ( elem.parentNode ) {
4784                      elem.parentNode.removeChild( elem );
4785                 }
4786             }
4787         }
4788         
4789         return this;
4790     },
4791 
4792     empty: function() {
4793         for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
4794             // Remove element nodes and prevent memory leaks
4795             if ( elem.nodeType === 1 ) {
4796                 jQuery.cleanData( elem.getElementsByTagName("*") );
4797             }
4798 
4799             // Remove any remaining nodes
4800             while ( elem.firstChild ) {
4801                 elem.removeChild( elem.firstChild );
4802             }
4803         }
4804         
4805         return this;
4806     },
4807 
4808     clone: function( events ) {
4809         // Do the clone
4810         var ret = this.map(function() {
4811             if ( !jQuery.support.noCloneEvent && !jQuery.isXMLDoc(this) ) {
4812                 // IE copies events bound via attachEvent when
4813                 // using cloneNode. Calling detachEvent on the
4814                 // clone will also remove the events from the orignal
4815                 // In order to get around this, we use innerHTML.
4816                 // Unfortunately, this means some modifications to
4817                 // attributes in IE that are actually only stored
4818                 // as properties will not be copied (such as the
4819                 // the name attribute on an input).
4820                 var html = this.outerHTML,
4821                     ownerDocument = this.ownerDocument;
4822 
4823                 if ( !html ) {
4824                     var div = ownerDocument.createElement("div");
4825                     div.appendChild( this.cloneNode(true) );
4826                     html = div.innerHTML;
4827                 }
4828 
4829                 return jQuery.clean([html.replace(rinlinejQuery, "")
4830                     // Handle the case in IE 8 where action=/test/> self-closes a tag
4831                     .replace(raction, '="$1">')
4832                     .replace(rleadingWhitespace, "")], ownerDocument)[0];
4833             } else {
4834                 return this.cloneNode(true);
4835             }
4836         });
4837 
4838         // Copy the events from the original to the clone
4839         if ( events === true ) {
4840             cloneCopyEvent( this, ret );
4841             cloneCopyEvent( this.find("*"), ret.find("*") );
4842         }
4843 
4844         // Return the cloned set
4845         return ret;
4846     },
4847 
4848     html: function( value ) {
4849         if ( value === undefined ) {
4850             return this[0] && this[0].nodeType === 1 ?
4851                 this[0].innerHTML.replace(rinlinejQuery, "") :
4852                 null;
4853 
4854         // See if we can take a shortcut and just use innerHTML
4855         } else if ( typeof value === "string" && !rnocache.test( value ) &&
4856             (jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value )) &&
4857             !wrapMap[ (rtagName.exec( value ) || ["", ""])[1].toLowerCase() ] ) {
4858 
4859             value = value.replace(rxhtmlTag, "<$1></$2>");
4860 
4861             try {
4862                 for ( var i = 0, l = this.length; i < l; i++ ) {
4863                     // Remove element nodes and prevent memory leaks
4864                     if ( this[i].nodeType === 1 ) {
4865                         jQuery.cleanData( this[i].getElementsByTagName("*") );
4866                         this[i].innerHTML = value;
4867                     }
4868                 }
4869 
4870             // If using innerHTML throws an exception, use the fallback method
4871             } catch(e) {
4872                 this.empty().append( value );
4873             }
4874 
4875         } else if ( jQuery.isFunction( value ) ) {
4876             this.each(function(i){
4877                 var self = jQuery( this );
4878 
4879                 self.html( value.call(this, i, self.html()) );
4880             });
4881 
4882         } else {
4883             this.empty().append( value );
4884         }
4885 
4886         return this;
4887     },
4888 
4889     replaceWith: function( value ) {
4890         if ( this[0] && this[0].parentNode ) {
4891             // Make sure that the elements are removed from the DOM before they are inserted
4892             // this can help fix replacing a parent with child elements
4893             if ( jQuery.isFunction( value ) ) {
4894                 return this.each(function(i) {
4895                     var self = jQuery(this), old = self.html();
4896                     self.replaceWith( value.call( this, i, old ) );
4897                 });
4898             }
4899 
4900             if ( typeof value !== "string" ) {
4901                 value = jQuery( value ).detach();
4902             }
4903 
4904             return this.each(function() {
4905                 var next = this.nextSibling,
4906                     parent = this.parentNode;
4907 
4908                 jQuery( this ).remove();
4909 
4910                 if ( next ) {
4911                     jQuery(next).before( value );
4912                 } else {
4913                     jQuery(parent).append( value );
4914                 }
4915             });
4916         } else {
4917             return this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value );
4918         }
4919     },
4920 
4921     detach: function( selector ) {
4922         return this.remove( selector, true );
4923     },
4924 
4925     domManip: function( args, table, callback ) {
4926         var results, first, fragment, parent,
4927             value = args[0],
4928             scripts = [];
4929 
4930         // We can't cloneNode fragments that contain checked, in WebKit
4931         if ( !jQuery.support.checkClone && arguments.length === 3 && typeof value === "string" && rchecked.test( value ) ) {
4932             return this.each(function() {
4933                 jQuery(this).domManip( args, table, callback, true );
4934             });
4935         }
4936 
4937         if ( jQuery.isFunction(value) ) {
4938             return this.each(function(i) {
4939                 var self = jQuery(this);
4940                 args[0] = value.call(this, i, table ? self.html() : undefined);
4941                 self.domManip( args, table, callback );
4942             });
4943         }
4944 
4945         if ( this[0] ) {
4946             parent = value && value.parentNode;
4947 
4948             // If we're in a fragment, just use that instead of building a new one
4949             if ( jQuery.support.parentNode && parent && parent.nodeType === 11 && parent.childNodes.length === this.length ) {
4950                 results = { fragment: parent };
4951 
4952             } else {
4953                 results = jQuery.buildFragment( args, this, scripts );
4954             }
4955             
4956             fragment = results.fragment;
4957             
4958             if ( fragment.childNodes.length === 1 ) {
4959                 first = fragment = fragment.firstChild;
4960             } else {
4961                 first = fragment.firstChild;
4962             }
4963 
4964             if ( first ) {
4965                 table = table && jQuery.nodeName( first, "tr" );
4966 
4967                 for ( var i = 0, l = this.length; i < l; i++ ) {
4968                     callback.call(
4969                         table ?
4970                             root(this[i], first) :
4971                             this[i],
4972                         i > 0 || results.cacheable || this.length > 1  ?
4973                             fragment.cloneNode(true) :
4974                             fragment
4975                     );
4976                 }
4977             }
4978 
4979             if ( scripts.length ) {
4980                 jQuery.each( scripts, evalScript );
4981             }
4982         }
4983 
4984         return this;
4985     }
4986 });
4987 
4988 function root( elem, cur ) {
4989     return jQuery.nodeName(elem, "table") ?
4990         (elem.getElementsByTagName("tbody")[0] ||
4991         elem.appendChild(elem.ownerDocument.createElement("tbody"))) :
4992         elem;
4993 }
4994 
4995 function cloneCopyEvent(orig, ret) {
4996     var i = 0;
4997 
4998     ret.each(function() {
4999         if ( this.nodeName !== (orig[i] && orig[i].nodeName) ) {
5000             return;
5001         }
5002 
5003         var oldData = jQuery.data( orig[i++] ),
5004             curData = jQuery.data( this, oldData ),
5005             events = oldData && oldData.events;
5006 
5007         if ( events ) {
5008             delete curData.handle;
5009             curData.events = {};
5010 
5011             for ( var type in events ) {
5012                 for ( var handler in events[ type ] ) {
5013                     jQuery.event.add( this, type, events[ type ][ handler ], events[ type ][ handler ].data );
5014                 }
5015             }
5016         }
5017     });
5018 }
5019 
5020 jQuery.buildFragment = function( args, nodes, scripts ) {
5021     var fragment, cacheable, cacheresults,
5022         doc = (nodes && nodes[0] ? nodes[0].ownerDocument || nodes[0] : document);
5023 
5024     // Only cache "small" (1/2 KB) strings that are associated with the main document
5025     // Cloning options loses the selected state, so don't cache them
5026     // IE 6 doesn't like it when you put <object> or <embed> elements in a fragment
5027     // Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache
5028     if ( args.length === 1 && typeof args[0] === "string" && args[0].length < 512 && doc === document &&
5029         !rnocache.test( args[0] ) && (jQuery.support.checkClone || !rchecked.test( args[0] )) ) {
5030 
5031         cacheable = true;
5032         cacheresults = jQuery.fragments[ args[0] ];
5033         if ( cacheresults ) {
5034             if ( cacheresults !== 1 ) {
5035                 fragment = cacheresults;
5036             }
5037         }
5038     }
5039 
5040     if ( !fragment ) {
5041         fragment = doc.createDocumentFragment();
5042         jQuery.clean( args, doc, fragment, scripts );
5043     }
5044 
5045     if ( cacheable ) {
5046         jQuery.fragments[ args[0] ] = cacheresults ? fragment : 1;
5047     }
5048 
5049     return { fragment: fragment, cacheable: cacheable };
5050 };
5051 
5052 jQuery.fragments = {};
5053 
5054 jQuery.each({
5055     appendTo: "append",
5056     prependTo: "prepend",
5057     insertBefore: "before",
5058     insertAfter: "after",
5059     replaceAll: "replaceWith"
5060 }, function( name, original ) {
5061     jQuery.fn[ name ] = function( selector ) {
5062         var ret = [],
5063             insert = jQuery( selector ),
5064             parent = this.length === 1 && this[0].parentNode;
5065         
5066         if ( parent && parent.nodeType === 11 && parent.childNodes.length === 1 && insert.length === 1 ) {
5067             insert[ original ]( this[0] );
5068             return this;
5069             
5070         } else {
5071             for ( var i = 0, l = insert.length; i < l; i++ ) {
5072                 var elems = (i > 0 ? this.clone(true) : this).get();
5073                 jQuery( insert[i] )[ original ]( elems );
5074                 ret = ret.concat( elems );
5075             }
5076         
5077             return this.pushStack( ret, name, insert.selector );
5078         }
5079     };
5080 });
5081 
5082 jQuery.extend({
5083     clean: function( elems, context, fragment, scripts ) {
5084         context = context || document;
5085 
5086         // !context.createElement fails in IE with an error but returns typeof 'object'
5087         if ( typeof context.createElement === "undefined" ) {
5088             context = context.ownerDocument || context[0] && context[0].ownerDocument || document;
5089         }
5090 
5091         var ret = [];
5092 
5093         for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
5094             if ( typeof elem === "number" ) {
5095                 elem += "";
5096             }
5097 
5098             if ( !elem ) {
5099                 continue;
5100             }
5101 
5102             // Convert html string into DOM nodes
5103             if ( typeof elem === "string" && !rhtml.test( elem ) ) {
5104                 elem = context.createTextNode( elem );
5105 
5106             } else if ( typeof elem === "string" ) {
5107                 // Fix "XHTML"-style tags in all browsers
5108                 elem = elem.replace(rxhtmlTag, "<$1></$2>");
5109 
5110                 // Trim whitespace, otherwise indexOf won't work as expected
5111                 var tag = (rtagName.exec( elem ) || ["", ""])[1].toLowerCase(),
5112                     wrap = wrapMap[ tag ] || wrapMap._default,
5113                     depth = wrap[0],
5114                     div = context.createElement("div");
5115 
5116                 // Go to html and back, then peel off extra wrappers
5117                 div.innerHTML = wrap[1] + elem + wrap[2];
5118 
5119                 // Move to the right depth
5120                 while ( depth-- ) {
5121                     div = div.lastChild;
5122                 }
5123 
5124                 // Remove IE's autoinserted <tbody> from table fragments
5125                 if ( !jQuery.support.tbody ) {
5126 
5127                     // String was a <table>, *may* have spurious <tbody>
5128                     var hasBody = rtbody.test(elem),
5129                         tbody = tag === "table" && !hasBody ?
5130                             div.firstChild && div.firstChild.childNodes :
5131 
5132                             // String was a bare <thead> or <tfoot>
5133                             wrap[1] === "<table>" && !hasBody ?
5134                                 div.childNodes :
5135                                 [];
5136 
5137                     for ( var j = tbody.length - 1; j >= 0 ; --j ) {
5138                         if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) {
5139                             tbody[ j ].parentNode.removeChild( tbody[ j ] );
5140                         }
5141                     }
5142 
5143                 }
5144 
5145                 // IE completely kills leading whitespace when innerHTML is used
5146                 if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
5147                     div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild );
5148                 }
5149 
5150                 elem = div.childNodes;
5151             }
5152 
5153             if ( elem.nodeType ) {
5154                 ret.push( elem );
5155             } else {
5156                 ret = jQuery.merge( ret, elem );
5157             }
5158         }
5159 
5160         if ( fragment ) {
5161             for ( i = 0; ret[i]; i++ ) {
5162                 if ( scripts && jQuery.nodeName( ret[i], "script" ) && (!ret[i].type || ret[i].type.toLowerCase() === "text/javascript") ) {
5163                     scripts.push( ret[i].parentNode ? ret[i].parentNode.removeChild( ret[i] ) : ret[i] );
5164                 
5165                 } else {
5166                     if ( ret[i].nodeType === 1 ) {
5167                         ret.splice.apply( ret, [i + 1, 0].concat(jQuery.makeArray(ret[i].getElementsByTagName("script"))) );
5168                     }
5169                     fragment.appendChild( ret[i] );
5170                 }
5171             }
5172         }
5173 
5174         return ret;
5175     },
5176     
5177     cleanData: function( elems ) {
5178         var data, id, cache = jQuery.cache,
5179             special = jQuery.event.special,
5180             deleteExpando = jQuery.support.deleteExpando;
5181         
5182         for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
5183             if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {
5184                 continue;
5185             }
5186 
5187             id = elem[ jQuery.expando ];
5188             
5189             if ( id ) {
5190                 data = cache[ id ];
5191                 
5192                 if ( data && data.events ) {
5193                     for ( var type in data.events ) {
5194                         if ( special[ type ] ) {
5195                             jQuery.event.remove( elem, type );
5196 
5197                         } else {
5198                             jQuery.removeEvent( elem, type, data.handle );
5199                         }
5200                     }
5201                 }
5202                 
5203                 if ( deleteExpando ) {
5204                     delete elem[ jQuery.expando ];
5205 
5206                 } else if ( elem.removeAttribute ) {
5207                     elem.removeAttribute( jQuery.expando );
5208                 }
5209                 
5210                 delete cache[ id ];
5211             }
5212         }
5213     }
5214 });
5215 
5216 function evalScript( i, elem ) {
5217     if ( elem.src ) {
5218         jQuery.ajax({
5219             url: elem.src,
5220             async: false,
5221             dataType: "script"
5222         });
5223     } else {
5224         jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" );
5225     }
5226 
5227     if ( elem.parentNode ) {
5228         elem.parentNode.removeChild( elem );
5229     }
5230 }
5231 
5232 
5233 
5234 
5235 var ralpha = /alpha\([^)]*\)/i,
5236     ropacity = /opacity=([^)]*)/,
5237     rdashAlpha = /-([a-z])/ig,
5238     rupper = /([A-Z])/g,
5239     rnumpx = /^-?\d+(?:px)?$/i,
5240     rnum = /^-?\d/,
5241 
5242     cssShow = { position: "absolute", visibility: "hidden", display: "block" },
5243     cssWidth = [ "Left", "Right" ],
5244     cssHeight = [ "Top", "Bottom" ],
5245     curCSS,
5246 
5247     getComputedStyle,
5248     currentStyle,
5249 
5250     fcamelCase = function( all, letter ) {
5251         return letter.toUpperCase();
5252     };
5253 
5254 jQuery.fn.css = function( name, value ) {
5255     // Setting 'undefined' is a no-op
5256     if ( arguments.length === 2 && value === undefined ) {
5257         return this;
5258     }
5259 
5260     return jQuery.access( this, name, value, true, function( elem, name, value ) {
5261         return value !== undefined ?
5262             jQuery.style( elem, name, value ) :
5263             jQuery.css( elem, name );
5264     });
5265 };
5266 
5267 jQuery.extend({
5268     // Add in style property hooks for overriding the default
5269     // behavior of getting and setting a style property
5270     cssHooks: {
5271         opacity: {
5272             get: function( elem, computed ) {
5273                 if ( computed ) {
5274                     // We should always get a number back from opacity
5275                     var ret = curCSS( elem, "opacity", "opacity" );
5276                     return ret === "" ? "1" : ret;
5277 
5278                 } else {
5279                     return elem.style.opacity;
5280                 }
5281             }
5282         }
5283     },
5284 
5285     // Exclude the following css properties to add px
5286     cssNumber: {
5287         "zIndex": true,
5288         "fontWeight": true,
5289         "opacity": true,
5290         "zoom": true,
5291         "lineHeight": true
5292     },
5293 
5294     // Add in properties whose names you wish to fix before
5295     // setting or getting the value
5296     cssProps: {
5297         // normalize float css property
5298         "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat"
5299     },
5300 
5301     // Get and set the style property on a DOM Node
5302     style: function( elem, name, value, extra ) {
5303         // Don't set styles on text and comment nodes
5304         if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
5305             return;
5306         }
5307 
5308         // Make sure that we're working with the right name
5309         var ret, origName = jQuery.camelCase( name ),
5310             style = elem.style, hooks = jQuery.cssHooks[ origName ];
5311 
5312         name = jQuery.cssProps[ origName ] || origName;
5313 
5314         // Check if we're setting a value
5315         if ( value !== undefined ) {
5316             // Make sure that NaN and null values aren't set. See: #7116
5317             if ( typeof value === "number" && isNaN( value ) || value == null ) {
5318                 return;
5319             }
5320 
5321             // If a number was passed in, add 'px' to the (except for certain CSS properties)
5322             if ( typeof value === "number" && !jQuery.cssNumber[ origName ] ) {
5323                 value += "px";
5324             }
5325 
5326             // If a hook was provided, use that value, otherwise just set the specified value
5327             if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value )) !== undefined ) {
5328                 // Wrapped to prevent IE from throwing errors when 'invalid' values are provided
5329                 // Fixes bug #5509
5330                 try {
5331                     style[ name ] = value;
5332                 } catch(e) {}
5333             }
5334 
5335         } else {
5336             // If a hook was provided get the non-computed value from there
5337             if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
5338                 return ret;
5339             }
5340 
5341             // Otherwise just get the value from the style object
5342             return style[ name ];
5343         }
5344     },
5345 
5346     css: function( elem, name, extra ) {
5347         // Make sure that we're working with the right name
5348         var ret, origName = jQuery.camelCase( name ),
5349             hooks = jQuery.cssHooks[ origName ];
5350 
5351         name = jQuery.cssProps[ origName ] || origName;
5352 
5353         // If a hook was provided get the computed value from there
5354         if ( hooks && "get" in hooks && (ret = hooks.get( elem, true, extra )) !== undefined ) {
5355             return ret;
5356 
5357         // Otherwise, if a way to get the computed value exists, use that
5358         } else if ( curCSS ) {
5359             return curCSS( elem, name, origName );
5360         }
5361     },
5362 
5363     // A method for quickly swapping in/out CSS properties to get correct calculations
5364     swap: function( elem, options, callback ) {
5365         var old = {};
5366 
5367         // Remember the old values, and insert the new ones
5368         for ( var name in options ) {
5369             old[ name ] = elem.style[ name ];
5370             elem.style[ name ] = options[ name ];
5371         }
5372 
5373         callback.call( elem );
5374 
5375         // Revert the old values
5376         for ( name in options ) {
5377             elem.style[ name ] = old[ name ];
5378         }
5379     },
5380 
5381     camelCase: function( string ) {
5382         return string.replace( rdashAlpha, fcamelCase );
5383     }
5384 });
5385 
5386 // DEPRECATED, Use jQuery.css() instead
5387 jQuery.curCSS = jQuery.css;
5388 
5389 jQuery.each(["height", "width"], function( i, name ) {
5390     jQuery.cssHooks[ name ] = {
5391         get: function( elem, computed, extra ) {
5392             var val;
5393 
5394             if ( computed ) {
5395                 if ( elem.offsetWidth !== 0 ) {
5396                     val = getWH( elem, name, extra );
5397 
5398                 } else {
5399                     jQuery.swap( elem, cssShow, function() {
5400                         val = getWH( elem, name, extra );
5401                     });
5402                 }
5403 
5404                 if ( val <= 0 ) {
5405                     val = curCSS( elem, name, name );
5406 
5407                     if ( val === "0px" && currentStyle ) {
5408                         val = currentStyle( elem, name, name );
5409                     }
5410 
5411                     if ( val != null ) {
5412                         // Should return "auto" instead of 0, use 0 for
5413                         // temporary backwards-compat
5414                         return val === "" || val === "auto" ? "0px" : val;
5415                     }
5416                 }
5417 
5418                 if ( val < 0 || val == null ) {
5419                     val = elem.style[ name ];
5420 
5421                     // Should return "auto" instead of 0, use 0 for
5422                     // temporary backwards-compat
5423                     return val === "" || val === "auto" ? "0px" : val;
5424                 }
5425 
5426                 return typeof val === "string" ? val : val + "px";
5427             }
5428         },
5429 
5430         set: function( elem, value ) {
5431             if ( rnumpx.test( value ) ) {
5432                 // ignore negative width and height values #1599
5433                 value = parseFloat(value);
5434 
5435                 if ( value >= 0 ) {
5436                     return value + "px";
5437                 }
5438 
5439             } else {
5440                 return value;
5441             }
5442         }
5443     };
5444 });
5445 
5446 if ( !jQuery.support.opacity ) {
5447     jQuery.cssHooks.opacity = {
5448         get: function( elem, computed ) {
5449             // IE uses filters for opacity
5450             return ropacity.test((computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "") ?
5451                 (parseFloat(RegExp.$1) / 100) + "" :
5452                 computed ? "1" : "";
5453         },
5454 
5455         set: function( elem, value ) {
5456             var style = elem.style;
5457 
5458             // IE has trouble with opacity if it does not have layout
5459             // Force it by setting the zoom level
5460             style.zoom = 1;
5461 
5462             // Set the alpha filter to set the opacity
5463             var opacity = jQuery.isNaN(value) ?
5464                 "" :
5465                 "alpha(opacity=" + value * 100 + ")",
5466                 filter = style.filter || "";
5467 
5468             style.filter = ralpha.test(filter) ?
5469                 filter.replace(ralpha, opacity) :
5470                 style.filter + ' ' + opacity;
5471         }
5472     };
5473 }
5474 
5475 if ( document.defaultView && document.defaultView.getComputedStyle ) {
5476     getComputedStyle = function( elem, newName, name ) {
5477         var ret, defaultView, computedStyle;
5478 
5479         name = name.replace( rupper, "-$1" ).toLowerCase();
5480 
5481         if ( !(defaultView = elem.ownerDocument.defaultView) ) {
5482             return undefined;
5483         }
5484 
5485         if ( (computedStyle = defaultView.getComputedStyle( elem, null )) ) {
5486             ret = computedStyle.getPropertyValue( name );
5487             if ( ret === "" && !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) {
5488                 ret = jQuery.style( elem, name );
5489             }
5490         }
5491 
5492         return ret;
5493     };
5494 }
5495 
5496 if ( document.documentElement.currentStyle ) {
5497     currentStyle = function( elem, name ) {
5498         var left, rsLeft,
5499             ret = elem.currentStyle && elem.currentStyle[ name ],
5500             style = elem.style;
5501 
5502         // From the awesome hack by Dean Edwards
5503         // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
5504 
5505         // If we're not dealing with a regular pixel number
5506         // but a number that has a weird ending, we need to convert it to pixels
5507         if ( !rnumpx.test( ret ) && rnum.test( ret ) ) {
5508             // Remember the original values
5509             left = style.left;
5510             rsLeft = elem.runtimeStyle.left;
5511 
5512             // Put in the new values to get a computed value out
5513             elem.runtimeStyle.left = elem.currentStyle.left;
5514             style.left = name === "fontSize" ? "1em" : (ret || 0);
5515             ret = style.pixelLeft + "px";
5516 
5517             // Revert the changed values
5518             style.left = left;
5519             elem.runtimeStyle.left = rsLeft;
5520         }
5521 
5522         return ret === "" ? "auto" : ret;
5523     };
5524 }
5525 
5526 curCSS = getComputedStyle || currentStyle;
5527 
5528 function getWH( elem, name, extra ) {
5529     var which = name === "width" ? cssWidth : cssHeight,
5530         val = name === "width" ? elem.offsetWidth : elem.offsetHeight;
5531 
5532     if ( extra === "border" ) {
5533         return val;
5534     }
5535 
5536     jQuery.each( which, function() {
5537         if ( !extra ) {
5538             val -= parseFloat(jQuery.css( elem, "padding" + this )) || 0;
5539         }
5540 
5541         if ( extra === "margin" ) {
5542             val += parseFloat(jQuery.css( elem, "margin" + this )) || 0;
5543 
5544         } else {
5545             val -= parseFloat(jQuery.css( elem, "border" + this + "Width" )) || 0;
5546         }
5547     });
5548 
5549     return val;
5550 }
5551 
5552 if ( jQuery.expr && jQuery.expr.filters ) {
5553     jQuery.expr.filters.hidden = function( elem ) {
5554         var width = elem.offsetWidth,
5555             height = elem.offsetHeight;
5556 
5557         return (width === 0 && height === 0) || (!jQuery.support.reliableHiddenOffsets && (elem.style.display || jQuery.css( elem, "display" )) === "none");
5558     };
5559 
5560     jQuery.expr.filters.visible = function( elem ) {
5561         return !jQuery.expr.filters.hidden( elem );
5562     };
5563 }
5564 
5565 
5566 
5567 
5568 var jsc = jQuery.now(),
5569     rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
5570     rselectTextarea = /^(?:select|textarea)/i,
5571     rinput = /^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,
5572     rnoContent = /^(?:GET|HEAD)$/,
5573     rbracket = /\[\]$/,
5574     jsre = /\=\?(&|$)/,
5575     rquery = /\?/,
5576     rts = /([?&])_=[^&]*/,
5577     rurl = /^(\w+:)?\/\/([^\/?#]+)/,
5578     r20 = /%20/g,
5579     rhash = /#.*$/,
5580 
5581     // Keep a copy of the old load method
5582     _load = jQuery.fn.load;
5583 
5584 jQuery.fn.extend({
5585     load: function( url, params, callback ) {
5586         if ( typeof url !== "string" && _load ) {
5587             return _load.apply( this, arguments );
5588 
5589         // Don't do a request if no elements are being requested
5590         } else if ( !this.length ) {
5591             return this;
5592         }
5593 
5594         var off = url.indexOf(" ");
5595         if ( off >= 0 ) {
5596             var selector = url.slice(off, url.length);
5597             url = url.slice(0, off);
5598         }
5599 
5600         // Default to a GET request
5601         var type = "GET";
5602 
5603         // If the second parameter was provided
5604         if ( params ) {
5605             // If it's a function
5606             if ( jQuery.isFunction( params ) ) {
5607                 // We assume that it's the callback
5608                 callback = params;
5609                 params = null;
5610 
5611             // Otherwise, build a param string
5612             } else if ( typeof params === "object" ) {
5613                 params = jQuery.param( params, jQuery.ajaxSettings.traditional );
5614                 type = "POST";
5615             }
5616         }
5617 
5618         var self = this;
5619 
5620         // Request the remote document
5621         jQuery.ajax({
5622             url: url,
5623             type: type,
5624             dataType: "html",
5625             data: params,
5626             complete: function( res, status ) {
5627                 // If successful, inject the HTML into all the matched elements
5628                 if ( status === "success" || status === "notmodified" ) {
5629                     // See if a selector was specified
5630                     self.html( selector ?
5631                         // Create a dummy div to hold the results
5632                         jQuery("<div>")
5633                             // inject the contents of the document in, removing the scripts
5634                             // to avoid any 'Permission Denied' errors in IE
5635                             .append(res.responseText.replace(rscript, ""))
5636 
5637                             // Locate the specified elements
5638                             .find(selector) :
5639 
5640                         // If not, just inject the full result
5641                         res.responseText );
5642                 }
5643 
5644                 if ( callback ) {
5645                     self.each( callback, [res.responseText, status, res] );
5646                 }
5647             }
5648         });
5649 
5650         return this;
5651     },
5652 
5653     serialize: function() {
5654         return jQuery.param(this.serializeArray());
5655     },
5656 
5657     serializeArray: function() {
5658         return this.map(function() {
5659             return this.elements ? jQuery.makeArray(this.elements) : this;
5660         })
5661         .filter(function() {
5662             return this.name && !this.disabled &&
5663                 (this.checked || rselectTextarea.test(this.nodeName) ||
5664                     rinput.test(this.type));
5665         })
5666         .map(function( i, elem ) {
5667             var val = jQuery(this).val();
5668 
5669             return val == null ?
5670                 null :
5671                 jQuery.isArray(val) ?
5672                     jQuery.map( val, function( val, i ) {
5673                         return { name: elem.name, value: val };
5674                     }) :
5675                     { name: elem.name, value: val };
5676         }).get();
5677     }
5678 });
5679 
5680 // Attach a bunch of functions for handling common AJAX events
5681 jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "), function( i, o ) {
5682     jQuery.fn[o] = function( f ) {
5683         return this.bind(o, f);
5684     };
5685 });
5686 
5687 jQuery.extend({
5688     get: function( url, data, callback, type ) {
5689         // shift arguments if data argument was omited
5690         if ( jQuery.isFunction( data ) ) {
5691             type = type || callback;
5692             callback = data;
5693             data = null;
5694         }
5695 
5696         return jQuery.ajax({
5697             type: "GET",
5698             url: url,
5699             data: data,
5700             success: callback,
5701             dataType: type
5702         });
5703     },
5704 
5705     getScript: function( url, callback ) {
5706         return jQuery.get(url, null, callback, "script");
5707     },
5708 
5709     getJSON: function( url, data, callback ) {
5710         return jQuery.get(url, data, callback, "json");
5711     },
5712 
5713     post: function( url, data, callback, type ) {
5714         // shift arguments if data argument was omited
5715         if ( jQuery.isFunction( data ) ) {
5716             type = type || callback;
5717             callback = data;
5718             data = {};
5719         }
5720 
5721         return jQuery.ajax({
5722             type: "POST",
5723             url: url,
5724             data: data,
5725             success: callback,
5726             dataType: type
5727         });
5728     },
5729 
5730     ajaxSetup: function( settings ) {
5731         jQuery.extend( jQuery.ajaxSettings, settings );
5732     },
5733 
5734     ajaxSettings: {
5735         url: location.href,
5736         global: true,
5737         type: "GET",
5738         contentType: "application/x-www-form-urlencoded",
5739         processData: true,
5740         async: true,
5741         /*
5742         timeout: 0,
5743         data: null,
5744         username: null,
5745         password: null,
5746         traditional: false,
5747         */
5748         // This function can be overriden by calling jQuery.ajaxSetup
5749         xhr: function() {
5750             return new window.XMLHttpRequest();
5751         },
5752         accepts: {
5753             xml: "application/xml, text/xml",
5754             html: "text/html",
5755             script: "text/javascript, application/javascript",
5756             json: "application/json, text/javascript",
5757             text: "text/plain",
5758             _default: "*/*"
5759         }
5760     },
5761 
5762     ajax: function( origSettings ) {
5763         var s = jQuery.extend(true, {}, jQuery.ajaxSettings, origSettings),
5764             jsonp, status, data, type = s.type.toUpperCase(), noContent = rnoContent.test(type);
5765 
5766         s.url = s.url.replace( rhash, "" );
5767 
5768         // Use original (not extended) context object if it was provided
5769         s.context = origSettings && origSettings.context != null ? origSettings.context : s;
5770 
5771         // convert data if not already a string
5772         if ( s.data && s.processData && typeof s.data !== "string" ) {
5773             s.data = jQuery.param( s.data, s.traditional );
5774         }
5775 
5776         // Handle JSONP Parameter Callbacks
5777         if ( s.dataType === "jsonp" ) {
5778             if ( type === "GET" ) {
5779                 if ( !jsre.test( s.url ) ) {
5780                     s.url += (rquery.test( s.url ) ? "&" : "?") + (s.jsonp || "callback") + "=?";
5781                 }
5782             } else if ( !s.data || !jsre.test(s.data) ) {
5783                 s.data = (s.data ? s.data + "&" : "") + (s.jsonp || "callback") + "=?";
5784             }
5785             s.dataType = "json";
5786         }
5787 
5788         // Build temporary JSONP function
5789         if ( s.dataType === "json" && (s.data && jsre.test(s.data) || jsre.test(s.url)) ) {
5790             jsonp = s.jsonpCallback || ("jsonp" + jsc++);
5791 
5792             // Replace the =? sequence both in the query string and the data
5793             if ( s.data ) {
5794                 s.data = (s.data + "").replace(jsre, "=" + jsonp + "$1");
5795             }
5796 
5797             s.url = s.url.replace(jsre, "=" + jsonp + "$1");
5798 
5799             // We need to make sure
5800             // that a JSONP style response is executed properly
5801             s.dataType = "script";
5802 
5803             // Handle JSONP-style loading
5804             var customJsonp = window[ jsonp ];
5805 
5806             window[ jsonp ] = function( tmp ) {
5807                 if ( jQuery.isFunction( customJsonp ) ) {
5808                     customJsonp( tmp );
5809 
5810                 } else {
5811                     // Garbage collect
5812                     window[ jsonp ] = undefined;
5813 
5814                     try {
5815                         delete window[ jsonp ];
5816                     } catch( jsonpError ) {}
5817                 }
5818 
5819                 data = tmp;
5820                 jQuery.handleSuccess( s, xhr, status, data );
5821                 jQuery.handleComplete( s, xhr, status, data );
5822                 
5823                 if ( head ) {
5824                     head.removeChild( script );
5825                 }
5826             };
5827         }
5828 
5829         if ( s.dataType === "script" && s.cache === null ) {
5830             s.cache = false;
5831         }
5832 
5833         if ( s.cache === false && noContent ) {
5834             var ts = jQuery.now();
5835 
5836             // try replacing _= if it is there
5837             var ret = s.url.replace(rts, "$1_=" + ts);
5838 
5839             // if nothing was replaced, add timestamp to the end
5840             s.url = ret + ((ret === s.url) ? (rquery.test(s.url) ? "&" : "?") + "_=" + ts : "");
5841         }
5842 
5843         // If data is available, append data to url for GET/HEAD requests
5844         if ( s.data && noContent ) {
5845             s.url += (rquery.test(s.url) ? "&" : "?") + s.data;
5846         }
5847 
5848         // Watch for a new set of requests
5849         if ( s.global && jQuery.active++ === 0 ) {
5850             jQuery.event.trigger( "ajaxStart" );
5851         }
5852 
5853         // Matches an absolute URL, and saves the domain
5854         var parts = rurl.exec( s.url ),
5855             remote = parts && (parts[1] && parts[1].toLowerCase() !== location.protocol || parts[2].toLowerCase() !== location.host);
5856 
5857         // If we're requesting a remote document
5858         // and trying to load JSON or Script with a GET
5859         if ( s.dataType === "script" && type === "GET" && remote ) {
5860             var head = document.getElementsByTagName("head")[0] || document.documentElement;
5861             var script = document.createElement("script");
5862             if ( s.scriptCharset ) {
5863                 script.charset = s.scriptCharset;
5864             }
5865             script.src = s.url;
5866 
5867             // Handle Script loading
5868             if ( !jsonp ) {
5869                 var done = false;
5870 
5871                 // Attach handlers for all browsers
5872                 script.onload = script.onreadystatechange = function() {
5873                     if ( !done && (!this.readyState ||
5874                             this.readyState === "loaded" || this.readyState === "complete") ) {
5875                         done = true;
5876                         jQuery.handleSuccess( s, xhr, status, data );
5877                         jQuery.handleComplete( s, xhr, status, data );
5878 
5879                         // Handle memory leak in IE
5880                         script.onload = script.onreadystatechange = null;
5881                         if ( head && script.parentNode ) {
5882                             head.removeChild( script );
5883                         }
5884                     }
5885                 };
5886             }
5887 
5888             // Use insertBefore instead of appendChild  to circumvent an IE6 bug.
5889             // This arises when a base node is used (#2709 and #4378).
5890             head.insertBefore( script, head.firstChild );
5891 
5892             // We handle everything using the script element injection
5893             return undefined;
5894         }
5895 
5896         var requestDone = false;
5897 
5898         // Create the request object
5899         var xhr = s.xhr();
5900 
5901         if ( !xhr ) {
5902             return;
5903         }
5904 
5905         // Open the socket
5906         // Passing null username, generates a login popup on Opera (#2865)
5907         if ( s.username ) {
5908             xhr.open(type, s.url, s.async, s.username, s.password);
5909         } else {
5910             xhr.open(type, s.url, s.async);
5911         }
5912 
5913         // Need an extra try/catch for cross domain requests in Firefox 3
5914         try {
5915             // Set content-type if data specified and content-body is valid for this type
5916             if ( (s.data != null && !noContent) || (origSettings && origSettings.contentType) ) {
5917                 xhr.setRequestHeader("Content-Type", s.contentType);
5918             }
5919 
5920             // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
5921             if ( s.ifModified ) {
5922                 if ( jQuery.lastModified[s.url] ) {
5923                     xhr.setRequestHeader("If-Modified-Since", jQuery.lastModified[s.url]);
5924                 }
5925 
5926                 if ( jQuery.etag[s.url] ) {
5927                     xhr.setRequestHeader("If-None-Match", jQuery.etag[s.url]);
5928                 }
5929             }
5930 
5931             // Set header so the called script knows that it's an XMLHttpRequest
5932             // Only send the header if it's not a remote XHR
5933             if ( !remote ) {
5934                 xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
5935             }
5936 
5937             // Set the Accepts header for the server, depending on the dataType
5938             xhr.setRequestHeader("Accept", s.dataType && s.accepts[ s.dataType ] ?
5939                 s.accepts[ s.dataType ] + ", */*; q=0.01" :
5940                 s.accepts._default );
5941         } catch( headerError ) {}
5942 
5943         // Allow custom headers/mimetypes and early abort
5944         if ( s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false ) {
5945             // Handle the global AJAX counter
5946             if ( s.global && jQuery.active-- === 1 ) {
5947                 jQuery.event.trigger( "ajaxStop" );
5948             }
5949 
5950             // close opended socket
5951             xhr.abort();
5952             return false;
5953         }
5954 
5955         if ( s.global ) {
5956             jQuery.triggerGlobal( s, "ajaxSend", [xhr, s] );
5957         }
5958 
5959         // Wait for a response to come back
5960         var onreadystatechange = xhr.onreadystatechange = function( isTimeout ) {
5961             // The request was aborted
5962             if ( !xhr || xhr.readyState === 0 || isTimeout === "abort" ) {
5963                 // Opera doesn't call onreadystatechange before this point
5964                 // so we simulate the call
5965                 if ( !requestDone ) {
5966                     jQuery.handleComplete( s, xhr, status, data );
5967                 }
5968 
5969                 requestDone = true;
5970                 if ( xhr ) {
5971                     xhr.onreadystatechange = jQuery.noop;
5972                 }
5973 
5974             // The transfer is complete and the data is available, or the request timed out
5975             } else if ( !requestDone && xhr && (xhr.readyState === 4 || isTimeout === "timeout") ) {
5976                 requestDone = true;
5977                 xhr.onreadystatechange = jQuery.noop;
5978 
5979                 status = isTimeout === "timeout" ?
5980                     "timeout" :
5981                     !jQuery.httpSuccess( xhr ) ?
5982                         "error" :
5983                         s.ifModified && jQuery.httpNotModified( xhr, s.url ) ?
5984                             "notmodified" :
5985                             "success";
5986 
5987                 var errMsg;
5988 
5989                 if ( status === "success" ) {
5990                     // Watch for, and catch, XML document parse errors
5991                     try {
5992                         // process the data (runs the xml through httpData regardless of callback)
5993                         data = jQuery.httpData( xhr, s.dataType, s );
5994                     } catch( parserError ) {
5995                         status = "parsererror";
5996                         errMsg = parserError;
5997                     }
5998                 }
5999 
6000                 // Make sure that the request was successful or notmodified
6001                 if ( status === "success" || status === "notmodified" ) {
6002                     // JSONP handles its own success callback
6003                     if ( !jsonp ) {
6004                         jQuery.handleSuccess( s, xhr, status, data );
6005                     }
6006                 } else {
6007                     jQuery.handleError( s, xhr, status, errMsg );
6008                 }
6009 
6010                 // Fire the complete handlers
6011                 if ( !jsonp ) {
6012                     jQuery.handleComplete( s, xhr, status, data );
6013                 }
6014 
6015                 if ( isTimeout === "timeout" ) {
6016                     xhr.abort();
6017                 }
6018 
6019                 // Stop memory leaks
6020                 if ( s.async ) {
6021                     xhr = null;
6022                 }
6023             }
6024         };
6025 
6026         // Override the abort handler, if we can (IE 6 doesn't allow it, but that's OK)
6027         // Opera doesn't fire onreadystatechange at all on abort
6028         try {
6029             var oldAbort = xhr.abort;
6030             xhr.abort = function() {
6031                 if ( xhr ) {
6032                     // oldAbort has no call property in IE7 so
6033                     // just do it this way, which works in all
6034                     // browsers
6035                     Function.prototype.call.call( oldAbort, xhr );
6036                 }
6037 
6038                 onreadystatechange( "abort" );
6039             };
6040         } catch( abortError ) {}
6041 
6042         // Timeout checker
6043         if ( s.async && s.timeout > 0 ) {
6044             setTimeout(function() {
6045                 // Check to see if the request is still happening
6046                 if ( xhr && !requestDone ) {
6047                     onreadystatechange( "timeout" );
6048                 }
6049             }, s.timeout);
6050         }
6051 
6052         // Send the data
6053         try {
6054             xhr.send( noContent || s.data == null ? null : s.data );
6055 
6056         } catch( sendError ) {
6057             jQuery.handleError( s, xhr, null, sendError );
6058 
6059             // Fire the complete handlers
6060             jQuery.handleComplete( s, xhr, status, data );
6061         }
6062 
6063         // firefox 1.5 doesn't fire statechange for sync requests
6064         if ( !s.async ) {
6065             onreadystatechange();
6066         }
6067 
6068         // return XMLHttpRequest to allow aborting the request etc.
6069         return xhr;
6070     },
6071 
6072     // Serialize an array of form elements or a set of
6073     // key/values into a query string
6074     param: function( a, traditional ) {
6075         var s = [],
6076             add = function( key, value ) {
6077                 // If value is a function, invoke it and return its value
6078                 value = jQuery.isFunction(value) ? value() : value;
6079                 s[ s.length ] = encodeURIComponent(key) + "=" + encodeURIComponent(value);
6080             };
6081         
6082         // Set traditional to true for jQuery <= 1.3.2 behavior.
6083         if ( traditional === undefined ) {
6084             traditional = jQuery.ajaxSettings.traditional;
6085         }
6086         
6087         // If an array was passed in, assume that it is an array of form elements.
6088         if ( jQuery.isArray(a) || a.jquery ) {
6089             // Serialize the form elements
6090             jQuery.each( a, function() {
6091                 add( this.name, this.value );
6092             });
6093             
6094         } else {
6095             // If traditional, encode the "old" way (the way 1.3.2 or older
6096             // did it), otherwise encode params recursively.
6097             for ( var prefix in a ) {
6098                 buildParams( prefix, a[prefix], traditional, add );
6099             }
6100         }
6101 
6102         // Return the resulting serialization
6103         return s.join("&").replace(r20, "+");
6104     }
6105 });
6106 
6107 function buildParams( prefix, obj, traditional, add ) {
6108     if ( jQuery.isArray(obj) && obj.length ) {
6109         // Serialize array item.
6110         jQuery.each( obj, function( i, v ) {
6111             if ( traditional || rbracket.test( prefix ) ) {
6112                 // Treat each array item as a scalar.
6113                 add( prefix, v );
6114 
6115             } else {
6116                 // If array item is non-scalar (array or object), encode its
6117                 // numeric index to resolve deserialization ambiguity issues.
6118                 // Note that rack (as of 1.0.0) can't currently deserialize
6119                 // nested arrays properly, and attempting to do so may cause
6120                 // a server error. Possible fixes are to modify rack's
6121                 // deserialization algorithm or to provide an option or flag
6122                 // to force array serialization to be shallow.
6123                 buildParams( prefix + "[" + ( typeof v === "object" || jQuery.isArray(v) ? i : "" ) + "]", v, traditional, add );
6124             }
6125         });
6126             
6127     } else if ( !traditional && obj != null && typeof obj === "object" ) {
6128         if ( jQuery.isEmptyObject( obj ) ) {
6129             add( prefix, "" );
6130 
6131         // Serialize object item.
6132         } else {
6133             jQuery.each( obj, function( k, v ) {
6134                 buildParams( prefix + "[" + k + "]", v, traditional, add );
6135             });
6136         }
6137                     
6138     } else {
6139         // Serialize scalar item.
6140         add( prefix, obj );
6141     }
6142 }
6143 
6144 // This is still on the jQuery object... for now
6145 // Want to move this to jQuery.ajax some day
6146 jQuery.extend({
6147 
6148     // Counter for holding the number of active queries
6149     active: 0,
6150 
6151     // Last-Modified header cache for next request
6152     lastModified: {},
6153     etag: {},
6154 
6155     handleError: function( s, xhr, status, e ) {
6156         // If a local callback was specified, fire it
6157         if ( s.error ) {
6158             s.error.call( s.context, xhr, status, e );
6159         }
6160 
6161         // Fire the global callback
6162         if ( s.global ) {
6163             jQuery.triggerGlobal( s, "ajaxError", [xhr, s, e] );
6164         }
6165     },
6166 
6167     handleSuccess: function( s, xhr, status, data ) {
6168         // If a local callback was specified, fire it and pass it the data
6169         if ( s.success ) {
6170             s.success.call( s.context, data, status, xhr );
6171         }
6172 
6173         // Fire the global callback
6174         if ( s.global ) {
6175             jQuery.triggerGlobal( s, "ajaxSuccess", [xhr, s] );
6176         }
6177     },
6178 
6179     handleComplete: function( s, xhr, status ) {
6180         // Process result
6181         if ( s.complete ) {
6182             s.complete.call( s.context, xhr, status );
6183         }
6184 
6185         // The request was completed
6186         if ( s.global ) {
6187             jQuery.triggerGlobal( s, "ajaxComplete", [xhr, s] );
6188         }
6189 
6190         // Handle the global AJAX counter
6191         if ( s.global && jQuery.active-- === 1 ) {
6192             jQuery.event.trigger( "ajaxStop" );
6193         }
6194     },
6195         
6196     triggerGlobal: function( s, type, args ) {
6197         (s.context && s.context.url == null ? jQuery(s.context) : jQuery.event).trigger(type, args);
6198     },
6199 
6200     // Determines if an XMLHttpRequest was successful or not
6201     httpSuccess: function( xhr ) {
6202         try {
6203             // IE error sometimes returns 1223 when it should be 204 so treat it as success, see #1450
6204             return !xhr.status && location.protocol === "file:" ||
6205                 xhr.status >= 200 && xhr.status < 300 ||
6206                 xhr.status === 304 || xhr.status === 1223;
6207         } catch(e) {}
6208 
6209         return false;
6210     },
6211 
6212     // Determines if an XMLHttpRequest returns NotModified
6213     httpNotModified: function( xhr, url ) {
6214         var lastModified = xhr.getResponseHeader("Last-Modified"),
6215             etag = xhr.getResponseHeader("Etag");
6216 
6217         if ( lastModified ) {
6218             jQuery.lastModified[url] = lastModified;
6219         }
6220 
6221         if ( etag ) {
6222             jQuery.etag[url] = etag;
6223         }
6224 
6225         return xhr.status === 304;
6226     },
6227 
6228     httpData: function( xhr, type, s ) {
6229         var ct = xhr.getResponseHeader("content-type") || "",
6230             xml = type === "xml" || !type && ct.indexOf("xml") >= 0,
6231             data = xml ? xhr.responseXML : xhr.responseText;
6232 
6233         if ( xml && data.documentElement.nodeName === "parsererror" ) {
6234             jQuery.error( "parsererror" );
6235         }
6236 
6237         // Allow a pre-filtering function to sanitize the response
6238         // s is checked to keep backwards compatibility
6239         if ( s && s.dataFilter ) {
6240             data = s.dataFilter( data, type );
6241         }
6242 
6243         // The filter can actually parse the response
6244         if ( typeof data === "string" ) {
6245             // Get the JavaScript object, if JSON is used.
6246             if ( type === "json" || !type && ct.indexOf("json") >= 0 ) {
6247                 data = jQuery.parseJSON( data );
6248 
6249             // If the type is "script", eval it in global context
6250             } else if ( type === "script" || !type && ct.indexOf("javascript") >= 0 ) {
6251                 jQuery.globalEval( data );
6252             }
6253         }
6254 
6255         return data;
6256     }
6257 
6258 });
6259 
6260 /*
6261  * Create the request object; Microsoft failed to properly
6262  * implement the XMLHttpRequest in IE7 (can't request local files),
6263  * so we use the ActiveXObject when it is available
6264  * Additionally XMLHttpRequest can be disabled in IE7/IE8 so
6265  * we need a fallback.
6266  */
6267 if ( window.ActiveXObject ) {
6268     jQuery.ajaxSettings.xhr = function() {
6269         if ( window.location.protocol !== "file:" ) {
6270             try {
6271                 return new window.XMLHttpRequest();
6272             } catch(xhrError) {}
6273         }
6274 
6275         try {
6276             return new window.ActiveXObject("Microsoft.XMLHTTP");
6277         } catch(activeError) {}
6278     };
6279 }
6280 
6281 // Does this browser support XHR requests?
6282 jQuery.support.ajax = !!jQuery.ajaxSettings.xhr();
6283 
6284 
6285 
6286 
6287 var elemdisplay = {},
6288     rfxtypes = /^(?:toggle|show|hide)$/,
6289     rfxnum = /^([+\-]=)?([\d+.\-]+)(.*)$/,
6290     timerId,
6291     fxAttrs = [
6292         // height animations
6293         [ "height", "marginTop", "marginBottom", "paddingTop", "paddingBottom" ],
6294         // width animations
6295         [ "width", "marginLeft", "marginRight", "paddingLeft", "paddingRight" ],
6296         // opacity animations
6297         [ "opacity" ]
6298     ];
6299 
6300 jQuery.fn.extend({
6301     show: function( speed, easing, callback ) {
6302         var elem, display;
6303 
6304         if ( speed || speed === 0 ) {
6305             return this.animate( genFx("show", 3), speed, easing, callback);
6306 
6307         } else {
6308             for ( var i = 0, j = this.length; i < j; i++ ) {
6309                 elem = this[i];
6310                 display = elem.style.display;
6311 
6312                 // Reset the inline display of this element to learn if it is
6313                 // being hidden by cascaded rules or not
6314                 if ( !jQuery.data(elem, "olddisplay") && display === "none" ) {
6315                     display = elem.style.display = "";
6316                 }
6317 
6318                 // Set elements which have been overridden with display: none
6319                 // in a stylesheet to whatever the default browser style is
6320                 // for such an element
6321                 if ( display === "" && jQuery.css( elem, "display" ) === "none" ) {
6322                     jQuery.data(elem, "olddisplay", defaultDisplay(elem.nodeName));
6323                 }
6324             }
6325 
6326             // Set the display of most of the elements in a second loop
6327             // to avoid the constant reflow
6328             for ( i = 0; i < j; i++ ) {
6329                 elem = this[i];
6330                 display = elem.style.display;
6331 
6332                 if ( display === "" || display === "none" ) {
6333                     elem.style.display = jQuery.data(elem, "olddisplay") || "";
6334                 }
6335             }
6336 
6337             return this;
6338         }
6339     },
6340 
6341     hide: function( speed, easing, callback ) {
6342         if ( speed || speed === 0 ) {
6343             return this.animate( genFx("hide", 3), speed, easing, callback);
6344 
6345         } else {
6346             for ( var i = 0, j = this.length; i < j; i++ ) {
6347                 var display = jQuery.css( this[i], "display" );
6348 
6349                 if ( display !== "none" ) {
6350                     jQuery.data( this[i], "olddisplay", display );
6351                 }
6352             }
6353 
6354             // Set the display of the elements in a second loop
6355             // to avoid the constant reflow
6356             for ( i = 0; i < j; i++ ) {
6357                 this[i].style.display = "none";
6358             }
6359 
6360             return this;
6361         }
6362     },
6363 
6364     // Save the old toggle function
6365     _toggle: jQuery.fn.toggle,
6366 
6367     toggle: function( fn, fn2, callback ) {
6368         var bool = typeof fn === "boolean";
6369 
6370         if ( jQuery.isFunction(fn) && jQuery.isFunction(fn2) ) {
6371             this._toggle.apply( this, arguments );
6372 
6373         } else if ( fn == null || bool ) {
6374             this.each(function() {
6375                 var state = bool ? fn : jQuery(this).is(":hidden");
6376                 jQuery(this)[ state ? "show" : "hide" ]();
6377             });
6378 
6379         } else {
6380             this.animate(genFx("toggle", 3), fn, fn2, callback);
6381         }
6382 
6383         return this;
6384     },
6385 
6386     fadeTo: function( speed, to, easing, callback ) {
6387         return this.filter(":hidden").css("opacity", 0).show().end()
6388                     .animate({opacity: to}, speed, easing, callback);
6389     },
6390 
6391     animate: function( prop, speed, easing, callback ) {
6392         var optall = jQuery.speed(speed, easing, callback);
6393 
6394         if ( jQuery.isEmptyObject( prop ) ) {
6395             return this.each( optall.complete );
6396         }
6397 
6398         return this[ optall.queue === false ? "each" : "queue" ](function() {
6399             // XXX 'this' does not always have a nodeName when running the
6400             // test suite
6401 
6402             var opt = jQuery.extend({}, optall), p,
6403                 isElement = this.nodeType === 1,
6404                 hidden = isElement && jQuery(this).is(":hidden"),
6405                 self = this;
6406 
6407             for ( p in prop ) {
6408                 var name = jQuery.camelCase( p );
6409 
6410                 if ( p !== name ) {
6411                     prop[ name ] = prop[ p ];
6412                     delete prop[ p ];
6413                     p = name;
6414                 }
6415 
6416                 if ( prop[p] === "hide" && hidden || prop[p] === "show" && !hidden ) {
6417                     return opt.complete.call(this);
6418                 }
6419 
6420                 if ( isElement && ( p === "height" || p === "width" ) ) {
6421                     // Make sure that nothing sneaks out
6422                     // Record all 3 overflow attributes because IE does not
6423                     // change the overflow attribute when overflowX and
6424                     // overflowY are set to the same value
6425                     opt.overflow = [ this.style.overflow, this.style.overflowX, this.style.overflowY ];
6426 
6427                     // Set display property to inline-block for height/width
6428                     // animations on inline elements that are having width/height
6429                     // animated
6430                     if ( jQuery.css( this, "display" ) === "inline" &&
6431                             jQuery.css( this, "float" ) === "none" ) {
6432                         if ( !jQuery.support.inlineBlockNeedsLayout ) {
6433                             this.style.display = "inline-block";
6434 
6435                         } else {
6436                             var display = defaultDisplay(this.nodeName);
6437 
6438                             // inline-level elements accept inline-block;
6439                             // block-level elements need to be inline with layout
6440                             if ( display === "inline" ) {
6441                                 this.style.display = "inline-block";
6442 
6443                             } else {
6444                                 this.style.display = "inline";
6445                                 this.style.zoom = 1;
6446                             }
6447                         }
6448                     }
6449                 }
6450 
6451                 if ( jQuery.isArray( prop[p] ) ) {
6452                     // Create (if needed) and add to specialEasing
6453                     (opt.specialEasing = opt.specialEasing || {})[p] = prop[p][1];
6454                     prop[p] = prop[p][0];
6455                 }
6456             }
6457 
6458             if ( opt.overflow != null ) {
6459                 this.style.overflow = "hidden";
6460             }
6461 
6462             opt.curAnim = jQuery.extend({}, prop);
6463 
6464             jQuery.each( prop, function( name, val ) {
6465                 var e = new jQuery.fx( self, opt, name );
6466 
6467                 if ( rfxtypes.test(val) ) {
6468                     e[ val === "toggle" ? hidden ? "show" : "hide" : val ]( prop );
6469 
6470                 } else {
6471                     var parts = rfxnum.exec(val),
6472                         start = e.cur() || 0;
6473 
6474                     if ( parts ) {
6475                         var end = parseFloat( parts[2] ),
6476                             unit = parts[3] || "px";
6477 
6478                         // We need to compute starting value
6479                         if ( unit !== "px" ) {
6480                             jQuery.style( self, name, (end || 1) + unit);
6481                             start = ((end || 1) / e.cur()) * start;
6482                             jQuery.style( self, name, start + unit);
6483                         }
6484 
6485                         // If a +=/-= token was provided, we're doing a relative animation
6486                         if ( parts[1] ) {
6487                             end = ((parts[1] === "-=" ? -1 : 1) * end) + start;
6488                         }
6489 
6490                         e.custom( start, end, unit );
6491 
6492                     } else {
6493                         e.custom( start, val, "" );
6494                     }
6495                 }
6496             });
6497 
6498             // For JS strict compliance
6499             return true;
6500         });
6501     },
6502 
6503     stop: function( clearQueue, gotoEnd ) {
6504         var timers = jQuery.timers;
6505 
6506         if ( clearQueue ) {
6507             this.queue([]);
6508         }
6509 
6510         this.each(function() {
6511             // go in reverse order so anything added to the queue during the loop is ignored
6512             for ( var i = timers.length - 1; i >= 0; i-- ) {
6513                 if ( timers[i].elem === this ) {
6514                     if (gotoEnd) {
6515                         // force the next step to be the last
6516                         timers[i](true);
6517                     }
6518 
6519                     timers.splice(i, 1);
6520                 }
6521             }
6522         });
6523 
6524         // start the next in the queue if the last step wasn't forced
6525         if ( !gotoEnd ) {
6526             this.dequeue();
6527         }
6528 
6529         return this;
6530     }
6531 
6532 });
6533 
6534 function genFx( type, num ) {
6535     var obj = {};
6536 
6537     jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice(0,num)), function() {
6538         obj[ this ] = type;
6539     });
6540 
6541     return obj;
6542 }
6543 
6544 // Generate shortcuts for custom animations
6545 jQuery.each({
6546     slideDown: genFx("show", 1),
6547     slideUp: genFx("hide", 1),
6548     slideToggle: genFx("toggle", 1),
6549     fadeIn: { opacity: "show" },
6550     fadeOut: { opacity: "hide" },
6551     fadeToggle: { opacity: "toggle" }
6552 }, function( name, props ) {
6553     jQuery.fn[ name ] = function( speed, easing, callback ) {
6554         return this.animate( props, speed, easing, callback );
6555     };
6556 });
6557 
6558 jQuery.extend({
6559     speed: function( speed, easing, fn ) {
6560         var opt = speed && typeof speed === "object" ? jQuery.extend({}, speed) : {
6561             complete: fn || !fn && easing ||
6562                 jQuery.isFunction( speed ) && speed,
6563             duration: speed,
6564             easing: fn && easing || easing && !jQuery.isFunction(easing) && easing
6565         };
6566 
6567         opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
6568             opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[opt.duration] : jQuery.fx.speeds._default;
6569 
6570         // Queueing
6571         opt.old = opt.complete;
6572         opt.complete = function() {
6573             if ( opt.queue !== false ) {
6574                 jQuery(this).dequeue();
6575             }
6576             if ( jQuery.isFunction( opt.old ) ) {
6577                 opt.old.call( this );
6578             }
6579         };
6580 
6581         return opt;
6582     },
6583 
6584     easing: {
6585         linear: function( p, n, firstNum, diff ) {
6586             return firstNum + diff * p;
6587         },
6588         swing: function( p, n, firstNum, diff ) {
6589             return ((-Math.cos(p*Math.PI)/2) + 0.5) * diff + firstNum;
6590         }
6591     },
6592 
6593     timers: [],
6594 
6595     fx: function( elem, options, prop ) {
6596         this.options = options;
6597         this.elem = elem;
6598         this.prop = prop;
6599 
6600         if ( !options.orig ) {
6601             options.orig = {};
6602         }
6603     }
6604 
6605 });
6606 
6607 jQuery.fx.prototype = {
6608     // Simple function for setting a style value
6609     update: function() {
6610         if ( this.options.step ) {
6611             this.options.step.call( this.elem, this.now, this );
6612         }
6613 
6614         (jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this );
6615     },
6616 
6617     // Get the current size
6618     cur: function() {
6619         if ( this.elem[this.prop] != null && (!this.elem.style || this.elem.style[this.prop] == null) ) {
6620             return this.elem[ this.prop ];
6621         }
6622 
6623         var r = parseFloat( jQuery.css( this.elem, this.prop ) );
6624         return r && r > -10000 ? r : 0;
6625     },
6626 
6627     // Start an animation from one number to another
6628     custom: function( from, to, unit ) {
6629         var self = this,
6630             fx = jQuery.fx;
6631 
6632         this.startTime = jQuery.now();
6633         this.start = from;
6634         this.end = to;
6635         this.unit = unit || this.unit || "px";
6636         this.now = this.start;
6637         this.pos = this.state = 0;
6638 
6639         function t( gotoEnd ) {
6640             return self.step(gotoEnd);
6641         }
6642 
6643         t.elem = this.elem;
6644 
6645         if ( t() && jQuery.timers.push(t) && !timerId ) {
6646             timerId = setInterval(fx.tick, fx.interval);
6647         }
6648     },
6649 
6650     // Simple 'show' function
6651     show: function() {
6652         // Remember where we started, so that we can go back to it later
6653         this.options.orig[this.prop] = jQuery.style( this.elem, this.prop );
6654         this.options.show = true;
6655 
6656         // Begin the animation
6657         // Make sure that we start at a small width/height to avoid any
6658         // flash of content
6659         this.custom(this.prop === "width" || this.prop === "height" ? 1 : 0, this.cur());
6660 
6661         // Start by showing the element
6662         jQuery( this.elem ).show();
6663     },
6664 
6665     // Simple 'hide' function
6666     hide: function() {
6667         // Remember where we started, so that we can go back to it later
6668         this.options.orig[this.prop] = jQuery.style( this.elem, this.prop );
6669         this.options.hide = true;
6670 
6671         // Begin the animation
6672         this.custom(this.cur(), 0);
6673     },
6674 
6675     // Each step of an animation
6676     step: function( gotoEnd ) {
6677         var t = jQuery.now(), done = true;
6678 
6679         if ( gotoEnd || t >= this.options.duration + this.startTime ) {
6680             this.now = this.end;
6681             this.pos = this.state = 1;
6682             this.update();
6683 
6684             this.options.curAnim[ this.prop ] = true;
6685 
6686             for ( var i in this.options.curAnim ) {
6687                 if ( this.options.curAnim[i] !== true ) {
6688                     done = false;
6689                 }
6690             }
6691 
6692             if ( done ) {
6693                 // Reset the overflow
6694                 if ( this.options.overflow != null && !jQuery.support.shrinkWrapBlocks ) {
6695                     var elem = this.elem,
6696                         options = this.options;
6697 
6698                     jQuery.each( [ "", "X", "Y" ], function (index, value) {
6699                         elem.style[ "overflow" + value ] = options.overflow[index];
6700                     } );
6701                 }
6702 
6703                 // Hide the element if the "hide" operation was done
6704                 if ( this.options.hide ) {
6705                     jQuery(this.elem).hide();
6706                 }
6707 
6708                 // Reset the properties, if the item has been hidden or shown
6709                 if ( this.options.hide || this.options.show ) {
6710                     for ( var p in this.options.curAnim ) {
6711                         jQuery.style( this.elem, p, this.options.orig[p] );
6712                     }
6713                 }
6714 
6715                 // Execute the complete function
6716                 this.options.complete.call( this.elem );
6717             }
6718 
6719             return false;
6720 
6721         } else {
6722             var n = t - this.startTime;
6723             this.state = n / this.options.duration;
6724 
6725             // Perform the easing function, defaults to swing
6726             var specialEasing = this.options.specialEasing && this.options.specialEasing[this.prop];
6727             var defaultEasing = this.options.easing || (jQuery.easing.swing ? "swing" : "linear");
6728             this.pos = jQuery.easing[specialEasing || defaultEasing](this.state, n, 0, 1, this.options.duration);
6729             this.now = this.start + ((this.end - this.start) * this.pos);
6730 
6731             // Perform the next step of the animation
6732             this.update();
6733         }
6734 
6735         return true;
6736     }
6737 };
6738 
6739 jQuery.extend( jQuery.fx, {
6740     tick: function() {
6741         var timers = jQuery.timers;
6742 
6743         for ( var i = 0; i < timers.length; i++ ) {
6744             if ( !timers[i]() ) {
6745                 timers.splice(i--, 1);
6746             }
6747         }
6748 
6749         if ( !timers.length ) {
6750             jQuery.fx.stop();
6751         }
6752     },
6753 
6754     interval: 13,
6755 
6756     stop: function() {
6757         clearInterval( timerId );
6758         timerId = null;
6759     },
6760 
6761     speeds: {
6762         slow: 600,
6763         fast: 200,
6764         // Default speed
6765         _default: 400
6766     },
6767 
6768     step: {
6769         opacity: function( fx ) {
6770             jQuery.style( fx.elem, "opacity", fx.now );
6771         },
6772 
6773         _default: function( fx ) {
6774             if ( fx.elem.style && fx.elem.style[ fx.prop ] != null ) {
6775                 fx.elem.style[ fx.prop ] = (fx.prop === "width" || fx.prop === "height" ? Math.max(0, fx.now) : fx.now) + fx.unit;
6776             } else {
6777                 fx.elem[ fx.prop ] = fx.now;
6778             }
6779         }
6780     }
6781 });
6782 
6783 if ( jQuery.expr && jQuery.expr.filters ) {
6784     jQuery.expr.filters.animated = function( elem ) {
6785         return jQuery.grep(jQuery.timers, function( fn ) {
6786             return elem === fn.elem;
6787         }).length;
6788     };
6789 }
6790 
6791 function defaultDisplay( nodeName ) {
6792     if ( !elemdisplay[ nodeName ] ) {
6793         var elem = jQuery("<" + nodeName + ">").appendTo("body"),
6794             display = elem.css("display");
6795 
6796         elem.remove();
6797 
6798         if ( display === "none" || display === "" ) {
6799             display = "block";
6800         }
6801 
6802         elemdisplay[ nodeName ] = display;
6803     }
6804 
6805     return elemdisplay[ nodeName ];
6806 }
6807 
6808 
6809 
6810 
6811 var rtable = /^t(?:able|d|h)$/i,
6812     rroot = /^(?:body|html)$/i;
6813 
6814 if ( "getBoundingClientRect" in document.documentElement ) {
6815     jQuery.fn.offset = function( options ) {
6816         var elem = this[0], box;
6817 
6818         if ( options ) { 
6819             return this.each(function( i ) {
6820                 jQuery.offset.setOffset( this, options, i );
6821             });
6822         }
6823 
6824         if ( !elem || !elem.ownerDocument ) {
6825             return null;
6826         }
6827 
6828         if ( elem === elem.ownerDocument.body ) {
6829             return jQuery.offset.bodyOffset( elem );
6830         }
6831 
6832         try {
6833             box = elem.getBoundingClientRect();
6834         } catch(e) {}
6835 
6836         var doc = elem.ownerDocument,
6837             docElem = doc.documentElement;
6838 
6839         // Make sure we're not dealing with a disconnected DOM node
6840         if ( !box || !jQuery.contains( docElem, elem ) ) {
6841             return box || { top: 0, left: 0 };
6842         }
6843 
6844         var body = doc.body,
6845             win = getWindow(doc),
6846             clientTop  = docElem.clientTop  || body.clientTop  || 0,
6847             clientLeft = docElem.clientLeft || body.clientLeft || 0,
6848             scrollTop  = (win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop  || body.scrollTop ),
6849             scrollLeft = (win.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft),
6850             top  = box.top  + scrollTop  - clientTop,
6851             left = box.left + scrollLeft - clientLeft;
6852 
6853         return { top: top, left: left };
6854     };
6855 
6856 } else {
6857     jQuery.fn.offset = function( options ) {
6858         var elem = this[0];
6859 
6860         if ( options ) { 
6861             return this.each(function( i ) {
6862                 jQuery.offset.setOffset( this, options, i );
6863             });
6864         }
6865 
6866         if ( !elem || !elem.ownerDocument ) {
6867             return null;
6868         }
6869 
6870         if ( elem === elem.ownerDocument.body ) {
6871             return jQuery.offset.bodyOffset( elem );
6872         }
6873 
6874         jQuery.offset.initialize();
6875 
6876         var computedStyle,
6877             offsetParent = elem.offsetParent,
6878             prevOffsetParent = elem,
6879             doc = elem.ownerDocument,
6880             docElem = doc.documentElement,
6881             body = doc.body,
6882             defaultView = doc.defaultView,
6883             prevComputedStyle = defaultView ? defaultView.getComputedStyle( elem, null ) : elem.currentStyle,
6884             top = elem.offsetTop,
6885             left = elem.offsetLeft;
6886 
6887         while ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) {
6888             if ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === "fixed" ) {
6889                 break;
6890             }
6891 
6892             computedStyle = defaultView ? defaultView.getComputedStyle(elem, null) : elem.currentStyle;
6893             top  -= elem.scrollTop;
6894             left -= elem.scrollLeft;
6895 
6896             if ( elem === offsetParent ) {
6897                 top  += elem.offsetTop;
6898                 left += elem.offsetLeft;
6899 
6900                 if ( jQuery.offset.doesNotAddBorder && !(jQuery.offset.doesAddBorderForTableAndCells && rtable.test(elem.nodeName)) ) {
6901                     top  += parseFloat( computedStyle.borderTopWidth  ) || 0;
6902                     left += parseFloat( computedStyle.borderLeftWidth ) || 0;
6903                 }
6904 
6905                 prevOffsetParent = offsetParent;
6906                 offsetParent = elem.offsetParent;
6907             }
6908 
6909             if ( jQuery.offset.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible" ) {
6910                 top  += parseFloat( computedStyle.borderTopWidth  ) || 0;
6911                 left += parseFloat( computedStyle.borderLeftWidth ) || 0;
6912             }
6913 
6914             prevComputedStyle = computedStyle;
6915         }
6916 
6917         if ( prevComputedStyle.position === "relative" || prevComputedStyle.position === "static" ) {
6918             top  += body.offsetTop;
6919             left += body.offsetLeft;
6920         }
6921 
6922         if ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === "fixed" ) {
6923             top  += Math.max( docElem.scrollTop, body.scrollTop );
6924             left += Math.max( docElem.scrollLeft, body.scrollLeft );
6925         }
6926 
6927         return { top: top, left: left };
6928     };
6929 }
6930 
6931 jQuery.offset = {
6932     initialize: function() {
6933         var body = document.body, container = document.createElement("div"), innerDiv, checkDiv, table, td, bodyMarginTop = parseFloat( jQuery.css(body, "marginTop") ) || 0,
6934             html = "<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";
6935 
6936         jQuery.extend( container.style, { position: "absolute", top: 0, left: 0, margin: 0, border: 0, width: "1px", height: "1px", visibility: "hidden" } );
6937 
6938         container.innerHTML = html;
6939         body.insertBefore( container, body.firstChild );
6940         innerDiv = container.firstChild;
6941         checkDiv = innerDiv.firstChild;
6942         td = innerDiv.nextSibling.firstChild.firstChild;
6943 
6944         this.doesNotAddBorder = (checkDiv.offsetTop !== 5);
6945         this.doesAddBorderForTableAndCells = (td.offsetTop === 5);
6946 
6947         checkDiv.style.position = "fixed";
6948         checkDiv.style.top = "20px";
6949 
6950         // safari subtracts parent border width here which is 5px
6951         this.supportsFixedPosition = (checkDiv.offsetTop === 20 || checkDiv.offsetTop === 15);
6952         checkDiv.style.position = checkDiv.style.top = "";
6953 
6954         innerDiv.style.overflow = "hidden";
6955         innerDiv.style.position = "relative";
6956 
6957         this.subtractsBorderForOverflowNotVisible = (checkDiv.offsetTop === -5);
6958 
6959         this.doesNotIncludeMarginInBodyOffset = (body.offsetTop !== bodyMarginTop);
6960 
6961         body.removeChild( container );
6962         body = container = innerDiv = checkDiv = table = td = null;
6963         jQuery.offset.initialize = jQuery.noop;
6964     },
6965 
6966     bodyOffset: function( body ) {
6967         var top = body.offsetTop,
6968             left = body.offsetLeft;
6969 
6970         jQuery.offset.initialize();
6971 
6972         if ( jQuery.offset.doesNotIncludeMarginInBodyOffset ) {
6973             top  += parseFloat( jQuery.css(body, "marginTop") ) || 0;
6974             left += parseFloat( jQuery.css(body, "marginLeft") ) || 0;
6975         }
6976 
6977         return { top: top, left: left };
6978     },
6979     
6980     setOffset: function( elem, options, i ) {
6981         var position = jQuery.css( elem, "position" );
6982 
6983         // set position first, in-case top/left are set even on static elem
6984         if ( position === "static" ) {
6985             elem.style.position = "relative";
6986         }
6987 
6988         var curElem = jQuery( elem ),
6989             curOffset = curElem.offset(),
6990             curCSSTop = jQuery.css( elem, "top" ),
6991             curCSSLeft = jQuery.css( elem, "left" ),
6992             calculatePosition = (position === "absolute" && jQuery.inArray('auto', [curCSSTop, curCSSLeft]) > -1),
6993             props = {}, curPosition = {}, curTop, curLeft;
6994 
6995         // need to be able to calculate position if either top or left is auto and position is absolute
6996         if ( calculatePosition ) {
6997             curPosition = curElem.position();
6998         }
6999 
7000         curTop  = calculatePosition ? curPosition.top  : parseInt( curCSSTop,  10 ) || 0;
7001         curLeft = calculatePosition ? curPosition.left : parseInt( curCSSLeft, 10 ) || 0;
7002 
7003         if ( jQuery.isFunction( options ) ) {
7004             options = options.call( elem, i, curOffset );
7005         }
7006 
7007         if (options.top != null) {
7008             props.top = (options.top - curOffset.top) + curTop;
7009         }
7010         if (options.left != null) {
7011             props.left = (options.left - curOffset.left) + curLeft;
7012         }
7013         
7014         if ( "using" in options ) {
7015             options.using.call( elem, props );
7016         } else {
7017             curElem.css( props );
7018         }
7019     }
7020 };
7021 
7022 
7023 jQuery.fn.extend({
7024     position: function() {
7025         if ( !this[0] ) {
7026             return null;
7027         }
7028 
7029         var elem = this[0],
7030 
7031         // Get *real* offsetParent
7032         offsetParent = this.offsetParent(),
7033 
7034         // Get correct offsets
7035         offset       = this.offset(),
7036         parentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset();
7037 
7038         // Subtract element margins
7039         // note: when an element has margin: auto the offsetLeft and marginLeft
7040         // are the same in Safari causing offset.left to incorrectly be 0
7041         offset.top  -= parseFloat( jQuery.css(elem, "marginTop") ) || 0;
7042         offset.left -= parseFloat( jQuery.css(elem, "marginLeft") ) || 0;
7043 
7044         // Add offsetParent borders
7045         parentOffset.top  += parseFloat( jQuery.css(offsetParent[0], "borderTopWidth") ) || 0;
7046         parentOffset.left += parseFloat( jQuery.css(offsetParent[0], "borderLeftWidth") ) || 0;
7047 
7048         // Subtract the two offsets
7049         return {
7050             top:  offset.top  - parentOffset.top,
7051             left: offset.left - parentOffset.left
7052         };
7053     },
7054 
7055     offsetParent: function() {
7056         return this.map(function() {
7057             var offsetParent = this.offsetParent || document.body;
7058             while ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) {
7059                 offsetParent = offsetParent.offsetParent;
7060             }
7061             return offsetParent;
7062         });
7063     }
7064 });
7065 
7066 
7067 // Create scrollLeft and scrollTop methods
7068 jQuery.each( ["Left", "Top"], function( i, name ) {
7069     var method = "scroll" + name;
7070 
7071     jQuery.fn[ method ] = function(val) {
7072         var elem = this[0], win;
7073         
7074         if ( !elem ) {
7075             return null;
7076         }
7077 
7078         if ( val !== undefined ) {
7079             // Set the scroll offset
7080             return this.each(function() {
7081                 win = getWindow( this );
7082 
7083                 if ( win ) {
7084                     win.scrollTo(
7085                         !i ? val : jQuery(win).scrollLeft(),
7086                          i ? val : jQuery(win).scrollTop()
7087                     );
7088 
7089                 } else {
7090                     this[ method ] = val;
7091                 }
7092             });
7093         } else {
7094             win = getWindow( elem );
7095 
7096             // Return the scroll offset
7097             return win ? ("pageXOffset" in win) ? win[ i ? "pageYOffset" : "pageXOffset" ] :
7098                 jQuery.support.boxModel && win.document.documentElement[ method ] ||
7099                     win.document.body[ method ] :
7100                 elem[ method ];
7101         }
7102     };
7103 });
7104 
7105 function getWindow( elem ) {
7106     return jQuery.isWindow( elem ) ?
7107         elem :
7108         elem.nodeType === 9 ?
7109             elem.defaultView || elem.parentWindow :
7110             false;
7111 }
7112 
7113 
7114 
7115 
7116 // Create innerHeight, innerWidth, outerHeight and outerWidth methods
7117 jQuery.each([ "Height", "Width" ], function( i, name ) {
7118 
7119     var type = name.toLowerCase();
7120 
7121     // innerHeight and innerWidth
7122     jQuery.fn["inner" + name] = function() {
7123         return this[0] ?
7124             parseFloat( jQuery.css( this[0], type, "padding" ) ) :
7125             null;
7126     };
7127 
7128     // outerHeight and outerWidth
7129     jQuery.fn["outer" + name] = function( margin ) {
7130         return this[0] ?
7131             parseFloat( jQuery.css( this[0], type, margin ? "margin" : "border" ) ) :
7132             null;
7133     };
7134 
7135     jQuery.fn[ type ] = function( size ) {
7136         // Get window width or height
7137         var elem = this[0];
7138         if ( !elem ) {
7139             return size == null ? null : this;
7140         }
7141         
7142         if ( jQuery.isFunction( size ) ) {
7143             return this.each(function( i ) {
7144                 var self = jQuery( this );
7145                 self[ type ]( size.call( this, i, self[ type ]() ) );
7146             });
7147         }
7148 
7149         if ( jQuery.isWindow( elem ) ) {
7150             // Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode
7151             return elem.document.compatMode === "CSS1Compat" && elem.document.documentElement[ "client" + name ] ||
7152                 elem.document.body[ "client" + name ];
7153 
7154         // Get document width or height
7155         } else if ( elem.nodeType === 9 ) {
7156             // Either scroll[Width/Height] or offset[Width/Height], whichever is greater
7157             return Math.max(
7158                 elem.documentElement["client" + name],
7159                 elem.body["scroll" + name], elem.documentElement["scroll" + name],
7160                 elem.body["offset" + name], elem.documentElement["offset" + name]
7161             );
7162 
7163         // Get or set width or height on the element
7164         } else if ( size === undefined ) {
7165             var orig = jQuery.css( elem, type ),
7166                 ret = parseFloat( orig );
7167 
7168             return jQuery.isNaN( ret ) ? orig : ret;
7169 
7170         // Set the width or height on the element (default to pixels if value is unitless)
7171         } else {
7172             return this.css( type, typeof size === "string" ? size : size + "px" );
7173         }
7174     };
7175 
7176 });
7177 
7178 
7179 })(window);

jQuery 1.4.4

 这个立即执行函数是比较庞大,所以我选取的是1.4.4这样一个比较老的版本,但也足以用来进行说明。

1.整个jQuery占用全局作用域两个变量,一个是jQuery,另一个是$。而且占用两个还是为了方便我们书写。其实两个变量是完全相同的,在第908行,我们可以看到。

// Expose jQuery to the global object
return (window.jQuery = window.$ = jQuery);

jQuery内部封装的变量,我们可以直接通过$来访问。这样,避免了声明不必要的全局变量。

这里的jQuery可谓起到了一个命名空间的作用。

试想,如果我们引用了另一个js插件superQuery,它占用了一个全局变量,声明window.superQuery=superQuery;

那即便superQuery内部声明了和jQuery同名变量,它们命名空间不同,实际上,并不会造成冲突。

 2.我们再来看913-1105行。

(function(){
jQuery.support = {};
//……
})();

内部主要为创建了jQuery.support。这个创建工作只需要执行一次,所以也使用了立即执行函数。

而巧妙的是,再通过为support添加一系列的内容,就轻松将其暴露在我们可访问的范围之类了。同时,并未造成全局作用域污染。

3.参数和返回值

既然是函数,不可避免地要提一下参数和返回值。

立即函数内部是可以访问外部变量的,所以很多情况下,我们并不需要传参数。如:jQuery的window实参,如果不传入。内部也是可以直接使用的。

返回值也可以直接返回给立即执行函数外的某个变量的一个对象属性(注意,外部变量var a=1;是不能通过a.newAttribute=inParameter来赋值的。)

然而,从代码的可读性等方面考虑,我们显式地传入需要的参数是一个好习惯。

(四)注意点

立即执行函数通常作为一个单独模块使用。一般没有问题,但是,建议在自己写的立即执行函数前加分号,这样可以有效地与前面代码进行隔离。否则,可能出现意想不到的错误。

如:

        var c = 12
        var d = c
        (function () { var e = 14; }())

会报这样一个错误:

立即执行函数(IIFE)的理解与运用

因为在我们立即执行函数模块前面代码没有一个分号来断句。那编译器就把前面的c和后面的语句当作函数调用来看了。

所以,由于很多时候,在立即执行函数之前的代码我们无法控制,为了良好的容错能力。我们一般在立即执行函数前加个分号与前面的代码断开,避免解析错误。

 

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/30701.html

(0)

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信