diff --git a/web/static/script/jquery-1.7.2.js b/web/static/script/jquery-1.7.2.js
index dbb890e..b124fe1 100644
--- a/web/static/script/jquery-1.7.2.js
+++ b/web/static/script/jquery-1.7.2.js
@@ -6844,2850 +6844,2545 @@
         return val + "px";
     }
 
-// 使用 jQuery 的 each 方法遍历数组 ["height", "width"]
     jQuery.each([ "height", "width" ], function( i, name ) {
-        // 为 jQuery 的 cssHooks 对象添加属性,属性名为当前遍历到的元素(height 或 width)
         jQuery.cssHooks[ name ] = {
-            // 定义获取元素样式属性的函数
             get: function( elem, computed, extra ) {
-                // 如果 computed 参数为 true
                 if ( computed ) {
-                    // 如果元素的偏移宽度不为 0
-                    if ( elem.offsetWidth!== 0 ) {
-                        // 调用 getWidthOrHeight 函数获取元素的宽度或高度
+                    if ( elem.offsetWidth !== 0 ) {
                         return getWidthOrHeight( elem, name, extra );
                     } else {
-                        // 否则使用 jQuery 的 swap 方法交换元素样式,然后调用 getWidthOrHeight 函数
                         return jQuery.swap( elem, cssShow, function() {
                             return getWidthOrHeight( elem, name, extra );
                         });
                     }
                 }
             },
-            // 定义设置元素样式属性的函数
+
             set: function( elem, value ) {
-                // 如果 value 是数字,则添加 px 后缀,否则直接返回 value
-                return rnum.test( value )?
+                return rnum.test( value ) ?
                     value + "px" :
                     value;
             }
         };
     });
 
-// 如果 jQuery 不支持 opacity 属性
-    if (!jQuery.support.opacity ) {
-        // 为 jQuery 的 cssHooks 对象添加 opacity 属性
+    if ( !jQuery.support.opacity ) {
         jQuery.cssHooks.opacity = {
-            // 定义获取元素不透明度的函数
             get: function( elem, computed ) {
-                // IE 使用 filters 来实现不透明度
-                return ropacity.test( (computed && elem.currentStyle? elem.currentStyle.filter : elem.style.filter) || "" )?
-                    // 如果有不透明度,提取其值并除以 100 转换为 0-1 的范围
+                // IE uses filters for opacity
+                return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ?
                     ( parseFloat( RegExp.$1 ) / 100 ) + "" :
-                    // 如果 computed 为 true,返回 1,否则返回空字符串
-                    computed? "1" : "";
+                    computed ? "1" : "";
             },
-            // 定义设置元素不透明度的函数
+
             set: function( elem, value ) {
                 var style = elem.style,
                     currentStyle = elem.currentStyle,
-                    // 根据 value 生成不透明度的字符串表示
-                    opacity = jQuery.isNumeric( value )? "alpha(opacity=" + value * 100 + ")" : "",
-                    // 获取元素的 filter 样式
+                    opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "",
                     filter = currentStyle && currentStyle.filter || style.filter || "";
-                // IE 在没有布局的情况下处理不透明度会有问题,通过设置 zoom 为 1 来强制布局
+
+                // IE has trouble with opacity if it does not have layout
+                // Force it by setting the zoom level
                 style.zoom = 1;
-                // 如果设置不透明度为 1,且没有其他 filters 存在,尝试移除 filter 属性
+
+                // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652
                 if ( value >= 1 && jQuery.trim( filter.replace( ralpha, "" ) ) === "" ) {
-                    // 设置 style.filter 为 null、"" 或 " " 仍然会在 cssText 中保留 "filter:",会禁用 clearType,使用 removeAttribute 方法移除
-                    // style.removeAttribute 仅在 IE 中有效,但此代码路径似乎也仅在 IE 中使用
+
+                    // Setting style.filter to null, "" & " " still leave "filter:" in the cssText
+                    // if "filter:" is present at all, clearType is disabled, we want to avoid this
+                    // style.removeAttribute is IE Only, but so apparently is this code path...
                     style.removeAttribute( "filter" );
-                    // 如果没有通过 CSS 规则应用 filter 样式,完成操作
-                    if ( currentStyle &&!currentStyle.filter ) {
+
+                    // if there there is no filter style applied in a css rule, we are done
+                    if ( currentStyle && !currentStyle.filter ) {
                         return;
                     }
                 }
-                // 否则,更新 filter 的值
-                style.filter = ralpha.test( filter )?
-                    // 如果 filter 中已经存在不透明度相关设置,替换其值
+
+                // otherwise, set new filter values
+                style.filter = ralpha.test( filter ) ?
                     filter.replace( ralpha, opacity ) :
-                    // 否则添加不透明度相关设置
                     filter + " " + opacity;
             }
         };
     }
-    // otherwise, set new filter values
-    // 根据条件设置元素的 filter 样式
-    style.filter = ralpha.test( filter )?
-        // 如果 filter 满足 ralpha 的测试,将 filter 中匹配 ralpha 的部分替换为 opacity
-        filter.replace( ralpha, opacity ) :
-        // 否则将 filter 与 opacity 拼接
-        filter + " " + opacity;
-};
-};
-
-// 当 DOM 加载完成后执行以下函数
-jQuery(function() {
-    // 这个钩子在 DOM 加载完成后才能添加,因为对其的支持测试在 DOM 加载完成后才运行
-    if (!jQuery.support.reliableMarginRight ) {
-        // 为 jQuery 的 cssHooks 对象添加 marginRight 属性
-        jQuery.cssHooks.marginRight = {
-            // 定义获取元素 marginRight 属性的函数
-            get: function( elem, computed ) {
-                // WebKit Bug 13343:getComputedStyle 会返回错误的 margin-right 值,通过将元素临时设置为 inline-block 来解决
-                return jQuery.swap( elem, { "display": "inline-block" }, function() {
-                    // 如果 computed 为 true,使用 curCSS 获取元素的 margin-right 属性
-                    if ( computed ) {
-                        return curCSS( elem, "margin-right" );
-                    } else {
-                        // 否则直接返回元素的 marginRight 样式属性
-                        return elem.style.marginRight;
-                    }
-                });
-            }
-        };
-    }
-});
-
-// 如果 jQuery.expr 和 jQuery.expr.filters 存在
-if ( jQuery.expr && jQuery.expr.filters ) {
-    // 为 jQuery.expr.filters 添加 hidden 过滤器
-    jQuery.expr.filters.hidden = function( elem ) {
-        var width = elem.offsetWidth,
-            height = elem.offsetHeight;
-        // 判断元素是否隐藏,根据元素的宽高是否都为 0 或者显示样式为 none 来判断
-        return ( width === 0 && height === 0 ) || (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || jQuery.css( elem, "display" )) === "none");
-    };
-    // 为 jQuery.expr.filters 添加 visible 过滤器,它是 hidden 的反义
-    jQuery.expr.filters.visible = function( elem ) {
-        return!jQuery.expr.filters.hidden( elem );
-    };
-}
-
-// 这些钩子被用于 animate 来扩展属性
-jQuery.each({
-    margin: "",
-    padding: "",
-    border: "Width"
-}, function( prefix, suffix ) {
-    // 为 jQuery 的 cssHooks 对象添加属性,属性名为 prefix 与 suffix 组合
-    jQuery.cssHooks[ prefix + suffix ] = {
-        // 定义 expand 函数
-        expand: function( value ) {
-            var i,
-                // 如果 value 不是字符串,假设它是一个单独的数字,否则将其分割为数组
-                parts = typeof value === "string"? value.split(" ") : [ value ],
-                expanded = {};
-            // 遍历 4 次,将值分配给不同的边
-            for ( i = 0; i < 4; i++ ) {
-                expanded[ prefix + cssExpand[ i ] + suffix ] =
-                    parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
-            }
-            // 返回扩展后的对象
-            return expanded;
-        }
-    };
-});
-
-
-
-// 定义一个全局变量 r20,用于匹配全局的 %20 字符串
-var r20 = /%20/g,
-    // 定义一个全局变量 rbracket,用于匹配以 [] 结尾的字符串
-    rbracket = /\[\]$/,
-    // 定义一个全局变量 rCRLF,用于匹配回车符和换行符(可能包含或不包含回车符)
-    rCRLF = /\r?\n/g,
-    // 定义一个全局变量 rhash,用于匹配以 # 开始并包含其后所有内容的字符串
-    rhash = /#.*$/,
-    // 定义一个全局变量 rheaders,用于匹配 HTTP 头信息格式,包括头名称和头值,IE 会在行尾留下一个 \r 字符
-    rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg,
-    // 定义一个全局变量 rinput,用于匹配特定的输入类型(如文本、日期、密码等),不区分大小写
-    rinput = /^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,
-    // 用于检测本地协议的正则表达式,包括 about、app 等
-    rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,
-    // 定义一个全局变量 rnoContent,用于匹配 GET 或 HEAD 请求
-    rnoContent = /^(?:GET|HEAD)$/,
-    // 定义一个全局变量 rprotocol,用于匹配以 // 开始的字符串
-    rprotocol = /^\/\//,
-    // 定义一个全局变量 rquery,用于匹配问号字符
-    rquery = /\?/,
-    // 定义一个全局变量 rscript,用于匹配 <script> 标签及其内容,不区分大小写
-    rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
-    // 定义一个全局变量 rselectTextarea,用于匹配 select 或 textarea 元素,不区分大小写
-    rselectTextarea = /^(?:select|textarea)/i,
-    // 定义一个全局变量 rspacesAjax,用于匹配一个或多个空格字符
-    rspacesAjax = /\s+/,
-    // 定义一个全局变量 rts,用于匹配包含 _= 的查询参数
-    rts = /([?&])_=[^&]*/,
-    // 定义一个全局变量 rurl,用于解析 URL,包括协议、域名、端口等部分
-    rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,
-
-    // 保存 jQuery.fn.load 方法的原始引用
-    _load = jQuery.fn.load,
-
-    /* Prefilters
-     * 1) 它们可用于引入自定义数据类型(可参考 ajax/jsonp.js 中的示例)
-     * 2) 它们的调用时机:
-     *    - 在请求传输之前
-     *    - 在参数序列化之后(如果 s.processData 为 true,s.data 是一个字符串)
-     * 3) key 是数据类型
-     * 4) 可以使用通配符 "*"
-     * 5) 执行将从传输的数据类型开始,如果需要,继续向下执行到 "*"
-     */
-    prefilters = {},
-
-    /* Transports bindings
-     * 1) key 是数据类型
-     * 2) 可以使用通配符 "*"
-     * 3) 选择将从传输的数据类型开始,如果需要,继续到 "*"
-     */
-    transports = {},
-
-    // 存储文档的位置
-    ajaxLocation,
-    // 存储文档位置的各个部分
-    ajaxLocParts,
-    // 避免注释序言字符序列(#10098);必须满足代码检查工具的要求并避免压缩问题
-    allTypes = ["*/"] + ["*"];
-
-// #8138,IE 可能在访问 window.location 的字段时抛出异常,如果 document.domain 已被设置
-try {
-    // 尝试获取当前页面的 URL
-    ajaxLocation = location.href;
-} catch( e ) {
-    // 使用一个 A 元素的 href 属性,因为 IE 会根据 document.location 修改它
-    ajaxLocation = document.createElement( "a" );
-    ajaxLocation.href = "";
-    ajaxLocation = ajaxLocation.href;
-}
-
-// 使用 rurl 正则表达式将 ajaxLocation 解析为各个部分,如果无法解析则返回空数组
-ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
-
-// 为 jQuery.ajaxPrefilter 和 jQuery.ajaxTransport 提供的基础“构造函数”
-function addToPrefiltersOrTransports( structure ) {
-    // dataTypeExpression 是可选的,默认值为 "*"
-    return function( dataTypeExpression, func ) {
-        // 如果 dataTypeExpression 不是字符串
-        if ( typeof dataTypeExpression!== "string" ) {
-            func = dataTypeExpression;
-            dataTypeExpression = "*";
-        }
-
-        // 如果 func 是一个函数
-        if ( jQuery.isFunction( func ) ) {
-            // 将 dataTypeExpression 按空格分割为多个数据类型并存储在 dataTypes 数组中
-            var dataTypes = dataTypeExpression.toLowerCase().split( rspacesAjax ),
-                i = 0,
-                // 获取 dataTypes 数组的长度
-                length = dataTypes.length,
-                dataType,
-                list,
-                placeBefore;
-
-            // 遍历 dataTypes 数组中的每个数据类型
-            for ( ; i < length; i++ ) {
-                dataType = dataTypes[ i ];
-                // 检查是否需要将 func 放在现有元素之前
-                placeBefore = /^\+/.test( dataType );
-                if ( placeBefore ) {
-                    // 去掉开头的 + 号,如果没有数据类型则使用 "*"
-                    dataType = dataType.substr( 1 ) || "*";
-                }
-                // 获取或创建结构中该数据类型的列表
-                list = structure[ dataType ] = structure[ dataType ] || [];
-                // 根据 placeBefore 的结果,将 func 插入到列表的头部或尾部
-                list[ placeBefore? "unshift" : "push" ]( func );
-            }
-        }
-    };
-}
 
-// Base inspection function for prefilters and transports
-// 用于检查预过滤器或传输器的函数
-function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR,
-                                        dataType /* internal */, inspected /* internal */ ) {
-    // 如果未提供 dataType,则使用 options.dataTypes 的第一个元素作为 dataType
-    dataType = dataType || options.dataTypes[ 0 ];
-    // 如果未提供 inspected,则创建一个新的 inspected 对象
-    inspected = inspected || {};
-    // 将当前 dataType 标记为已检查
-    inspected[ dataType ] = true;
-    // 获取 structure 中当前 dataType 对应的列表
-    var list = structure[ dataType ],
-        i = 0,
-        // 获取列表的长度,如果列表不存在则为 0
-        length = list? list.length : 0,
-        // 表示是否仅执行操作,根据 structure 是否为 prefilters 来判断
-        executeOnly = ( structure === prefilters ),
-        selection;
-    // 遍历列表中的元素
-    for ( ; i < length && ( executeOnly ||!selection ); i++ ) {
-        // 调用列表中的函数并存储结果
-        selection = list[ i ]( options, originalOptions, jqXHR );
-        // 如果结果是一个字符串(表示重定向到另一个 dataType)
-        if ( typeof selection === "string" ) {
-            // 如果仅执行操作且已经检查过该 dataType,将 selection 设为 undefined
-            if (!executeOnly || inspected[ selection ] ) {
-                selection = undefined;
-            } else {
-                // 否则将新的 dataType 加入 options.dataTypes 的头部
-                options.dataTypes.unshift( selection );
-                // 递归调用 inspectPrefiltersOrTransports 函数
-                selection = inspectPrefiltersOrTransports(
-                    structure, options, originalOptions, jqXHR, selection, inspected );
-            }
-        }
-    }
-    // 如果仅执行操作或没有选择,并且未检查过通配符 "*"
-    if ( ( executeOnly ||!selection ) &&!inspected[ "*" ] ) {
-        // 对通配符 "*" 调用 inspectPrefiltersOrTransports 函数
-        selection = inspectPrefiltersOrTransports(
-            structure, options, originalOptions, jqXHR, "*", inspected );
-    }
-    // 当仅执行操作时此返回值不必要(对于预过滤器),但调用者会忽略它
-    return selection;
-}
-
-// 一个特殊的 jQuery 扩展函数,用于 AJAX 选项,它只接受 "扁平" 选项(不进行深度扩展),解决 #9887 问题
-function ajaxExtend( target, src ) {
-    var key, deep,
-        // 获取 jQuery.ajaxSettings 中的 flatOptions 或一个空对象
-        flatOptions = jQuery.ajaxSettings.flatOptions || {};
-    // 遍历 src 对象的键
-    for ( key in src ) {
-        // 如果 src[key] 不为 undefined
-        if ( src[ key ]!== undefined ) {
-            // 根据 flatOptions 决定是否使用深度扩展
-            ( flatOptions[ key ]? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];
-        }
-    }
-    // 如果需要深度扩展,使用 jQuery.extend 进行深度扩展
-    if ( deep ) {
-        jQuery.extend( true, target, deep );
-    }
-}
-
-// 扩展 jQuery.fn 对象
-jQuery.fn.extend({
-    // load 方法的实现
-    load: function( url, params, callback ) {
-        // 如果 url 不是字符串且 _load 存在,调用 _load 方法
-        if ( typeof url!== "string" && _load ) {
-            return _load.apply( this, arguments );
-        }
-        // 如果没有元素请求,直接返回 jQuery 对象
-        else if (!this.length ) {
-            return this;
-        }
-        // 查找 url 中第一个空格的位置
-        var off = url.indexOf( " " );
-        if ( off >= 0 ) {
-            // 提取选择器和 url
-            var selector = url.slice( off, url.length );
-            url = url.slice( 0, off );
-        }
-        // 默认使用 GET 请求
-        var type = "GET";
-        // 如果提供了第二个参数
-        if ( params ) {
-            // 如果是函数,将其作为回调函数
-            if ( jQuery.isFunction( params ) ) {
-                callback = params;
-                params = undefined;
-            }
-            // 如果是对象,将其转换为参数字符串并使用 POST 请求
-            else if ( typeof params === "object" ) {
-                params = jQuery.param( params, jQuery.ajaxSettings.traditional );
-                type = "POST";
-            }
-        }
-        var self = this;
-        // 发起 AJAX 请求
-        jQuery.ajax({
-            url: url,
-            type: type,
-            dataType: "html",
-            data: params,
-            // 完成回调函数
-            complete: function( jqXHR, status, responseText ) {
-                // 存储 jqXHR 对象的响应文本
-                responseText = jqXHR.responseText;
-                // 如果请求成功
-                if ( jqXHR.isResolved() ) {
-                    // 如果存在数据过滤器,获取实际的响应
-                    jqXHR.done(function( r ) {
-                        responseText = r;
-                    });
-                    // 如果指定了选择器
-                    self.html( selector?
-                        // 创建一个临时 div 元素,将响应文本添加进去并移除脚本元素
-                        jQuery("<div>")
-                            .append(responseText.replace(rscript, ""))
-                            // 查找选择器匹配的元素
-                            .find(selector) :
-                        // 否则直接将响应文本添加进去
-                        responseText );
-                }
-                // 如果有回调函数,对每个元素调用回调函数
-                if ( callback ) {
-                    self.each( callback, [ responseText, status, jqXHR ] );
-                }
-            }
-        });
-        // 返回 jQuery 对象
-        return this;
-    },
-    // 序列化方法,将表单元素序列化为参数字符串
-    serialize: function() {
-        return jQuery.param( this.serializeArray() );
-    },
-    // 序列化数组方法,将表单元素转换为数组
-    serializeArray: function() {
-        return this.map(function(){
-            // 如果元素有 elements 属性,将其转换为数组,否则直接使用元素本身
-            return this.elements? jQuery.makeArray( this.elements ) : this;
-        })
-            .filter(function(){
-                // 过滤出有名称、未禁用且满足一定条件的元素
-                return this.name &&!this.disabled &&
-                    ( this.checked || rselectTextarea.test( this.nodeName ) ||
-                        rinput.test( this.type ) );
-            })
-            .map(function( i, elem ){
-                var val = jQuery( this ).val();
-                // 处理元素的值,替换 CRLF 并构建对象
-                return val == null?
-                    null :
-                    jQuery.isArray( val )?
-                        jQuery.map( val, function( val, i ){
-                            return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
-                        }) :
-                        { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
-            }).get();
-    }
-});
-
-jQuery.extend({
-    // 定义 getScript 方法,用于加载并执行 JavaScript 脚本
-    getScript: function( url, callback ) {
-        // 使用 jQuery.get 方法请求 url,将回调函数作为第三个参数,数据类型为 "script"
-        return jQuery.get( url, undefined, callback, "script" );
-    },
-    // 定义 getJSON 方法,用于获取 JSON 数据
-    getJSON: function( url, data, callback ) {
-        // 使用 jQuery.get 方法请求 url,将数据作为第二个参数,回调函数作为第三个参数,数据类型为 "json"
-        return jQuery.get( url, data, callback, "json" );
-    },
-    // 创建一个完整的设置对象,包含 ajaxSettings 和 settings 字段,如果 target 未提供,则写入 ajaxSettings
-    ajaxSetup: function( target, settings ) {
-        if ( settings ) {
-            // 构建一个设置对象,将 jQuery.ajaxSettings 扩展到 target 中
-            ajaxExtend( target, jQuery.ajaxSettings );
-        } else {
-            // 如果没有提供 settings,将 target 作为 settings,并将 jQuery.ajaxSettings 作为 target
-            settings = target;
-            target = jQuery.ajaxSettings;
-        }
-        // 将 settings 扩展到 target 中
-        ajaxExtend( target, settings );
-        return target;
-    },
-    ajaxSettings: {
-        // 默认的请求 URL,使用之前获取的 ajaxLocation
-        url: ajaxLocation,
-        // 判断是否为本地请求,使用 rlocalProtocol 正则表达式对 ajaxLocParts[1] 进行测试
-        isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
-        // 是否触发全局事件
-        global: true,
-        // 默认请求类型为 GET
-        type: "GET",
-        // 默认的内容类型
-        contentType: "application/x-www-form-urlencoded; charset=UTF-8",
-        // 是否处理数据
-        processData: true,
-        // 是否异步请求
-        async: true,
-        /*
-        timeout: 0,
-        data: null,
-        dataType: null,
-        username: null,
-        password: null,
-        cache: null,
-        traditional: false,
-        headers: {},
-        */
-        // 可接受的数据类型及其对应的 MIME 类型
-        accepts: {
-            xml: "application/xml, text/xml",
-            html: "text/html",
-            text: "text/plain",
-            json: "application/json, text/javascript",
-            "*": allTypes
-        },
-        // 内容类型的匹配正则表达式
-        contents: {
-            xml: /xml/,
-            html: /html/,
-            json: /json/
-        },
-        // 响应字段的映射
-        responseFields: {
-            xml: "responseXML",
-            text: "responseText"
-        },
-        // 数据转换器列表
-        // 1) 键的格式为 "source_type destination_type"(中间有一个空格)
-        // 2) 可以使用通配符 "*" 作为 source_type
-        converters: {
-            // 将任何类型转换为文本
-            "* text": window.String,
-            // 文本到 HTML(true 表示不转换)
-            "text html": true,
-            // 将文本解析为 JSON 表达式
-            "text json": jQuery.parseJSON,
-            // 将文本解析为 XML
-            "text xml": jQuery.parseXML
-        },
-        // 对于不应该深度扩展的选项
-        // 可以在这里添加自己的自定义选项,如果创建了一个不应该深度扩展的选项(见 ajaxExtend)
-        flatOptions: {
-            context: true,
-            url: true
-        }
-    },
-    // 使用 addToPrefiltersOrTransports 函数为 prefilters 添加 ajaxPrefilter
-    ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
-    // 使用 addToPrefiltersOrTransports 函数为 transports 添加 ajaxTransport
-    ajaxTransport: addToPrefiltersOrTransports( transports ),
-    // 主方法,用于发送 AJAX 请求
-    ajax: function( url, options ) {
-        // 如果 url 是一个对象,模拟 1.5 版本之前的签名
-        if ( typeof url === "object" ) {
-            options = url;
-            url = undefined;
-        }
-        // 强制 options 为对象
-        options = options || {};
-        var
-            // 创建最终的选项对象,使用 ajaxSetup 函数
-            s = jQuery.ajaxSetup( {}, options ),
-            // 回调函数的上下文
-            callbackContext = s.context || s,
-            // 全局事件的上下文
-            // 如果 options 中提供了回调上下文且为 DOM 节点或 jQuery 集合,则使用 jQuery 包装它,否则使用 jQuery.event
-            globalEventContext = callbackContext!== s &&
-            ( callbackContext.nodeType || callbackContext instanceof jQuery )?
-                jQuery( callbackContext ) : jQuery.event,
-            // 创建 Deferred 对象
-            deferred = jQuery.Deferred(),
-            // 仅调用一次的回调函数
-            completeDeferred = jQuery.Callbacks( "once memory" ),
-            // 状态相关的回调函数
-            statusCode = s.statusCode || {},
-            // ifModified 键
-            ifModifiedKey,
-            // 请求头,一次性发送
-            requestHeaders = {},
-            requestHeadersNames = {},
-            // 响应头
-            responseHeadersString,
-            responseHeaders,
-            // 传输对象
-            transport,
-            // 超时处理的定时器
-            timeoutTimer,
-            // 跨域检测变量
-            parts,
-            // jqXHR 的状态
-            state = 0,
-            // 是否触发全局事件
-            fireGlobals,
-            // 循环变量
-            i,
-            // 模拟的 xhr 对象
-            jqXHR = {
-                readyState: 0,
-                // 设置请求头
-                setRequestHeader: function( name, value ) {
-                    if (!state ) {
-                        var lname = name.toLowerCase();
-                        name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
-                        requestHeaders[ name ] = value;
-                    }
-                    return this;
-                },
-                // 获取所有响应头
-                getAllResponseHeaders: function() {
-                    return state === 2? responseHeadersString : null;
-                },
-                // 构建响应头的哈希表(如果需要)
-                getResponseHeader: function( key ) {
-                    var match;
-                    if ( state === 2 ) {
-                        if (!responseHeaders ) {
-                            responseHeaders = {};
-                            while( ( match = rheaders.exec( responseHeadersString ) ) ) {
-                                responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
-                            }
+    jQuery(function() {
+        // This hook cannot be added until DOM ready because the support test
+        // for it is not run until after DOM ready
+        if ( !jQuery.support.reliableMarginRight ) {
+            jQuery.cssHooks.marginRight = {
+                get: function( elem, computed ) {
+                    // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+                    // Work around by temporarily setting element display to inline-block
+                    return jQuery.swap( elem, { "display": "inline-block" }, function() {
+                        if ( computed ) {
+                            return curCSS( elem, "margin-right" );
+                        } else {
+                            return elem.style.marginRight;
                         }
-                        match = responseHeaders[ key.toLowerCase() ];
-                    }
-                    return match === undefined? null : match;
-                },
-                // 覆盖响应的内容类型头
-                overrideMimeType: function( type ) {
-                    if (!state ) {
-                        s.mimeType = type;
-                    }
-                    return this;
-                },
-                // 取消请求
-                abort: function( statusText ) {
-                    statusText = statusText || "abort";
-                    if ( transport ) {
-                        transport.abort( statusText );
-                    }
-                    done( 0, statusText );
-                    return this;
+                    });
                 }
             };
+        }
+    });
 
-        // Callback for when everything is done
-        // It is defined here because jslint complains if it is declared
-        // at the end of the function (which would be more logical and readable)
-        function done( status, nativeStatusText, responses, headers ) {
-            // Called once
-            if ( state === 2 ) {
-                // 如果状态等于 2,则直接返回
-                return;
-            }
-
-            // State is "done" now
-            state = 2;
+    if ( jQuery.expr && jQuery.expr.filters ) {
+        jQuery.expr.filters.hidden = function( elem ) {
+            var width = elem.offsetWidth,
+                height = elem.offsetHeight;
 
-            // Clear timeout if it exists
-            if ( timeoutTimer ) {
-                // 如果存在超时定时器,则清除它
-                clearTimeout( timeoutTimer );
-            }
+            return ( width === 0 && height === 0 ) || (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || jQuery.css( elem, "display" )) === "none");
+        };
 
-            // Dereference transport for early garbage collection
-            // (no matter how long the jqXHR object will be used)
-            transport = undefined;
+        jQuery.expr.filters.visible = function( elem ) {
+            return !jQuery.expr.filters.hidden( elem );
+        };
+    }
 
-            // Cache response headers
-            responseHeadersString = headers || "";
+// These hooks are used by animate to expand properties
+    jQuery.each({
+        margin: "",
+        padding: "",
+        border: "Width"
+    }, function( prefix, suffix ) {
 
-            // Set readyState
-            jqXHR.readyState = status > 0? 4 : 0;
+        jQuery.cssHooks[ prefix + suffix ] = {
+            expand: function( value ) {
+                var i,
 
-            var isSuccess,
-                success,
-                error,
-                statusText = nativeStatusText,
-                response = responses? ajaxHandleResponses( s, jqXHR, responses ) : undefined,
-                lastModified,
-                etag;
+                    // assumes a single number if not a string
+                    parts = typeof value === "string" ? value.split(" ") : [ value ],
+                    expanded = {};
 
-            // If successful, handle type chaining
-            if ( status >= 200 && status < 300 || status === 304 ) {
-                // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
-                if ( s.ifModified ) {
-                    if ( ( lastModified = jqXHR.getResponseHeader( "Last-Modified" ) ) ) {
-                        // 如果存在 Last-Modified 响应头,将其存储在 jQuery.lastModified 对象中
-                        jQuery.lastModified[ ifModifiedKey ] = lastModified;
-                    }
-                    if ( ( etag = jqXHR.getResponseHeader( "Etag" ) ) ) {
-                        // 如果存在 Etag 响应头,将其存储在 jQuery.etag 对象中
-                        jQuery.etag[ ifModifiedKey ] = etag;
-                    }
+                for ( i = 0; i < 4; i++ ) {
+                    expanded[ prefix + cssExpand[ i ] + suffix ] =
+                        parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
                 }
 
-                // If not modified
-                if ( status === 304 ) {
-                    statusText = "notmodified";
-                    isSuccess = true;
-                } else {
-                    // If we have data
-                    try {
-                        // 尝试将响应转换为相应的数据格式
-                        success = ajaxConvert( s, response );
-                        statusText = "success";
-                        isSuccess = true;
-                    } catch(e) {
-                        // We have a parsererror
-                        statusText = "parsererror";
-                        error = e;
-                    }
-                }
-            } else {
-                // We extract error from statusText
-                // then normalize statusText and status for non-aborts
-                error = statusText;
-                if (!statusText || status ) {
-                    statusText = "error";
-                    if ( status < 0 ) {
-                        status = 0;
-                    }
-                }
+                return expanded;
             }
+        };
+    });
 
-            // Set data for the fake xhr object
-            jqXHR.status = status;
-            jqXHR.statusText = "" + ( nativeStatusText || statusText );
 
-            // Success/Error
-            if ( isSuccess ) {
-                // 若请求成功,使用 deferred 对象的 resolveWith 方法解决承诺
-                deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
-            } else {
-                // 若请求失败,使用 deferred 对象的 rejectWith 方法拒绝承诺
-                deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
-            }
 
-            // Status-dependent callbacks
-            jqXHR.statusCode( statusCode );
-            statusCode = undefined;
 
-            if ( fireGlobals ) {
-                // 触发全局的 ajax 成功或失败事件
-                globalEventContext.trigger( "ajax" + ( isSuccess? "Success" : "Error" ),
-                    [ jqXHR, s, isSuccess? success : error ] );
-            }
+    var r20 = /%20/g,
+        rbracket = /\[\]$/,
+        rCRLF = /\r?\n/g,
+        rhash = /#.*$/,
+        rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
+        rinput = /^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,
+        // #7653, #8125, #8152: local protocol detection
+        rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,
+        rnoContent = /^(?:GET|HEAD)$/,
+        rprotocol = /^\/\//,
+        rquery = /\?/,
+        rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
+        rselectTextarea = /^(?:select|textarea)/i,
+        rspacesAjax = /\s+/,
+        rts = /([?&])_=[^&]*/,
+        rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,
+
+        // Keep a copy of the old load method
+        _load = jQuery.fn.load,
+
+        /* Prefilters
+	 * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
+	 * 2) These are called:
+	 *    - BEFORE asking for a transport
+	 *    - AFTER param serialization (s.data is a string if s.processData is true)
+	 * 3) key is the dataType
+	 * 4) the catchall symbol "*" can be used
+	 * 5) execution will start with transport dataType and THEN continue down to "*" if needed
+	 */
+        prefilters = {},
+
+        /* Transports bindings
+	 * 1) key is the dataType
+	 * 2) the catchall symbol "*" can be used
+	 * 3) selection will start with transport dataType and THEN go to "*" if needed
+	 */
+        transports = {},
+
+        // Document location
+        ajaxLocation,
+
+        // Document location segments
+        ajaxLocParts,
+
+        // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
+        allTypes = ["*/"] + ["*"];
+
+// #8138, IE may throw an exception when accessing
+// a field from window.location if document.domain has been set
+    try {
+        ajaxLocation = location.href;
+    } catch( e ) {
+        // Use the href attribute of an A element
+        // since IE will modify it given document.location
+        ajaxLocation = document.createElement( "a" );
+        ajaxLocation.href = "";
+        ajaxLocation = ajaxLocation.href;
+    }
 
-            // Complete
-            completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
+// Segment location into parts
+    ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
 
-            if ( fireGlobals ) {
-                // 触发全局的 ajax 完成事件
-                globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
-                // Handle the global AJAX counter
-                if (!( --jQuery.active ) ) {
-                    // 如果 jQuery.active 减为 0,触发 ajaxStop 事件
-                    jQuery.event.trigger( "ajaxStop" );
-                }
+// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
+    function addToPrefiltersOrTransports( structure ) {
+
+        // dataTypeExpression is optional and defaults to "*"
+        return function( dataTypeExpression, func ) {
+
+            if ( typeof dataTypeExpression !== "string" ) {
+                func = dataTypeExpression;
+                dataTypeExpression = "*";
             }
-        }
 
-// Attach deferreds
-        deferred.promise( jqXHR );
-        jqXHR.success = jqXHR.done;
-        jqXHR.error = jqXHR.fail;
-        jqXHR.complete = completeDeferred.add;
-
-// Status-dependent callbacks
-        jqXHR.statusCode = function( map ) {
-            if ( map ) {
-                var tmp;
-                if ( state < 2 ) {
-                    for ( tmp in map ) {
-                        // 存储状态码映射关系
-                        statusCode[ tmp ] = [ statusCode[tmp], map[tmp] ];
+            if ( jQuery.isFunction( func ) ) {
+                var dataTypes = dataTypeExpression.toLowerCase().split( rspacesAjax ),
+                    i = 0,
+                    length = dataTypes.length,
+                    dataType,
+                    list,
+                    placeBefore;
+
+                // For each dataType in the dataTypeExpression
+                for ( ; i < length; i++ ) {
+                    dataType = dataTypes[ i ];
+                    // We control if we're asked to add before
+                    // any existing element
+                    placeBefore = /^\+/.test( dataType );
+                    if ( placeBefore ) {
+                        dataType = dataType.substr( 1 ) || "*";
                     }
-                } else {
-                    tmp = map[ jqXHR.status ];
-                    // 根据状态码添加相应的 then 处理
-                    jqXHR.then( tmp, tmp );
+                    list = structure[ dataType ] = structure[ dataType ] || [];
+                    // then we add to the structure accordingly
+                    list[ placeBefore ? "unshift" : "push" ]( func );
                 }
             }
-            return this;
         };
+    }
 
-// Remove hash character (#7531: and string promotion)
-// Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
-// We also use the url parameter if available
-        s.url = ( ( url || s.url ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
-
-// Extract dataTypes list
-        s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( rspacesAjax );
-
-// Determine if a cross-domain request is in order
-        if ( s.crossDomain == null ) {
-            parts = rurl.exec( s.url.toLowerCase() );
-            s.crossDomain =!!( parts &&
-                ( parts[ 1 ]!= ajaxLocParts[ 1 ] || parts[ 2 ]!= ajaxLocParts[ 2 ] ||
-                    ( parts[ 3 ] || ( parts[ 1 ] === "http:"? 80 : 443 ) )!=
-                    ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:"? 80 : 443 ) ) )
-            );
+// Base inspection function for prefilters and transports
+    function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR,
+                                            dataType /* internal */, inspected /* internal */ ) {
+
+        dataType = dataType || options.dataTypes[ 0 ];
+        inspected = inspected || {};
+
+        inspected[ dataType ] = true;
+
+        var list = structure[ dataType ],
+            i = 0,
+            length = list ? list.length : 0,
+            executeOnly = ( structure === prefilters ),
+            selection;
+
+        for ( ; i < length && ( executeOnly || !selection ); i++ ) {
+            selection = list[ i ]( options, originalOptions, jqXHR );
+            // If we got redirected to another dataType
+            // we try there if executing only and not done already
+            if ( typeof selection === "string" ) {
+                if ( !executeOnly || inspected[ selection ] ) {
+                    selection = undefined;
+                } else {
+                    options.dataTypes.unshift( selection );
+                    selection = inspectPrefiltersOrTransports(
+                        structure, options, originalOptions, jqXHR, selection, inspected );
+                }
+            }
         }
-
-// Convert data if not already a string
-        if ( s.data && s.processData && typeof s.data!== "string" ) {
-            // 将数据转换为查询字符串形式
-            s.data = jQuery.param( s.data, s.traditional );
+        // If we're only executing or nothing was selected
+        // we try the catchall dataType if not done already
+        if ( ( executeOnly || !selection ) && !inspected[ "*" ] ) {
+            selection = inspectPrefiltersOrTransports(
+                structure, options, originalOptions, jqXHR, "*", inspected );
         }
+        // unnecessary when only executing (prefilters)
+        // but it'll be ignored by the caller in that case
+        return selection;
+    }
 
-// Apply prefilters
-        inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
-
-// If request was aborted inside a prefilter, stop there
-        if ( state === 2 ) {
-            // 如果在预过滤器中请求被中止,则返回 false
-            return false;
+// A special extend for ajax options
+// that takes "flat" options (not to be deep extended)
+// Fixes #9887
+    function ajaxExtend( target, src ) {
+        var key, deep,
+            flatOptions = jQuery.ajaxSettings.flatOptions || {};
+        for ( key in src ) {
+            if ( src[ key ] !== undefined ) {
+                ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];
+            }
         }
-
-// We can fire global events as of now if asked to
-        fireGlobals = s.global;
-
-// Uppercase the type
-        s.type = s.type.toUpperCase();
-
-// Determine if request has content
-        s.hasContent =!rnoContent.test( s.type );
-
-// Watch for a new set of requests
-        if ( fireGlobals && jQuery.active++ === 0 ) {
-            // 如果允许触发全局事件且 jQuery.active 为 0,则触发 ajaxStart 事件
-            jQuery.event.trigger( "ajaxStart" );
+        if ( deep ) {
+            jQuery.extend( true, target, deep );
         }
+    }
 
-// More options handling for requests with no content
-        if (!s.hasContent ) {
-            // If data is available, append data to url
-            if ( s.data ) {
-                s.url += ( rquery.test( s.url )? "&" : "?" ) + s.data;
-                // #9682: remove data so that it's not used in an eventual retry
-                delete s.data;
-            }
-
-            // Get ifModifiedKey before adding the anti-cache parameter
-            ifModifiedKey = s.url;
-
-            // Add anti-cache in url if needed
-            if ( s.cache === false ) {
-                var ts = jQuery.now(),
-                    // try replacing _= if it is there
-                    ret = s.url.replace( rts, "$1_=" + ts );
+    jQuery.fn.extend({
+        load: function( url, params, callback ) {
+            if ( typeof url !== "string" && _load ) {
+                return _load.apply( this, arguments );
 
-                // if nothing was replaced, add timestamp to the end
-                s.url = ret + ( ( ret === s.url )? ( rquery.test( s.url )? "&" : "?" ) + "_=" + ts : "" );
+                // Don't do a request if no elements are being requested
+            } else if ( !this.length ) {
+                return this;
             }
-        }
-
-// Set the correct header, if data is being sent
-        if ( s.data && s.hasContent && s.contentType!== false || options.contentType ) {
-            // 设置请求的 Content-Type 头
-            jqXHR.setRequestHeader( "Content-Type", s.contentType );
-        }
 
-// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
-        if ( s.ifModified ) {
-            ifModifiedKey = ifModifiedKey || s.url;
-            if ( jQuery.lastModified[ ifModifiedKey ] ) {
-                // 设置 If-Modified-Since 头
-                jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ ifModifiedKey ] );
-            }
-            if ( jQuery.etag[ ifModifiedKey ] ) {
-                // 设置 If-None-Match 头
-                jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ ifModifiedKey ] );
-            }
-        }
+            var off = url.indexOf( " " );
+            if ( off >= 0 ) {
+                var selector = url.slice( off, url.length );
+                url = url.slice( 0, off );
+            }
+
+            // Default to a GET request
+            var type = "GET";
+
+            // If the second parameter was provided
+            if ( params ) {
+                // If it's a function
+                if ( jQuery.isFunction( params ) ) {
+                    // We assume that it's the callback
+                    callback = params;
+                    params = undefined;
+
+                    // Otherwise, build a param string
+                } else if ( typeof params === "object" ) {
+                    params = jQuery.param( params, jQuery.ajaxSettings.traditional );
+                    type = "POST";
+                }
+            }
+
+            var self = this;
+
+            // Request the remote document
+            jQuery.ajax({
+                url: url,
+                type: type,
+                dataType: "html",
+                data: params,
+                // Complete callback (responseText is used internally)
+                complete: function( jqXHR, status, responseText ) {
+                    // Store the response as specified by the jqXHR object
+                    responseText = jqXHR.responseText;
+                    // If successful, inject the HTML into all the matched elements
+                    if ( jqXHR.isResolved() ) {
+                        // #4825: Get the actual response in case
+                        // a dataFilter is present in ajaxSettings
+                        jqXHR.done(function( r ) {
+                            responseText = r;
+                        });
+                        // See if a selector was specified
+                        self.html( selector ?
+                            // Create a dummy div to hold the results
+                            jQuery("<div>")
+                                // inject the contents of the document in, removing the scripts
+                                // to avoid any 'Permission Denied' errors in IE
+                                .append(responseText.replace(rscript, ""))
 
-        // Set the Accepts header for the server, depending on the dataType
-        jqXHR.setRequestHeader(
-            "Accept",
-            s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ]?
-                s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ]!== "*"? ", " + allTypes + "; q=0.01" : "" ) :
-                s.accepts[ "*" ]
-        );
-// 设置请求的 Accept 头信息,根据 dataTypes 和 accepts 属性进行设置
-
-// Check for headers option
-        for ( i in s.headers ) {
-            // 遍历 s.headers 并设置请求头信息
-            jqXHR.setRequestHeader( i, s.headers[ i ] );
-        }
+                                // Locate the specified elements
+                                .find(selector) :
 
-// Allow custom headers/mimetypes and early abort
-        if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
-            // 如果 beforeSend 回调返回 false 或者状态为 2,则中止请求
-            // Abort if not done already
-            jqXHR.abort();
-            return false;
-        }
+                            // If not, just inject the full result
+                            responseText );
+                    }
 
-// Install callbacks on deferreds
-        for ( i in { success: 1, error: 1, complete: 1 } ) {
-            // 为 success、error、complete 事件安装回调函数
-            jqXHR[ i ]( s[ i ] );
-        }
+                    if ( callback ) {
+                        self.each( callback, [ responseText, status, jqXHR ] );
+                    }
+                }
+            });
 
-// Get transport
-        transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
-// 获取传输对象
+            return this;
+        },
 
-// If no transport, we auto-abort
-        if (!transport ) {
-            // 如果没有传输对象,完成请求并设置状态为 -1 及相应的错误信息
-            done( -1, "No Transport" );
-        } else {
-            jqXHR.readyState = 1;
-            // Send global event
-            if ( fireGlobals ) {
-                // 发送全局的 ajaxSend 事件
-                globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
-            }
-            // Timeout
-            if ( s.async && s.timeout > 0 ) {
-                // 设置超时定时器,如果超时则中止请求
-                timeoutTimer = setTimeout( function(){
-                    jqXHR.abort( "timeout" );
-                }, s.timeout );
-            }
+        serialize: function() {
+            return jQuery.param( this.serializeArray() );
+        },
 
-            try {
-                state = 1;
-                // 发送请求,并将 done 作为完成回调函数
-                transport.send( requestHeaders, done );
-            } catch (e) {
-                // Propagate exception as error if not done
-                if ( state < 2 ) {
-                    // 如果状态小于 2,将异常作为错误完成请求
-                    done( -1, e );
-                    // Simply rethrow otherwise
-                } else {
-                    // 否则重新抛出异常
-                    throw e;
-                }
-            }
+        serializeArray: function() {
+            return this.map(function(){
+                return this.elements ? jQuery.makeArray( this.elements ) : this;
+            })
+                .filter(function(){
+                    return this.name && !this.disabled &&
+                        ( this.checked || rselectTextarea.test( this.nodeName ) ||
+                            rinput.test( this.type ) );
+                })
+                .map(function( i, elem ){
+                    var val = jQuery( this ).val();
+
+                    return val == null ?
+                        null :
+                        jQuery.isArray( val ) ?
+                            jQuery.map( val, function( val, i ){
+                                return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+                            }) :
+                            { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+                }).get();
         }
+    });
 
-        return jqXHR;
-    },
-
-// Serialize an array of form elements or a set of
-// key/values into a query string
-    param: function( a, traditional ) {
-        var s = [],
-            add = function( key, value ) {
-                // If value is a function, invoke it and return its value
-                value = jQuery.isFunction( value )? value() : value;
-                // 将键值对添加到数组 s 中,并进行 URI 编码
-                s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
-            };
+// Attach a bunch of functions for handling common AJAX events
+    jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split( " " ), function( i, o ){
+        jQuery.fn[ o ] = function( f ){
+            return this.on( o, f );
+        };
+    });
 
-        // Set traditional to true for jQuery <= 1.3.2 behavior.
-        if ( traditional === undefined ) {
-            traditional = jQuery.ajaxSettings.traditional;
-        }
+    jQuery.each( [ "get", "post" ], function( i, method ) {
+        jQuery[ method ] = function( url, data, callback, type ) {
+            // shift arguments if data argument was omitted
+            if ( jQuery.isFunction( data ) ) {
+                type = type || callback;
+                callback = data;
+                data = undefined;
+            }
 
-        // If an array was passed in, assume that it is an array of form elements.
-        if ( jQuery.isArray( a ) || ( a.jquery &&!jQuery.isPlainObject( a ) ) ) {
-            // Serialize the form elements
-            jQuery.each( a, function() {
-                // 遍历数组或 jQuery 对象,调用 add 函数添加键值对
-                add( this.name, this.value );
+            return jQuery.ajax({
+                type: method,
+                url: url,
+                data: data,
+                success: callback,
+                dataType: type
             });
+        };
+    });
 
-        } else {
-            // If traditional, encode the "old" way (the way 1.3.2 or older
-            // did it), otherwise encode params recursively.
-            for ( var prefix in a ) {
-                // 对于对象,调用 buildParams 进行参数构建
-                buildParams( prefix, a[ prefix ], traditional, add );
-            }
-        }
+    jQuery.extend({
 
-        // Return the resulting serialization
-        return s.join( "&" ).replace( r20, "+" );
-        // 将数组元素拼接为查询字符串并替换相应字符
-    }
-});
+        getScript: function( url, callback ) {
+            return jQuery.get( url, undefined, callback, "script" );
+        },
 
-function buildParams( prefix, obj, traditional, add ) {
-    if ( jQuery.isArray( obj ) ) {
-        // Serialize array item.
-        jQuery.each( obj, function( i, v ) {
-            if ( traditional || rbracket.test( prefix ) ) {
-                // Treat each array item as a scalar.
-                // 将数组元素作为标量添加
-                add( prefix, v );
+        getJSON: function( url, data, callback ) {
+            return jQuery.get( url, data, callback, "json" );
+        },
 
+        // Creates a full fledged settings object into target
+        // with both ajaxSettings and settings fields.
+        // If target is omitted, writes into ajaxSettings.
+        ajaxSetup: function( target, settings ) {
+            if ( settings ) {
+                // Building a settings object
+                ajaxExtend( target, jQuery.ajaxSettings );
             } else {
-                // If array item is non-scalar (array or object), encode its
-                // numeric index to resolve deserialization ambiguity issues.
-                // Note that rack (as of 1.0.0) can't currently deserialize
-                // nested arrays properly, and attempting to do so may cause
-                // a server error. Possible fixes are to modify rack's
-                // deserialization algorithm or to provide an option or flag
-                // to force array serialization to be shallow.
-                // 对于非标量数组元素,递归调用 buildParams 进行编码
-                buildParams( prefix + "[" + ( typeof v === "object"? i : "" ) + "]", v, traditional, add );
+                // Extending ajaxSettings
+                settings = target;
+                target = jQuery.ajaxSettings;
             }
-        });
+            ajaxExtend( target, settings );
+            return target;
+        },
 
-    } else if (!traditional && jQuery.type( obj ) === "object" ) {
-        // Serialize object item.
-        for ( var name in obj ) {
-            // 对于对象,递归调用 buildParams 进行编码
-            buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
-        }
+        ajaxSettings: {
+            url: ajaxLocation,
+            isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
+            global: true,
+            type: "GET",
+            contentType: "application/x-www-form-urlencoded; charset=UTF-8",
+            processData: true,
+            async: true,
+            /*
+		timeout: 0,
+		data: null,
+		dataType: null,
+		username: null,
+		password: null,
+		cache: null,
+		traditional: false,
+		headers: {},
+		*/
+
+            accepts: {
+                xml: "application/xml, text/xml",
+                html: "text/html",
+                text: "text/plain",
+                json: "application/json, text/javascript",
+                "*": allTypes
+            },
 
-    } else {
-        // Serialize scalar item.
-        // 对于标量,直接添加
-        add( prefix, obj );
-    }
-}
+            contents: {
+                xml: /xml/,
+                html: /html/,
+                json: /json/
+            },
 
-// This is still on the jQuery object... for now
-// Want to move this to jQuery.ajax some day
-jQuery.extend({
+            responseFields: {
+                xml: "responseXML",
+                text: "responseText"
+            },
 
-    // Counter for holding the number of active queries
-    active: 0,
-    // 存储活动请求的数量
+            // List of data converters
+            // 1) key format is "source_type destination_type" (a single space in-between)
+            // 2) the catchall symbol "*" can be used for source_type
+            converters: {
 
-    // Last-Modified header cache for next request
-    lastModified: {},
-    etag: {}
-    // 存储 Last-Modified 和 Etag 头信息
-});
+                // Convert anything to text
+                "* text": window.String,
 
-/* Handles responses to an ajax request:
- * - sets all responseXXX fields accordingly
- * - finds the right dataType (mediates between content-type and expected dataType)
- * - returns the corresponding response
- */
-function ajaxHandleResponses( s, jqXHR, responses ) {
-
-    var contents = s.contents,
-        dataTypes = s.dataTypes,
-        responseFields = s.responseFields,
-        ct,
-        type,
-        finalDataType,
-        firstDataType;
-
-    // Fill responseXXX fields
-    for ( type in responseFields ) {
-        if ( type in responses ) {
-            // 填充响应字段
-            jqXHR[ responseFields[type] ] = responses[ type ];
-        }
-    }
+                // Text to html (true = no transformation)
+                "text html": true,
 
-    // Remove auto dataType and get content-type in the process
-    while( dataTypes[ 0 ] === "*" ) {
-        dataTypes.shift();
-        if ( ct === undefined ) {
-            // 获取响应的 content-type 头信息
-            ct = s.mimeType || jqXHR.getResponseHeader( "content-type" );
-        }
-    }
+                // Evaluate text as a json expression
+                "text json": jQuery.parseJSON,
 
-    // Check if we're dealing with a known content-type
-    if ( ct ) {
-        for ( type in contents ) {
-            if ( contents[ type ] && contents[ type ].test( ct ) ) {
-                // 根据 content-type 找到对应的 dataType 并添加到 dataTypes 头部
-                dataTypes.unshift( type );
-                break;
-            }
-        }
-    }
+                // Parse text as xml
+                "text xml": jQuery.parseXML
+            },
 
-    // Check to see if we have a response for the expected dataType
-    if ( dataTypes[ 0 ] in responses ) {
-        // 如果存在期望的数据类型的响应,设置最终的数据类型
-        finalDataType = dataTypes[ 0 ];
-    } else {
-        // Try convertible dataTypes
-        for ( type in responses ) {
-            if (!dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
-                finalDataType = type;
-                break;
-            }
-            if (!firstDataType ) {
-                firstDataType = type;
+            // For options that shouldn't be deep extended:
+            // you can add your own custom options here if
+            // and when you create one that shouldn't be
+            // deep extended (see ajaxExtend)
+            flatOptions: {
+                context: true,
+                url: true
             }
-        }
-        // Or just use first one
-        finalDataType = finalDataType || firstDataType;
-    }
+        },
 
-    // If we found a dataType
-    // We add the dataType to the list if needed
-    // and return the corresponding response
-    if ( finalDataType ) {
-        if ( finalDataType!== dataTypes[ 0 ] ) {
-            dataTypes.unshift( finalDataType );
-        }
-        return responses[ finalDataType ];
-        // 返回最终的数据类型的响应
-    }
-}
+        ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
+        ajaxTransport: addToPrefiltersOrTransports( transports ),
+
+        // Main method
+        ajax: function( url, options ) {
+
+            // If url is an object, simulate pre-1.5 signature
+            if ( typeof url === "object" ) {
+                options = url;
+                url = undefined;
+            }
+
+            // Force options to be an object
+            options = options || {};
+
+            var // Create the final options object
+                s = jQuery.ajaxSetup( {}, options ),
+                // Callbacks context
+                callbackContext = s.context || s,
+                // Context for global events
+                // It's the callbackContext if one was provided in the options
+                // and if it's a DOM node or a jQuery collection
+                globalEventContext = callbackContext !== s &&
+                ( callbackContext.nodeType || callbackContext instanceof jQuery ) ?
+                    jQuery( callbackContext ) : jQuery.event,
+                // Deferreds
+                deferred = jQuery.Deferred(),
+                completeDeferred = jQuery.Callbacks( "once memory" ),
+                // Status-dependent callbacks
+                statusCode = s.statusCode || {},
+                // ifModified key
+                ifModifiedKey,
+                // Headers (they are sent all at once)
+                requestHeaders = {},
+                requestHeadersNames = {},
+                // Response headers
+                responseHeadersString,
+                responseHeaders,
+                // transport
+                transport,
+                // timeout handle
+                timeoutTimer,
+                // Cross-domain detection vars
+                parts,
+                // The jqXHR state
+                state = 0,
+                // To know if global events are to be dispatched
+                fireGlobals,
+                // Loop variable
+                i,
+                // Fake xhr
+                jqXHR = {
 
-// Chain conversions given the request and the original response
-function ajaxConvert( s, response ) {
+                    readyState: 0,
 
-    // Apply the dataFilter if provided
-    if ( s.dataFilter ) {
-        // 应用数据过滤器
-        response = s.dataFilter( response, s.dataType );
-    }
+                    // Caches the header
+                    setRequestHeader: function( name, value ) {
+                        if ( !state ) {
+                            var lname = name.toLowerCase();
+                            name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
+                            requestHeaders[ name ] = value;
+                        }
+                        return this;
+                    },
 
-    var dataTypes = s.dataTypes,
-        converters = {},
-        i,
-        key,
-        length = dataTypes.length,
-        tmp,
-        // Current and previous dataTypes
-        current = dataTypes[ 0 ],
-        prev,
-        // Conversion expression
-        conversion,
-        // Conversion function
-        conv,
-        // Conversion functions (transitive conversion)
-        conv1,
-        conv2;
-
-    // For each dataType in the chain
-    for ( i = 1; i < length; i++ ) {
-
-        // Create converters map
-        // with lowercased keys
-        if ( i === 1 ) {
-            for ( key in s.converters ) {
-                if ( typeof key === "string" ) {
-                    // 创建转换器映射
-                    converters[ key.toLowerCase() ] = s.converters[ key ];
-                }
-            }
-        }
+                    // Raw string
+                    getAllResponseHeaders: function() {
+                        return state === 2 ? responseHeadersString : null;
+                    },
 
-        // Get the dataTypes
-        prev = current;
-        current = dataTypes[ i ];
-
-        // If current is auto dataType, update it to prev
-        if ( current === "*" ) {
-            current = prev;
-            // If no auto and dataTypes are actually different
-        } else if ( prev!== "*" && prev!== current ) {
-
-            // Get the converter
-            conversion = prev + " " + current;
-            conv = converters[ conversion ] || converters[ "* " + current ];
-
-            // If there is no direct converter, search transitively
-            if (!conv ) {
-                conv2 = undefined;
-                for ( conv1 in converters ) {
-                    tmp = conv1.split( " " );
-                    if ( tmp[ 0 ] === prev || tmp[ 0 ] === "*" ) {
-                        conv2 = converters[ tmp[1] + " " + current ];
-                        if ( conv2 ) {
-                            conv1 = converters[ conv1 ];
-                            if ( conv1 === true ) {
-                                conv = conv2;
-                            } else if ( conv2 === true ) {
-                                conv = conv1;
+                    // Builds headers hashtable if needed
+                    getResponseHeader: function( key ) {
+                        var match;
+                        if ( state === 2 ) {
+                            if ( !responseHeaders ) {
+                                responseHeaders = {};
+                                while( ( match = rheaders.exec( responseHeadersString ) ) ) {
+                                    responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
+                                }
                             }
-                            break;
+                            match = responseHeaders[ key.toLowerCase() ];
                         }
-                    }
-                }
-            }
-            // If we found no converter, dispatch an error
-            if (!( conv || conv2 ) ) {
-                // 未找到转换器时抛出错误
-                jQuery.error( "No conversion from " + conversion.replace(" "," to ") );
-            }
-            // If found converter is not an equivalence
-            if ( conv!== true ) {
-                // Convert with 1 or 2 converters accordingly
-                response = conv? conv( response ) : conv2( conv1(response) );
-                // 使用转换器进行数据转换
-            }
-        }
-    }
-    return response;
-}
+                        return match === undefined ? null : match;
+                    },
 
+                    // Overrides response content-type header
+                    overrideMimeType: function( type ) {
+                        if ( !state ) {
+                            s.mimeType = type;
+                        }
+                        return this;
+                    },
 
+                    // Cancel the request
+                    abort: function( statusText ) {
+                        statusText = statusText || "abort";
+                        if ( transport ) {
+                            transport.abort( statusText );
+                        }
+                        done( 0, statusText );
+                        return this;
+                    }
+                };
 
+            // Callback for when everything is done
+            // It is defined here because jslint complains if it is declared
+            // at the end of the function (which would be more logical and readable)
+            function done( status, nativeStatusText, responses, headers ) {
 
-// 创建一个变量存储 jQuery 的当前时间戳
-var jsc = jQuery.now(),
-    // 定义一个正则表达式,用于匹配特定的字符串模式
-    jsre = /(\=)\?(&|$)|\?\?/i;
+                // Called once
+                if ( state === 2 ) {
+                    return;
+                }
 
-// Default jsonp settings
-// 设置 jQuery 的 AJAX 默认配置
-jQuery.ajaxSetup({
-    // jsonp 请求的回调函数名称参数
-    jsonp: "callback",
-    jsonpCallback: function() {
-        // 生成一个唯一的 jsonp 回调函数名称,基于 jQuery 的 expando 属性和时间戳
-        return jQuery.expando + "_" + (jsc++);
-    }
-});
+                // State is "done" now
+                state = 2;
 
-// Detect, normalize options and install callbacks for jsonp requests
-// 为 jsonp 请求检测、规范化选项和安装回调函数
-jQuery.ajaxPrefilter("json jsonp", function(s, originalSettings, jqXHR) {
-    // 检查 s.data 是否为字符串且其 contentType 是否为 application/x-www-form-urlencoded 类型
-    var inspectData = (typeof s.data === "string") && /^application\/x\-www\-form\-urlencoded/.test(s.contentType);
-
-    if (s.dataTypes[0] === "jsonp" ||
-        s.jsonp!== false && (jsre.test(s.url) ||
-            inspectData && jsre.test(s.data))) {
-
-        var responseContainer,
-            // 确定 jsonpCallback 的值,根据 s.jsonpCallback 是否为函数调用相应的方法
-            jsonpCallback = s.jsonpCallback =
-                jQuery.isFunction(s.jsonpCallback)? s.jsonpCallback() : s.jsonpCallback,
-            // 存储之前的 window[jsonpCallback] 函数
-            previous = window[jsonpCallback],
-            url = s.url,
-            data = s.data,
-            // 用于替换的字符串模式
-            replace = "$1" + jsonpCallback + "$2";
-
-        if (s.jsonp!== false) {
-            // 替换 url 中的匹配部分
-            url = url.replace(jsre, replace);
-            if (s.url === url) {
-                if (inspectData) {
-                    // 替换 data 中的匹配部分
-                    data = data.replace(jsre, replace);
-                }
-                if (s.data === data) {
-                    // 如果 url 和 data 都没有变化,手动添加回调参数
-                    url += (/\?/.test(url)? "&" : "?") + s.jsonp + "=" + jsonpCallback;
+                // Clear timeout if it exists
+                if ( timeoutTimer ) {
+                    clearTimeout( timeoutTimer );
                 }
-            }
-        }
 
-        s.url = url;
-        s.data = data;
+                // Dereference transport for early garbage collection
+                // (no matter how long the jqXHR object will be used)
+                transport = undefined;
 
-        // Install callback
-        // 在 window 对象上安装回调函数,将响应存储在 responseContainer 中
-        window[jsonpCallback] = function(response) {
-            responseContainer = [response];
-        };
+                // Cache response headers
+                responseHeadersString = headers || "";
 
-        // Clean-up function
-        jqXHR.always(function() {
-            // 将回调函数恢复到之前的值
-            window[jsonpCallback] = previous;
-            // 如果是函数且有响应,调用该回调函数
-            if (responseContainer && jQuery.isFunction(previous)) {
-                window[jsonpCallback](responseContainer[0]);
-            }
-        });
+                // Set readyState
+                jqXHR.readyState = status > 0 ? 4 : 0;
 
-        // Use data converter to retrieve json after script execution
-        // 定义数据转换器,当脚本执行后尝试获取 json 数据
-        s.converters["script json"] = function() {
-            if (!responseContainer) {
-                // 如果没有调用回调函数则报错
-                jQuery.error(jsonpCallback + " was not called");
-            }
-            return responseContainer[0];
-        };
+                var isSuccess,
+                    success,
+                    error,
+                    statusText = nativeStatusText,
+                    response = responses ? ajaxHandleResponses( s, jqXHR, responses ) : undefined,
+                    lastModified,
+                    etag;
 
-        // force json dataType
-        // 强制将第一个数据类型设置为 json
-        s.dataTypes[0] = "json";
+                // If successful, handle type chaining
+                if ( status >= 200 && status < 300 || status === 304 ) {
 
-        // Delegate to script
-        // 委托给 script 处理
-        return "script";
-    }
-});
+                    // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+                    if ( s.ifModified ) {
 
+                        if ( ( lastModified = jqXHR.getResponseHeader( "Last-Modified" ) ) ) {
+                            jQuery.lastModified[ ifModifiedKey ] = lastModified;
+                        }
+                        if ( ( etag = jqXHR.getResponseHeader( "Etag" ) ) ) {
+                            jQuery.etag[ ifModifiedKey ] = etag;
+                        }
+                    }
 
-// Install script dataType
-// 安装 script 数据类型的相关配置
-jQuery.ajaxSetup({
-    accepts: {
-        // 设置 script 类型的接受内容类型
-        script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
-    },
-    contents: {
-        // 定义 script 类型的内容匹配规则
-        script: /javascript|ecmascript/
-    },
-    converters: {
-        // 定义 text 到 script 的数据转换器,使用 jQuery.globalEval 执行脚本
-        "text script": function(text) {
-            jQuery.globalEval(text);
-            return text;
-        }
-    }
-});
+                    // If not modified
+                    if ( status === 304 ) {
 
-// Handle cache's special case and global
-// 处理 script 类型的缓存特殊情况和全局设置
-jQuery.ajaxPrefilter("script", function(s) {
-    if (s.cache === undefined) {
-        // 如果缓存未定义,设置为 false
-        s.cache = false;
-    }
-    if (s.crossDomain) {
-        // 如果是跨域请求,设置请求类型为 GET 并关闭全局设置
-        s.type = "GET";
-        s.global = false;
-    }
-});
+                        statusText = "notmodified";
+                        isSuccess = true;
 
-// Bind script tag hack transport
-// 绑定脚本标签的传输方式
-jQuery.ajaxTransport("script", function(s) {
-    // This transport only deals with cross domain requests
-    // 此传输仅处理跨域请求
-    if (s.crossDomain) {
-        var script,
-            // 获取 head 元素或文档元素
-            head = document.head || document.getElementsByTagName("head")[0] || document.documentElement;
-
-        return {
-            send: function(_, callback) {
-                // 创建一个 script 元素
-                script = document.createElement("script");
-                // 设置 script 元素为异步
-                script.async = "async";
-
-                if (s.scriptCharset) {
-                    // 设置 script 元素的字符集
-                    script.charset = s.scriptCharset;
-                }
-
-                script.src = s.url;
-
-                // Attach handlers for all browsers
-                // 为 script 元素添加加载和状态改变的事件处理函数
-                script.onload = script.onreadystatechange = function(_, isAbort) {
-                    if (isAbort ||!script.readyState || /loaded|complete/.test(script.readyState)) {
-                        // Handle memory leak in IE
-                        // 处理 IE 中的内存泄漏问题
-                        script.onload = script.onreadystatechange = null;
-
-                        // Remove the script
-                        // 移除 script 元素
-                        if (head && script.parentNode) {
-                            head.removeChild(script);
+                        // If we have data
+                    } else {
+
+                        try {
+                            success = ajaxConvert( s, response );
+                            statusText = "success";
+                            isSuccess = true;
+                        } catch(e) {
+                            // We have a parsererror
+                            statusText = "parsererror";
+                            error = e;
+                        }
+                    }
+                } else {
+                    // We extract error from statusText
+                    // then normalize statusText and status for non-aborts
+                    error = statusText;
+                    if ( !statusText || status ) {
+                        statusText = "error";
+                        if ( status < 0 ) {
+                            status = 0;
                         }
+                    }
+                }
+
+                // Set data for the fake xhr object
+                jqXHR.status = status;
+                jqXHR.statusText = "" + ( nativeStatusText || statusText );
 
-                        // Dereference the script
-                        // 解除对 script 的引用
-                        script = undefined;
+                // Success/Error
+                if ( isSuccess ) {
+                    deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
+                } else {
+                    deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
+                }
+
+                // Status-dependent callbacks
+                jqXHR.statusCode( statusCode );
+                statusCode = undefined;
+
+                if ( fireGlobals ) {
+                    globalEventContext.trigger( "ajax" + ( isSuccess ? "Success" : "Error" ),
+                        [ jqXHR, s, isSuccess ? success : error ] );
+                }
+
+                // Complete
+                completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
 
-                        // Callback if not abort
-                        // 如果没有中止,调用回调函数
-                        if (!isAbort) {
-                            callback(200, "success");
+                if ( fireGlobals ) {
+                    globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
+                    // Handle the global AJAX counter
+                    if ( !( --jQuery.active ) ) {
+                        jQuery.event.trigger( "ajaxStop" );
+                    }
+                }
+            }
+
+            // Attach deferreds
+            deferred.promise( jqXHR );
+            jqXHR.success = jqXHR.done;
+            jqXHR.error = jqXHR.fail;
+            jqXHR.complete = completeDeferred.add;
+
+            // Status-dependent callbacks
+            jqXHR.statusCode = function( map ) {
+                if ( map ) {
+                    var tmp;
+                    if ( state < 2 ) {
+                        for ( tmp in map ) {
+                            statusCode[ tmp ] = [ statusCode[tmp], map[tmp] ];
                         }
+                    } else {
+                        tmp = map[ jqXHR.status ];
+                        jqXHR.then( tmp, tmp );
+                    }
+                }
+                return this;
+            };
+
+            // Remove hash character (#7531: and string promotion)
+            // Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
+            // We also use the url parameter if available
+            s.url = ( ( url || s.url ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
+
+            // Extract dataTypes list
+            s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( rspacesAjax );
+
+            // Determine if a cross-domain request is in order
+            if ( s.crossDomain == null ) {
+                parts = rurl.exec( s.url.toLowerCase() );
+                s.crossDomain = !!( parts &&
+                    ( parts[ 1 ] != ajaxLocParts[ 1 ] || parts[ 2 ] != ajaxLocParts[ 2 ] ||
+                        ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) !=
+                        ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) )
+                );
+            }
+
+            // Convert data if not already a string
+            if ( s.data && s.processData && typeof s.data !== "string" ) {
+                s.data = jQuery.param( s.data, s.traditional );
+            }
+
+            // Apply prefilters
+            inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
+
+            // If request was aborted inside a prefilter, stop there
+            if ( state === 2 ) {
+                return false;
+            }
+
+            // We can fire global events as of now if asked to
+            fireGlobals = s.global;
+
+            // Uppercase the type
+            s.type = s.type.toUpperCase();
+
+            // Determine if request has content
+            s.hasContent = !rnoContent.test( s.type );
+
+            // Watch for a new set of requests
+            if ( fireGlobals && jQuery.active++ === 0 ) {
+                jQuery.event.trigger( "ajaxStart" );
+            }
+
+            // More options handling for requests with no content
+            if ( !s.hasContent ) {
+
+                // If data is available, append data to url
+                if ( s.data ) {
+                    s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data;
+                    // #9682: remove data so that it's not used in an eventual retry
+                    delete s.data;
+                }
+
+                // Get ifModifiedKey before adding the anti-cache parameter
+                ifModifiedKey = s.url;
+
+                // Add anti-cache in url if needed
+                if ( s.cache === false ) {
+
+                    var ts = jQuery.now(),
+                        // try replacing _= if it is there
+                        ret = s.url.replace( rts, "$1_=" + ts );
+
+                    // if nothing was replaced, add timestamp to the end
+                    s.url = ret + ( ( ret === s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "" );
+                }
+            }
+
+            // Set the correct header, if data is being sent
+            if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
+                jqXHR.setRequestHeader( "Content-Type", s.contentType );
+            }
+
+            // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+            if ( s.ifModified ) {
+                ifModifiedKey = ifModifiedKey || s.url;
+                if ( jQuery.lastModified[ ifModifiedKey ] ) {
+                    jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ ifModifiedKey ] );
+                }
+                if ( jQuery.etag[ ifModifiedKey ] ) {
+                    jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ ifModifiedKey ] );
+                }
+            }
+
+            // Set the Accepts header for the server, depending on the dataType
+            jqXHR.setRequestHeader(
+                "Accept",
+                s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
+                    s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
+                    s.accepts[ "*" ]
+            );
+
+            // Check for headers option
+            for ( i in s.headers ) {
+                jqXHR.setRequestHeader( i, s.headers[ i ] );
+            }
+
+            // Allow custom headers/mimetypes and early abort
+            if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
+                // Abort if not done already
+                jqXHR.abort();
+                return false;
+
+            }
+
+            // Install callbacks on deferreds
+            for ( i in { success: 1, error: 1, complete: 1 } ) {
+                jqXHR[ i ]( s[ i ] );
+            }
+
+            // Get transport
+            transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
+
+            // If no transport, we auto-abort
+            if ( !transport ) {
+                done( -1, "No Transport" );
+            } else {
+                jqXHR.readyState = 1;
+                // Send global event
+                if ( fireGlobals ) {
+                    globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
+                }
+                // Timeout
+                if ( s.async && s.timeout > 0 ) {
+                    timeoutTimer = setTimeout( function(){
+                        jqXHR.abort( "timeout" );
+                    }, s.timeout );
+                }
+
+                try {
+                    state = 1;
+                    transport.send( requestHeaders, done );
+                } catch (e) {
+                    // Propagate exception as error if not done
+                    if ( state < 2 ) {
+                        done( -1, e );
+                        // Simply rethrow otherwise
+                    } else {
+                        throw e;
                     }
+                }
+            }
+
+            return jqXHR;
+        },
+
+        // Serialize an array of form elements or a set of
+        // key/values into a query string
+        param: function( a, traditional ) {
+            var s = [],
+                add = function( key, value ) {
+                    // If value is a function, invoke it and return its value
+                    value = jQuery.isFunction( value ) ? value() : value;
+                    s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
                 };
-                // Use insertBefore instead of appendChild  to circumvent an IE6 bug.
-                // 使用 insertBefore 代替 appendChild 来避免 IE6 的一个 bug
-                // This arises when a base node is used (#2709 and #4378).
-                // 当使用 base 节点时会出现该问题(参考问题 #2709 和 #4378)
-                head.insertBefore(script, head.firstChild);
-            },
 
-            abort: function() {
-                if (script) {
-                    // 中止请求
-                    script.onload(0, 1);
+            // Set traditional to true for jQuery <= 1.3.2 behavior.
+            if ( traditional === undefined ) {
+                traditional = jQuery.ajaxSettings.traditional;
+            }
+
+            // If an array was passed in, assume that it is an array of form elements.
+            if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
+                // Serialize the form elements
+                jQuery.each( a, function() {
+                    add( this.name, this.value );
+                });
+
+            } else {
+                // If traditional, encode the "old" way (the way 1.3.2 or older
+                // did it), otherwise encode params recursively.
+                for ( var prefix in a ) {
+                    buildParams( prefix, a[ prefix ], traditional, add );
                 }
             }
-        };
+
+            // Return the resulting serialization
+            return s.join( "&" ).replace( r20, "+" );
+        }
+    });
+
+    function buildParams( prefix, obj, traditional, add ) {
+        if ( jQuery.isArray( obj ) ) {
+            // Serialize array item.
+            jQuery.each( obj, function( i, v ) {
+                if ( traditional || rbracket.test( prefix ) ) {
+                    // Treat each array item as a scalar.
+                    add( prefix, v );
+
+                } else {
+                    // If array item is non-scalar (array or object), encode its
+                    // numeric index to resolve deserialization ambiguity issues.
+                    // Note that rack (as of 1.0.0) can't currently deserialize
+                    // nested arrays properly, and attempting to do so may cause
+                    // a server error. Possible fixes are to modify rack's
+                    // deserialization algorithm or to provide an option or flag
+                    // to force array serialization to be shallow.
+                    buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
+                }
+            });
+
+        } else if ( !traditional && jQuery.type( obj ) === "object" ) {
+            // Serialize object item.
+            for ( var name in obj ) {
+                buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
+            }
+
+        } else {
+            // Serialize scalar item.
+            add( prefix, obj );
+        }
     }
-});
 
+// This is still on the jQuery object... for now
+// Want to move this to jQuery.ajax some day
+    jQuery.extend({
+
+        // Counter for holding the number of active queries
+        active: 0,
+
+        // Last-Modified header cache for next request
+        lastModified: {},
+        etag: {}
+
+    });
 
+    /* Handles responses to an ajax request:
+ * - sets all responseXXX fields accordingly
+ * - finds the right dataType (mediates between content-type and expected dataType)
+ * - returns the corresponding response
+ */
+    function ajaxHandleResponses( s, jqXHR, responses ) {
+
+        var contents = s.contents,
+            dataTypes = s.dataTypes,
+            responseFields = s.responseFields,
+            ct,
+            type,
+            finalDataType,
+            firstDataType;
 
-var // #5280: Internet Explorer will keep connections alive if we don't abort on unload
-    // 如果在卸载时不中止,IE 会保持连接处于活动状态
-    xhrOnUnloadAbort = window.ActiveXObject? function() {
-        // Abort all pending requests
-        // 中止所有挂起的请求
-        for ( var key in xhrCallbacks ) {
-            xhrCallbacks[ key ]( 0, 1 );
+        // Fill responseXXX fields
+        for ( type in responseFields ) {
+            if ( type in responses ) {
+                jqXHR[ responseFields[type] ] = responses[ type ];
+            }
         }
-    } : false,
-    xhrId = 0,
-    xhrCallbacks;
+
+        // Remove auto dataType and get content-type in the process
+        while( dataTypes[ 0 ] === "*" ) {
+            dataTypes.shift();
+            if ( ct === undefined ) {
+                ct = s.mimeType || jqXHR.getResponseHeader( "content-type" );
+            }
+        }
+
+        // Check if we're dealing with a known content-type
+        if ( ct ) {
+            for ( type in contents ) {
+                if ( contents[ type ] && contents[ type ].test( ct ) ) {
+                    dataTypes.unshift( type );
+                    break;
+                }
+            }
+        }
+
+        // Check to see if we have a response for the expected dataType
+        if ( dataTypes[ 0 ] in responses ) {
+            finalDataType = dataTypes[ 0 ];
+        } else {
+            // Try convertible dataTypes
+            for ( type in responses ) {
+                if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
+                    finalDataType = type;
+                    break;
+                }
+                if ( !firstDataType ) {
+                    firstDataType = type;
+                }
+            }
+            // Or just use first one
+            finalDataType = finalDataType || firstDataType;
+        }
+
+        // If we found a dataType
+        // We add the dataType to the list if needed
+        // and return the corresponding response
+        if ( finalDataType ) {
+            if ( finalDataType !== dataTypes[ 0 ] ) {
+                dataTypes.unshift( finalDataType );
+            }
+            return responses[ finalDataType ];
+        }
+    }
+
+// Chain conversions given the request and the original response
+    function ajaxConvert( s, response ) {
+
+        // Apply the dataFilter if provided
+        if ( s.dataFilter ) {
+            response = s.dataFilter( response, s.dataType );
+        }
+
+        var dataTypes = s.dataTypes,
+            converters = {},
+            i,
+            key,
+            length = dataTypes.length,
+            tmp,
+            // Current and previous dataTypes
+            current = dataTypes[ 0 ],
+            prev,
+            // Conversion expression
+            conversion,
+            // Conversion function
+            conv,
+            // Conversion functions (transitive conversion)
+            conv1,
+            conv2;
+
+        // For each dataType in the chain
+        for ( i = 1; i < length; i++ ) {
+
+            // Create converters map
+            // with lowercased keys
+            if ( i === 1 ) {
+                for ( key in s.converters ) {
+                    if ( typeof key === "string" ) {
+                        converters[ key.toLowerCase() ] = s.converters[ key ];
+                    }
+                }
+            }
+
+            // Get the dataTypes
+            prev = current;
+            current = dataTypes[ i ];
+
+            // If current is auto dataType, update it to prev
+            if ( current === "*" ) {
+                current = prev;
+                // If no auto and dataTypes are actually different
+            } else if ( prev !== "*" && prev !== current ) {
+
+                // Get the converter
+                conversion = prev + " " + current;
+                conv = converters[ conversion ] || converters[ "* " + current ];
+
+                // If there is no direct converter, search transitively
+                if ( !conv ) {
+                    conv2 = undefined;
+                    for ( conv1 in converters ) {
+                        tmp = conv1.split( " " );
+                        if ( tmp[ 0 ] === prev || tmp[ 0 ] === "*" ) {
+                            conv2 = converters[ tmp[1] + " " + current ];
+                            if ( conv2 ) {
+                                conv1 = converters[ conv1 ];
+                                if ( conv1 === true ) {
+                                    conv = conv2;
+                                } else if ( conv2 === true ) {
+                                    conv = conv1;
+                                }
+                                break;
+                            }
+                        }
+                    }
+                }
+                // If we found no converter, dispatch an error
+                if ( !( conv || conv2 ) ) {
+                    jQuery.error( "No conversion from " + conversion.replace(" "," to ") );
+                }
+                // If found converter is not an equivalence
+                if ( conv !== true ) {
+                    // Convert with 1 or 2 converters accordingly
+                    response = conv ? conv( response ) : conv2( conv1(response) );
+                }
+            }
+        }
+        return response;
+    }
+
+
+
+
+    var jsc = jQuery.now(),
+        jsre = /(\=)\?(&|$)|\?\?/i;
+
+// Default jsonp settings
+    jQuery.ajaxSetup({
+        jsonp: "callback",
+        jsonpCallback: function() {
+            return jQuery.expando + "_" + ( jsc++ );
+        }
+    });
+
+// Detect, normalize options and install callbacks for jsonp requests
+    jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
+
+        var inspectData = ( typeof s.data === "string" ) && /^application\/x\-www\-form\-urlencoded/.test( s.contentType );
+
+        if ( s.dataTypes[ 0 ] === "jsonp" ||
+            s.jsonp !== false && ( jsre.test( s.url ) ||
+                inspectData && jsre.test( s.data ) ) ) {
+
+            var responseContainer,
+                jsonpCallback = s.jsonpCallback =
+                    jQuery.isFunction( s.jsonpCallback ) ? s.jsonpCallback() : s.jsonpCallback,
+                previous = window[ jsonpCallback ],
+                url = s.url,
+                data = s.data,
+                replace = "$1" + jsonpCallback + "$2";
+
+            if ( s.jsonp !== false ) {
+                url = url.replace( jsre, replace );
+                if ( s.url === url ) {
+                    if ( inspectData ) {
+                        data = data.replace( jsre, replace );
+                    }
+                    if ( s.data === data ) {
+                        // Add callback manually
+                        url += (/\?/.test( url ) ? "&" : "?") + s.jsonp + "=" + jsonpCallback;
+                    }
+                }
+            }
+
+            s.url = url;
+            s.data = data;
+
+            // Install callback
+            window[ jsonpCallback ] = function( response ) {
+                responseContainer = [ response ];
+            };
+
+            // Clean-up function
+            jqXHR.always(function() {
+                // Set callback back to previous value
+                window[ jsonpCallback ] = previous;
+                // Call if it was a function and we have a response
+                if ( responseContainer && jQuery.isFunction( previous ) ) {
+                    window[ jsonpCallback ]( responseContainer[ 0 ] );
+                }
+            });
+
+            // Use data converter to retrieve json after script execution
+            s.converters["script json"] = function() {
+                if ( !responseContainer ) {
+                    jQuery.error( jsonpCallback + " was not called" );
+                }
+                return responseContainer[ 0 ];
+            };
+
+            // force json dataType
+            s.dataTypes[ 0 ] = "json";
+
+            // Delegate to script
+            return "script";
+        }
+    });
+
+
+
+
+// Install script dataType
+    jQuery.ajaxSetup({
+        accepts: {
+            script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
+        },
+        contents: {
+            script: /javascript|ecmascript/
+        },
+        converters: {
+            "text script": function( text ) {
+                jQuery.globalEval( text );
+                return text;
+            }
+        }
+    });
+
+// Handle cache's special case and global
+    jQuery.ajaxPrefilter( "script", function( s ) {
+        if ( s.cache === undefined ) {
+            s.cache = false;
+        }
+        if ( s.crossDomain ) {
+            s.type = "GET";
+            s.global = false;
+        }
+    });
+
+// Bind script tag hack transport
+    jQuery.ajaxTransport( "script", function(s) {
+
+        // This transport only deals with cross domain requests
+        if ( s.crossDomain ) {
+
+            var script,
+                head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement;
+
+            return {
+
+                send: function( _, callback ) {
+
+                    script = document.createElement( "script" );
+
+                    script.async = "async";
+
+                    if ( s.scriptCharset ) {
+                        script.charset = s.scriptCharset;
+                    }
+
+                    script.src = s.url;
+
+                    // Attach handlers for all browsers
+                    script.onload = script.onreadystatechange = function( _, isAbort ) {
+
+                        if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {
+
+                            // Handle memory leak in IE
+                            script.onload = script.onreadystatechange = null;
+
+                            // Remove the script
+                            if ( head && script.parentNode ) {
+                                head.removeChild( script );
+                            }
+
+                            // Dereference the script
+                            script = undefined;
+
+                            // Callback if not abort
+                            if ( !isAbort ) {
+                                callback( 200, "success" );
+                            }
+                        }
+                    };
+                    // Use insertBefore instead of appendChild  to circumvent an IE6 bug.
+                    // This arises when a base node is used (#2709 and #4378).
+                    head.insertBefore( script, head.firstChild );
+                },
+
+                abort: function() {
+                    if ( script ) {
+                        script.onload( 0, 1 );
+                    }
+                }
+            };
+        }
+    });
+
+
+
+
+    var // #5280: Internet Explorer will keep connections alive if we don't abort on unload
+        xhrOnUnloadAbort = window.ActiveXObject ? function() {
+            // Abort all pending requests
+            for ( var key in xhrCallbacks ) {
+                xhrCallbacks[ key ]( 0, 1 );
+            }
+        } : false,
+        xhrId = 0,
+        xhrCallbacks;
 
 // Functions to create xhrs
-// 创建 XMLHttpRequest 对象的函数
-function createStandardXHR() {
-    try {
-        // 尝试创建标准的 XMLHttpRequest 对象
-        return new window.XMLHttpRequest();
-    } catch( e ) {}
-}
+    function createStandardXHR() {
+        try {
+            return new window.XMLHttpRequest();
+        } catch( e ) {}
+    }
 
-function createActiveXHR() {
-    try {
-        // 尝试创建 ActiveXObject 类型的 XMLHttpRequest 对象
-        return new window.ActiveXObject( "Microsoft.XMLHTTP" );
-    } catch( e ) {}
-}
+    function createActiveXHR() {
+        try {
+            return new window.ActiveXObject( "Microsoft.XMLHTTP" );
+        } catch( e ) {}
+    }
 
 // Create the request object
 // (This is still attached to ajaxSettings for backward compatibility)
-// 创建请求对象(为了向后兼容,仍然附加到 ajaxSettings)
-jQuery.ajaxSettings.xhr = window.ActiveXObject?
-    /* Microsoft failed to properly
-     * implement the XMLHttpRequest in IE7 (can't request local files),
-     * so we use the ActiveXObject when it is available
-     * Additionally XMLHttpRequest can be disabled in IE7/IE8 so
-     * we need a fallback.
-     */
-    function() {
-        // 在 IE 中,如果不是本地请求,优先使用标准的 XMLHttpRequest 对象,否则使用 ActiveXObject
-        return!this.isLocal && createStandardXHR() || createActiveXHR();
-    } :
-    // For all other browsers, use the standard XMLHttpRequest object
-    // 对于其他浏览器,使用标准的 XMLHttpRequest 对象
-    createStandardXHR;
+    jQuery.ajaxSettings.xhr = window.ActiveXObject ?
+        /* Microsoft failed to properly
+	 * implement the XMLHttpRequest in IE7 (can't request local files),
+	 * so we use the ActiveXObject when it is available
+	 * Additionally XMLHttpRequest can be disabled in IE7/IE8 so
+	 * we need a fallback.
+	 */
+        function() {
+            return !this.isLocal && createStandardXHR() || createActiveXHR();
+        } :
+        // For all other browsers, use the standard XMLHttpRequest object
+        createStandardXHR;
 
 // Determine support properties
-// 确定支持的属性
-(function( xhr ) {
-    jQuery.extend( jQuery.support, {
-        // 检查是否支持 ajax
-        ajax:!!xhr,
-        // 检查是否支持跨域资源共享 (CORS)
-        cors:!!xhr && ( "withCredentials" in xhr )
-    });
-})( jQuery.ajaxSettings.xhr() );
+    (function( xhr ) {
+        jQuery.extend( jQuery.support, {
+            ajax: !!xhr,
+            cors: !!xhr && ( "withCredentials" in xhr )
+        });
+    })( jQuery.ajaxSettings.xhr() );
 
 // Create transport if the browser can provide an xhr
-// 如果浏览器可以提供 xhr,则创建传输对象
-if ( jQuery.support.ajax ) {
+    if ( jQuery.support.ajax ) {
 
-    jQuery.ajaxTransport(function( s ) {
-        // Cross domain only allowed if supported through XMLHttpRequest
-        // 仅当通过 XMLHttpRequest 支持跨域时允许跨域请求
-        if (!s.crossDomain || jQuery.support.cors ) {
+        jQuery.ajaxTransport(function( s ) {
+            // Cross domain only allowed if supported through XMLHttpRequest
+            if ( !s.crossDomain || jQuery.support.cors ) {
 
-            var callback;
+                var callback;
 
-            return {
-                send: function( headers, complete ) {
-
-                    // Get a new xhr
-                    // 获取一个新的 xhr 对象
-                    var xhr = s.xhr(),
-                        handle,
-                        i;
-
-                    // Open the socket
-                    // 打开请求连接
-                    // Passing null username, generates a login popup on Opera (#2865)
-                    // 在 Opera 中传递空用户名会生成登录弹窗(#2865)
-                    if ( s.username ) {
-                        xhr.open( s.type, s.url, s.async, s.username, s.password );
-                    } else {
-                        xhr.open( s.type, s.url, s.async );
-                    }
+                return {
+                    send: function( headers, complete ) {
 
-                    // Apply custom fields if provided
-                    // 如果提供了自定义字段,则应用它们
-                    if ( s.xhrFields ) {
-                        for ( i in s.xhrFields ) {
-                            xhr[ i ] = s.xhrFields[ i ];
+                        // Get a new xhr
+                        var xhr = s.xhr(),
+                            handle,
+                            i;
+
+                        // Open the socket
+                        // Passing null username, generates a login popup on Opera (#2865)
+                        if ( s.username ) {
+                            xhr.open( s.type, s.url, s.async, s.username, s.password );
+                        } else {
+                            xhr.open( s.type, s.url, s.async );
                         }
-                    }
 
-                    // Override mime type if needed
-                    // 如果需要,覆盖 MIME 类型
-                    if ( s.mimeType && xhr.overrideMimeType ) {
-                        xhr.overrideMimeType( s.mimeType );
-                    }
+                        // Apply custom fields if provided
+                        if ( s.xhrFields ) {
+                            for ( i in s.xhrFields ) {
+                                xhr[ i ] = s.xhrFields[ i ];
+                            }
+                        }
 
-                    // X-Requested-With header
-                    // 对于跨域请求,由于预检条件比较复杂,所以不设置该请求头
-                    // 对于同域请求,如果未提供该请求头,则设置
-                    // (也可以在每次请求时设置或使用 ajaxSetup 设置)
-                    // For cross-domain requests, seeing as conditions for a preflight are
-                    // akin to a jigsaw puzzle, we simply never set it to be sure.
-                    // (it can always be set on a per-request basis or even using ajaxSetup)
-                    // For same-domain requests, won't change header if already provided.
-                    if (!s.crossDomain &&!headers["X-Requested-With"] ) {
-                        headers[ "X-Requested-With" ] = "XMLHttpRequest";
-                    }
+                        // Override mime type if needed
+                        if ( s.mimeType && xhr.overrideMimeType ) {
+                            xhr.overrideMimeType( s.mimeType );
+                        }
 
-                    // Need an extra try/catch for cross domain requests in Firefox 3
-                    // Firefox 3 中的跨域请求需要额外的 try/catch 处理
-                    try {
-                        for ( i in headers ) {
-                            xhr.setRequestHeader( i, headers[ i ] );
+                        // X-Requested-With header
+                        // For cross-domain requests, seeing as conditions for a preflight are
+                        // akin to a jigsaw puzzle, we simply never set it to be sure.
+                        // (it can always be set on a per-request basis or even using ajaxSetup)
+                        // For same-domain requests, won't change header if already provided.
+                        if ( !s.crossDomain && !headers["X-Requested-With"] ) {
+                            headers[ "X-Requested-With" ] = "XMLHttpRequest";
                         }
-                    } catch( _ ) {}
-
-                    // Do send the request
-                    // 发送请求
-                    // 这可能会引发异常,实际上 jQuery.ajax 会处理该异常,所以这里没有 try/catch
-                    // This may raise an exception which is actually
-                    // handled in jQuery.ajax (so no try/catch here)
-                    xhr.send( ( s.hasContent && s.data ) || null );
-
-                    // Listener
-                    // 监听器
-                    callback = function( _, isAbort ) {
-
-                        var status,
-                            statusText,
-                            responseHeaders,
-                            responses,
-                            xml;
-
-                        // Firefox throws exceptions when accessing properties
-                        // of an xhr when a network error occured
-                        // Firefox 在发生网络错误时访问 xhr 属性会抛出异常
-                        // http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)
+
+                        // Need an extra try/catch for cross domain requests in Firefox 3
                         try {
+                            for ( i in headers ) {
+                                xhr.setRequestHeader( i, headers[ i ] );
+                            }
+                        } catch( _ ) {}
 
-                            // Was never called and is aborted or complete
-                            // 如果未调用过且已中止或完成
-                            if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
+                        // Do send the request
+                        // This may raise an exception which is actually
+                        // handled in jQuery.ajax (so no try/catch here)
+                        xhr.send( ( s.hasContent && s.data ) || null );
 
-                                // Only called once
-                                // 只调用一次
-                                callback = undefined;
+                        // Listener
+                        callback = function( _, isAbort ) {
 
-                                // Do not keep as active anymore
-                                // 不再保持活动状态
-                                if ( handle ) {
-                                    xhr.onreadystatechange = jQuery.noop;
-                                    if ( xhrOnUnloadAbort ) {
-                                        delete xhrCallbacks[ handle ];
-                                    }
-                                }
+                            var status,
+                                statusText,
+                                responseHeaders,
+                                responses,
+                                xml;
 
-                                // If it's an abort
-                                // 如果是中止操作
-                                if ( isAbort ) {
-                                    // Abort it manually if needed
-                                    // 如果需要,手动中止
-                                    if ( xhr.readyState!== 4 ) {
-                                        xhr.abort();
-                                    }
-                                } else {
-                                    status = xhr.status;
-                                    responseHeaders = xhr.getAllResponseHeaders();
-                                    responses = {};
-                                    xml = xhr.responseXML;
-
-                                    // Construct response list
-                                    // 构建响应列表
-                                    if ( xml && xml.documentElement /* #4958 */ ) {
-                                        responses.xml = xml;
-                                    }
+                            // Firefox throws exceptions when accessing properties
+                            // of an xhr when a network error occured
+                            // http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)
+                            try {
 
-                                    // When requesting binary data, IE6-9 will throw an exception
-                                    // on any attempt to access responseText (#11426)
-                                    // 在请求二进制数据时,IE6-9 访问 responseText 会抛出异常(#11426)
-                                    try {
-                                        responses.text = xhr.responseText;
-                                    } catch( _ ) {
-                                    }
+                                // Was never called and is aborted or complete
+                                if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
+
+                                    // Only called once
+                                    callback = undefined;
 
-                                    // Firefox throws an exception when accessing
-                                    // statusText for faulty cross-domain requests
-                                    // Firefox 在访问有问题的跨域请求的 statusText 时会抛出异常
-                                    try {
-                                        statusText = xhr.statusText;
-                                    } catch( e ) {
-                                        // We normalize with Webkit giving an empty statusText
-                                        // 使用 Webkit 规范,将 statusText 设为空
-                                        statusText = "";
+                                    // Do not keep as active anymore
+                                    if ( handle ) {
+                                        xhr.onreadystatechange = jQuery.noop;
+                                        if ( xhrOnUnloadAbort ) {
+                                            delete xhrCallbacks[ handle ];
+                                        }
                                     }
 
-                                    // Filter status for non standard behaviors
-                                    // 过滤非标准行为的状态
-
-                                    // If the request is local and we have data: assume a success
-                                    // (success with no data won't get notified, that's the best we
-                                    // can do given current implementations)
-                                    // 如果请求是本地的且有数据:假设为成功
-                                    // (无数据的成功不会被通知,根据当前实现这是我们能做的最好的处理)
-                                    if (!status && s.isLocal &&!s.crossDomain ) {
-                                        status = responses.text? 200 : 404;
-                                        // IE - #1450: sometimes returns 1223 when it should be 204
-                                    } else if ( status === 1223 ) {
-                                        status = 204;
+                                    // If it's an abort
+                                    if ( isAbort ) {
+                                        // Abort it manually if needed
+                                        if ( xhr.readyState !== 4 ) {
+                                            xhr.abort();
+                                        }
+                                    } else {
+                                        status = xhr.status;
+                                        responseHeaders = xhr.getAllResponseHeaders();
+                                        responses = {};
+                                        xml = xhr.responseXML;
+
+                                        // Construct response list
+                                        if ( xml && xml.documentElement /* #4958 */ ) {
+                                            responses.xml = xml;
+                                        }
+
+                                        // When requesting binary data, IE6-9 will throw an exception
+                                        // on any attempt to access responseText (#11426)
+                                        try {
+                                            responses.text = xhr.responseText;
+                                        } catch( _ ) {
+                                        }
+
+                                        // Firefox throws an exception when accessing
+                                        // statusText for faulty cross-domain requests
+                                        try {
+                                            statusText = xhr.statusText;
+                                        } catch( e ) {
+                                            // We normalize with Webkit giving an empty statusText
+                                            statusText = "";
+                                        }
+
+                                        // Filter status for non standard behaviors
+
+                                        // If the request is local and we have data: assume a success
+                                        // (success with no data won't get notified, that's the best we
+                                        // can do given current implementations)
+                                        if ( !status && s.isLocal && !s.crossDomain ) {
+                                            status = responses.text ? 200 : 404;
+                                            // IE - #1450: sometimes returns 1223 when it should be 204
+                                        } else if ( status === 1223 ) {
+                                            status = 204;
+                                        }
                                     }
                                 }
+                            } catch( firefoxAccessException ) {
+                                if ( !isAbort ) {
+                                    complete( -1, firefoxAccessException );
+                                }
                             }
-                        } catch( firefoxAccessException ) {
-                            if (!isAbort ) {
-                                // 调用 complete 并传递错误信息
-                                complete( -1, firefoxAccessException );
+
+                            // Call complete if needed
+                            if ( responses ) {
+                                complete( status, statusText, responses, responseHeaders );
                             }
+                        };
+
+                        // if we're in sync mode or it's in cache
+                        // and has been retrieved directly (IE6 & IE7)
+                        // we need to manually fire the callback
+                        if ( !s.async || xhr.readyState === 4 ) {
+                            callback();
+                        } else {
+                            handle = ++xhrId;
+                            if ( xhrOnUnloadAbort ) {
+                                // Create the active xhrs callbacks list if needed
+                                // and attach the unload handler
+                                if ( !xhrCallbacks ) {
+                                    xhrCallbacks = {};
+                                    jQuery( window ).unload( xhrOnUnloadAbort );
+                                }
+                                // Add to list of active xhrs callbacks
+                                xhrCallbacks[ handle ] = callback;
+                            }
+                            xhr.onreadystatechange = callback;
                         }
+                    },
 
-                        // Call complete if needed
-                        // 如果需要,调用 complete 函数
-                        if ( responses ) {
-                            complete( status, statusText, responses, responseHeaders );
+                    abort: function() {
+                        if ( callback ) {
+                            callback(0,1);
                         }
-                    };
+                    }
+                };
+            }
+        });
+    }
+
+
+
+
+    var elemdisplay = {},
+        iframe, iframeDoc,
+        rfxtypes = /^(?:toggle|show|hide)$/,
+        rfxnum = /^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,
+        timerId,
+        fxAttrs = [
+            // height animations
+            [ "height", "marginTop", "marginBottom", "paddingTop", "paddingBottom" ],
+            // width animations
+            [ "width", "marginLeft", "marginRight", "paddingLeft", "paddingRight" ],
+            // opacity animations
+            [ "opacity" ]
+        ],
+        fxNow;
+
+    jQuery.fn.extend({
+        show: function( speed, easing, callback ) {
+            var elem, display;
+
+            if ( speed || speed === 0 ) {
+                return this.animate( genFx("show", 3), speed, easing, callback );
+
+            } else {
+                for ( var i = 0, j = this.length; i < j; i++ ) {
+                    elem = this[ i ];
+
+                    if ( elem.style ) {
+                        display = elem.style.display;
+
+                        // Reset the inline display of this element to learn if it is
+                        // being hidden by cascaded rules or not
+                        if ( !jQuery._data(elem, "olddisplay") && display === "none" ) {
+                            display = elem.style.display = "";
+                        }
+
+                        // Set elements which have been overridden with display: none
+                        // in a stylesheet to whatever the default browser style is
+                        // for such an element
+                        if ( (display === "" && jQuery.css(elem, "display") === "none") ||
+                            !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) {
+                            jQuery._data( elem, "olddisplay", defaultDisplay(elem.nodeName) );
+                        }
+                    }
+                }
+
+                // Set the display of most of the elements in a second loop
+                // to avoid the constant reflow
+                for ( i = 0; i < j; i++ ) {
+                    elem = this[ i ];
+
+                    if ( elem.style ) {
+                        display = elem.style.display;
+
+                        if ( display === "" || display === "none" ) {
+                            elem.style.display = jQuery._data( elem, "olddisplay" ) || "";
+                        }
+                    }
+                }
+
+                return this;
+            }
+        },
+
+        hide: function( speed, easing, callback ) {
+            if ( speed || speed === 0 ) {
+                return this.animate( genFx("hide", 3), speed, easing, callback);
+
+            } else {
+                var elem, display,
+                    i = 0,
+                    j = this.length;
+
+                for ( ; i < j; i++ ) {
+                    elem = this[i];
+                    if ( elem.style ) {
+                        display = jQuery.css( elem, "display" );
+
+                        if ( display !== "none" && !jQuery._data( elem, "olddisplay" ) ) {
+                            jQuery._data( elem, "olddisplay", display );
+                        }
+                    }
+                }
+
+                // Set the display of the elements in a second loop
+                // to avoid the constant reflow
+                for ( i = 0; i < j; i++ ) {
+                    if ( this[i].style ) {
+                        this[i].style.display = "none";
+                    }
+                }
+
+                return this;
+            }
+        },
+
+        // Save the old toggle function
+        _toggle: jQuery.fn.toggle,
+
+        toggle: function( fn, fn2, callback ) {
+            var bool = typeof fn === "boolean";
+
+            if ( jQuery.isFunction(fn) && jQuery.isFunction(fn2) ) {
+                this._toggle.apply( this, arguments );
+
+            } else if ( fn == null || bool ) {
+                this.each(function() {
+                    var state = bool ? fn : jQuery(this).is(":hidden");
+                    jQuery(this)[ state ? "show" : "hide" ]();
+                });
+
+            } else {
+                this.animate(genFx("toggle", 3), fn, fn2, callback);
+            }
+
+            return this;
+        },
+
+        fadeTo: function( speed, to, easing, callback ) {
+            return this.filter(":hidden").css("opacity", 0).show().end()
+                .animate({opacity: to}, speed, easing, callback);
+        },
+
+        animate: function( prop, speed, easing, callback ) {
+            var optall = jQuery.speed( speed, easing, callback );
+
+            if ( jQuery.isEmptyObject( prop ) ) {
+                return this.each( optall.complete, [ false ] );
+            }
 
-                    // if we're in sync mode or it's in cache
-                    // and has been retrieved directly (IE6 & IE7)
-                    // we need to manually fire the callback
-                    // 如果是同步模式或在缓存中且直接获取(IE6 和 IE7),需要手动触发回调
-                    if (!s.async || xhr.readyState === 4 ) {
-                        callback();
+            // Do not change referenced properties as per-property easing will be lost
+            prop = jQuery.extend( {}, prop );
+
+            function doAnimation() {
+                // XXX 'this' does not always have a nodeName when running the
+                // test suite
+
+                if ( optall.queue === false ) {
+                    jQuery._mark( this );
+                }
+
+                var opt = jQuery.extend( {}, optall ),
+                    isElement = this.nodeType === 1,
+                    hidden = isElement && jQuery(this).is(":hidden"),
+                    name, val, p, e, hooks, replace,
+                    parts, start, end, unit,
+                    method;
+
+                // will store per property easing and be used to determine when an animation is complete
+                opt.animatedProperties = {};
+
+                // first pass over propertys to expand / normalize
+                for ( p in prop ) {
+                    name = jQuery.camelCase( p );
+                    if ( p !== name ) {
+                        prop[ name ] = prop[ p ];
+                        delete prop[ p ];
+                    }
+
+                    if ( ( hooks = jQuery.cssHooks[ name ] ) && "expand" in hooks ) {
+                        replace = hooks.expand( prop[ name ] );
+                        delete prop[ name ];
+
+                        // not quite $.extend, this wont overwrite keys already present.
+                        // also - reusing 'p' from above because we have the correct "name"
+                        for ( p in replace ) {
+                            if ( ! ( p in prop ) ) {
+                                prop[ p ] = replace[ p ];
+                            }
+                        }
+                    }
+                }
+
+                for ( name in prop ) {
+                    val = prop[ name ];
+                    // easing resolution: per property > opt.specialEasing > opt.easing > 'swing' (default)
+                    if ( jQuery.isArray( val ) ) {
+                        opt.animatedProperties[ name ] = val[ 1 ];
+                        val = prop[ name ] = val[ 0 ];
                     } else {
-                        handle = ++xhrId;
-                        if ( xhrOnUnloadAbort ) {
-                            // Create the active xhrs callbacks list if needed
-                            // 如有需要,创建活动的 xhrs 回调列表
-                            // and attach the unload handler
-                            // 并添加卸载处理程序
-                            if (!xhrCallbacks ) {
-                                xhrCallbacks = {};
-                                jQuery( window ).unload( xhrOnUnloadAbort );
+                        opt.animatedProperties[ name ] = opt.specialEasing && opt.specialEasing[ name ] || opt.easing || 'swing';
+                    }
+
+                    if ( val === "hide" && hidden || val === "show" && !hidden ) {
+                        return opt.complete.call( this );
+                    }
+
+                    if ( isElement && ( name === "height" || name === "width" ) ) {
+                        // Make sure that nothing sneaks out
+                        // Record all 3 overflow attributes because IE does not
+                        // change the overflow attribute when overflowX and
+                        // overflowY are set to the same value
+                        opt.overflow = [ this.style.overflow, this.style.overflowX, this.style.overflowY ];
+
+                        // Set display property to inline-block for height/width
+                        // animations on inline elements that are having width/height animated
+                        if ( jQuery.css( this, "display" ) === "inline" &&
+                            jQuery.css( this, "float" ) === "none" ) {
+
+                            // inline-level elements accept inline-block;
+                            // block-level elements need to be inline with layout
+                            if ( !jQuery.support.inlineBlockNeedsLayout || defaultDisplay( this.nodeName ) === "inline" ) {
+                                this.style.display = "inline-block";
+
+                            } else {
+                                this.style.zoom = 1;
                             }
-                            // Add to list of active xhrs callbacks
-                            // 将回调添加到活动的 xhrs 回调列表
-                            xhrCallbacks[ handle ] = callback;
                         }
-                        xhr.onreadystatechange = callback;
                     }
-                },
+                }
 
-                abort: function() {
-                    if ( callback ) {
-                        // 调用回调函数进行中止操作
-                        callback(0,1);
+                if ( opt.overflow != null ) {
+                    this.style.overflow = "hidden";
+                }
+
+                for ( p in prop ) {
+                    e = new jQuery.fx( this, opt, p );
+                    val = prop[ p ];
+
+                    if ( rfxtypes.test( val ) ) {
+
+                        // Tracks whether to show or hide based on private
+                        // data attached to the element
+                        method = jQuery._data( this, "toggle" + p ) || ( val === "toggle" ? hidden ? "show" : "hide" : 0 );
+                        if ( method ) {
+                            jQuery._data( this, "toggle" + p, method === "show" ? "hide" : "show" );
+                            e[ method ]();
+                        } else {
+                            e[ val ]();
+                        }
+
+                    } else {
+                        parts = rfxnum.exec( val );
+                        start = e.cur();
+
+                        if ( parts ) {
+                            end = parseFloat( parts[2] );
+                            unit = parts[3] || ( jQuery.cssNumber[ p ] ? "" : "px" );
+
+                            // We need to compute starting value
+                            if ( unit !== "px" ) {
+                                jQuery.style( this, p, (end || 1) + unit);
+                                start = ( (end || 1) / e.cur() ) * start;
+                                jQuery.style( this, p, start + unit);
+                            }
+
+                            // If a +=/-= token was provided, we're doing a relative animation
+                            if ( parts[1] ) {
+                                end = ( (parts[ 1 ] === "-=" ? -1 : 1) * end ) + start;
+                            }
+
+                            e.custom( start, end, unit );
+
+                        } else {
+                            e.custom( start, val, "" );
+                        }
                     }
                 }
+
+                // For JS strict compliance
+                return true;
+            }
+
+            return optall.queue === false ?
+                this.each( doAnimation ) :
+                this.queue( optall.queue, doAnimation );
+        },
+
+        stop: function( type, clearQueue, gotoEnd ) {
+            if ( typeof type !== "string" ) {
+                gotoEnd = clearQueue;
+                clearQueue = type;
+                type = undefined;
+            }
+            if ( clearQueue && type !== false ) {
+                this.queue( type || "fx", [] );
+            }
+
+            return this.each(function() {
+                var index,
+                    hadTimers = false,
+                    timers = jQuery.timers,
+                    data = jQuery._data( this );
+
+                // clear marker counters if we know they won't be
+                if ( !gotoEnd ) {
+                    jQuery._unmark( true, this );
+                }
+
+                function stopQueue( elem, data, index ) {
+                    var hooks = data[ index ];
+                    jQuery.removeData( elem, index, true );
+                    hooks.stop( gotoEnd );
+                }
+
+                if ( type == null ) {
+                    for ( index in data ) {
+                        if ( data[ index ] && data[ index ].stop && index.indexOf(".run") === index.length - 4 ) {
+                            stopQueue( this, data, index );
+                        }
+                    }
+                } else if ( data[ index = type + ".run" ] && data[ index ].stop ){
+                    stopQueue( this, data, index );
+                }
+
+                for ( index = timers.length; index--; ) {
+                    if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
+                        if ( gotoEnd ) {
+
+                            // force the next step to be the last
+                            timers[ index ]( true );
+                        } else {
+                            timers[ index ].saveState();
+                        }
+                        hadTimers = true;
+                        timers.splice( index, 1 );
+                    }
+                }
+
+                // start the next in the queue if the last step wasn't forced
+                // timers currently will call their complete callbacks, which will dequeue
+                // but only if they were gotoEnd
+                if ( !( gotoEnd && hadTimers ) ) {
+                    jQuery.dequeue( this, type );
+                }
+            });
+        }
+
+    });
+
+// Animations created synchronously will run synchronously
+    function createFxNow() {
+        setTimeout( clearFxNow, 0 );
+        return ( fxNow = jQuery.now() );
+    }
+
+    function clearFxNow() {
+        fxNow = undefined;
+    }
+
+// Generate parameters to create a standard animation
+    function genFx( type, num ) {
+        var obj = {};
+
+        jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice( 0, num )), function() {
+            obj[ this ] = type;
+        });
+
+        return obj;
+    }
+
+// Generate shortcuts for custom animations
+    jQuery.each({
+        slideDown: genFx( "show", 1 ),
+        slideUp: genFx( "hide", 1 ),
+        slideToggle: genFx( "toggle", 1 ),
+        fadeIn: { opacity: "show" },
+        fadeOut: { opacity: "hide" },
+        fadeToggle: { opacity: "toggle" }
+    }, function( name, props ) {
+        jQuery.fn[ name ] = function( speed, easing, callback ) {
+            return this.animate( props, speed, easing, callback );
+        };
+    });
+
+    jQuery.extend({
+        speed: function( speed, easing, fn ) {
+            var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
+                complete: fn || !fn && easing ||
+                    jQuery.isFunction( speed ) && speed,
+                duration: speed,
+                easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
             };
+
+            opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
+                opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
+
+            // normalize opt.queue - true/undefined/null -> "fx"
+            if ( opt.queue == null || opt.queue === true ) {
+                opt.queue = "fx";
+            }
+
+            // Queueing
+            opt.old = opt.complete;
+
+            opt.complete = function( noUnmark ) {
+                if ( jQuery.isFunction( opt.old ) ) {
+                    opt.old.call( this );
+                }
+
+                if ( opt.queue ) {
+                    jQuery.dequeue( this, opt.queue );
+                } else if ( noUnmark !== false ) {
+                    jQuery._unmark( this );
+                }
+            };
+
+            return opt;
+        },
+
+        easing: {
+            linear: function( p ) {
+                return p;
+            },
+            swing: function( p ) {
+                return ( -Math.cos( p*Math.PI ) / 2 ) + 0.5;
+            }
+        },
+
+        timers: [],
+
+        fx: function( elem, options, prop ) {
+            this.options = options;
+            this.elem = elem;
+            this.prop = prop;
+
+            options.orig = options.orig || {};
         }
+
     });
-}
 
+    jQuery.fx.prototype = {
+        // Simple function for setting a style value
+        update: function() {
+            if ( this.options.step ) {
+                this.options.step.call( this.elem, this.now, this );
+            }
+
+            ( jQuery.fx.step[ this.prop ] || jQuery.fx.step._default )( this );
+        },
+
+        // Get the current size
+        cur: function() {
+            if ( this.elem[ this.prop ] != null && (!this.elem.style || this.elem.style[ this.prop ] == null) ) {
+                return this.elem[ this.prop ];
+            }
+
+            var parsed,
+                r = jQuery.css( this.elem, this.prop );
+            // Empty strings, null, undefined and "auto" are converted to 0,
+            // complex values such as "rotate(1rad)" are returned as is,
+            // simple values such as "10px" are parsed to Float.
+            return isNaN( parsed = parseFloat( r ) ) ? !r || r === "auto" ? 0 : r : parsed;
+        },
 
+        // Start an animation from one number to another
+        custom: function( from, to, unit ) {
+            var self = this,
+                fx = jQuery.fx;
 
+            this.startTime = fxNow || createFxNow();
+            this.end = to;
+            this.now = this.start = from;
+            this.pos = this.state = 0;
+            this.unit = unit || this.unit || ( jQuery.cssNumber[ this.prop ] ? "" : "px" );
 
-// 以下代码主要涉及 jQuery 的 AJAX 请求处理,根据不同的浏览器环境和请求情况进行相应的设置和操作
+            function t( gotoEnd ) {
+                return self.step( gotoEnd );
+            }
 
-// 根据是否为 IE 浏览器定义 xhrOnUnloadAbort 函数,如果是 IE 浏览器,该函数会遍历 xhrCallbacks 对象,调用其中存储的回调函数并传入中止参数,否则为 false
-var // #5280: Internet Explorer will keep connections alive if we don't abort on unload
-    xhrOnUnloadAbort = window.ActiveXObject? function() {
-        // 开始遍历 xhrCallbacks 对象
-        for ( var key in xhrCallbacks ) {
-            // 调用存储在 xhrCallbacks 中的回调函数,并传入中止信号 (0, 1),表示中止请求
-            xhrCallbacks[ key ]( 0, 1 );
-        }
-    } : false,
-    // 初始化 xhrId 为 0,用于为请求生成唯一标识
-    xhrId = 0,
-    // 用于存储 xhr 请求的回调函数的对象
-    xhrCallbacks;
+            t.queue = this.options.queue;
+            t.elem = this.elem;
+            t.saveState = function() {
+                if ( jQuery._data( self.elem, "fxshow" + self.prop ) === undefined ) {
+                    if ( self.options.hide ) {
+                        jQuery._data( self.elem, "fxshow" + self.prop, self.start );
+                    } else if ( self.options.show ) {
+                        jQuery._data( self.elem, "fxshow" + self.prop, self.end );
+                    }
+                }
+            };
 
+            if ( t() && jQuery.timers.push(t) && !timerId ) {
+                timerId = setInterval( fx.tick, fx.interval );
+            }
+        },
 
-// 定义 createStandardXHR 函数,尝试创建标准的 XMLHttpRequest 对象
-function createStandardXHR() {
-    try {
-        // 创建一个新的 XMLHttpRequest 对象
-        return new window.XMLHttpRequest();
-    } catch( e ) {
-        // 如果创建失败,不执行任何操作
-    }
-}
+        // Simple 'show' function
+        show: function() {
+            var dataShow = jQuery._data( this.elem, "fxshow" + this.prop );
 
+            // Remember where we started, so that we can go back to it later
+            this.options.orig[ this.prop ] = dataShow || jQuery.style( this.elem, this.prop );
+            this.options.show = true;
 
-// 定义 createActiveXHR 函数,尝试创建 ActiveXObject 类型的 XMLHttpRequest 对象,主要用于兼容旧版 IE 浏览器
-function createActiveXHR() {
-    try {
-        // 创建一个 Microsoft.XMLHTTP 类型的 ActiveXObject 对象,作为 XMLHttpRequest 对象的替代
-        return new window.ActiveXObject( "Microsoft.XMLHTTP" );
-    } catch( e ) {
-        // 如果创建失败,不执行任何操作
-    }
-}
-
-
-// 创建请求对象,根据浏览器是否支持 ActiveXObject 进行不同的创建方式,这里是为了向后兼容 jQuery 的 ajaxSettings
-jQuery.ajaxSettings.xhr = window.ActiveXObject?
-    /* Microsoft 在 IE7 中未能正确实现 XMLHttpRequest(无法请求本地文件),所以当 ActiveXObject 可用时使用它
-     * 另外,在 IE7/IE8 中 XMLHttpRequest 可能被禁用,所以需要一个后备方案
-     */
-    function() {
-        // 对于 IE 浏览器,如果不是本地请求,则尝试创建标准的 XMLHttpRequest 对象,若失败则创建 ActiveXObject 类型的 XMLHttpRequest 对象
-        return!this.isLocal && createStandardXHR() || createActiveXHR();
-    } :
-    // 对于其他浏览器,直接使用标准的 XMLHttpRequest 对象
-    createStandardXHR;
-
-
-// 确定浏览器的支持属性,通过立即执行函数,传入 jQuery.ajaxSettings.xhr() 的结果作为参数
-(function( xhr ) {
-    // 扩展 jQuery.support 对象,添加 ajax 和 cors 属性,以检查浏览器对 ajax 和跨域请求的支持情况
-    jQuery.extend( jQuery.support, {
-        // 检查是否支持 ajax,将 xhr 对象转换为布尔值
-        ajax:!!xhr,
-        // 检查是否支持 CORS,需要 xhr 存在且具有 withCredentials 属性
-        cors:!!xhr && ( "withCredentials" in xhr )
-    });
-})( jQuery.ajaxSettings.xhr() );
+            // Begin the animation
+            // Make sure that we start at a small width/height to avoid any flash of content
+            if ( dataShow !== undefined ) {
+                // This show is picking up where a previous hide or show left off
+                this.custom( this.cur(), dataShow );
+            } else {
+                this.custom( this.prop === "width" || this.prop === "height" ? 1 : 0, this.cur() );
+            }
 
+            // Start by showing the element
+            jQuery( this.elem ).show();
+        },
 
-// 如果浏览器支持 ajax,创建传输对象
-if ( jQuery.support.ajax ) {
-    // 为 jQuery 注册一个 ajax 传输对象
-    jQuery.ajaxTransport(function( s ) {
-        // 仅当请求不是跨域或支持跨域请求(通过 XMLHttpRequest)时才继续
-        if (!s.crossDomain || jQuery.support.cors ) {
-            // 存储回调函数的变量
-            var callback;
+        // Simple 'hide' function
+        hide: function() {
+            // Remember where we started, so that we can go back to it later
+            this.options.orig[ this.prop ] = jQuery._data( this.elem, "fxshow" + this.prop ) || jQuery.style( this.elem, this.prop );
+            this.options.hide = true;
 
-            return {
-                send: function( headers, complete ) {
-                    // 获取一个新的 xhr 对象
-                    var xhr = s.xhr(),
-                        // 用于存储请求的处理句柄
-                        handle,
-                        // 用于遍历的变量
-                        i;
-
-
-                    // 打开 xhr 请求
-                    // 如果提供了用户名,使用用户名和密码打开请求,否则只使用 url 和异步标志打开请求
-                    // 在 Opera 中传递空用户名会生成登录弹窗(#2865)
-                    if ( s.username ) {
-                        xhr.open( s.type, s.url, s.async, s.username, s.password );
-                    } else {
-                        xhr.open( s.type, s.url, s.async );
-                    }
+            // Begin the animation
+            this.custom( this.cur(), 0 );
+        },
 
+        // Each step of an animation
+        step: function( gotoEnd ) {
+            var p, n, complete,
+                t = fxNow || createFxNow(),
+                done = true,
+                elem = this.elem,
+                options = this.options;
 
-                    // 如果存在自定义的 xhr 字段,将它们应用到 xhr 对象上
-                    if ( s.xhrFields ) {
-                        for ( i in s.xhrFields ) {
-                            xhr[ i ] = s.xhrFields[ i ];
-                        }
-                    }
+            if ( gotoEnd || t >= options.duration + this.startTime ) {
+                this.now = this.end;
+                this.pos = this.state = 1;
+                this.update();
 
+                options.animatedProperties[ this.prop ] = true;
 
-                    // 如果需要,使用 xhr.overrideMimeType 方法覆盖 MIME 类型
-                    if ( s.mimeType && xhr.overrideMimeType ) {
-                        xhr.overrideMimeType( s.mimeType );
+                for ( p in options.animatedProperties ) {
+                    if ( options.animatedProperties[ p ] !== true ) {
+                        done = false;
                     }
+                }
 
+                if ( done ) {
+                    // Reset the overflow
+                    if ( options.overflow != null && !jQuery.support.shrinkWrapBlocks ) {
 
-                    // X-Requested-With 头处理
-                    // 对于跨域请求,由于预检条件复杂,不设置该请求头,对于同域请求,如果该请求头未提供,则设置为 XMLHttpRequest
-                    // 也可以在每次请求时设置或使用 ajaxSetup 设置
-                    if (!s.crossDomain &&!headers["X-Requested-With"] ) {
-                        headers[ "X-Requested-With" ] = "XMLHttpRequest";
+                        jQuery.each( [ "", "X", "Y" ], function( index, value ) {
+                            elem.style[ "overflow" + value ] = options.overflow[ index ];
+                        });
                     }
 
+                    // Hide the element if the "hide" operation was done
+                    if ( options.hide ) {
+                        jQuery( elem ).hide();
+                    }
 
-                    // Firefox 3 中的跨域请求需要额外的 try/catch 处理
-                    try {
-                        // 遍历 headers 并设置请求头
-                        for ( i in headers ) {
-                            xhr.setRequestHeader( i, headers[ i ] );
+                    // Reset the properties, if the item has been hidden or shown
+                    if ( options.hide || options.show ) {
+                        for ( p in options.animatedProperties ) {
+                            jQuery.style( elem, p, options.orig[ p ] );
+                            jQuery.removeData( elem, "fxshow" + p, true );
+                            // Toggle data is no longer needed
+                            jQuery.removeData( elem, "toggle" + p, true );
                         }
-                    } catch( _ ) {
-                        // 异常时不做特殊处理
                     }
 
+                    // Execute the complete function
+                    // in the event that the complete function throws an exception
+                    // we must ensure it won't be called twice. #5684
 
-                    // 发送请求,根据是否有内容和数据决定发送的数据,没有数据时发送 null
-                    xhr.send( ( s.hasContent && s.data ) || null );
-
+                    complete = options.complete;
+                    if ( complete ) {
 
-                    // 定义请求的回调函数
-                    callback = function( _, isAbort ) {
-                        var status,
-                            statusText,
-                            responseHeaders,
-                            responses,
-                            xml;
+                        options.complete = false;
+                        complete.call( elem );
+                    }
+                }
 
+                return false;
 
-                        // Firefox 在发生网络错误时访问 xhr 属性会抛出异常,参考 http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)
-                        try {
-                            // 如果回调函数存在且请求已中止或完成(readyState 为 4)
-                            if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
-                                // 确保回调函数只被调用一次
-                                callback = undefined;
+            } else {
+                // classical easing cannot be used with an Infinity duration
+                if ( options.duration == Infinity ) {
+                    this.now = t;
+                } else {
+                    n = t - this.startTime;
+                    this.state = n / options.duration;
 
+                    // Perform the easing function, defaults to swing
+                    this.pos = jQuery.easing[ options.animatedProperties[this.prop] ]( this.state, n, 0, 1, options.duration );
+                    this.now = this.start + ( (this.end - this.start) * this.pos );
+                }
+                // Perform the next step of the animation
+                this.update();
+            }
 
-                                // 如果存在句柄,移除 onreadystatechange 事件监听器,并在需要时从 xhrCallbacks 中删除该句柄
-                                if ( handle ) {
-                                    xhr.onreadystatechange = jQuery.noop;
-                                    if ( xhrOnUnloadAbort ) {
-                                        delete xhrCallbacks[ handle ];
-                                    }
-                                }
+            return true;
+        }
+    };
 
+    jQuery.extend( jQuery.fx, {
+        tick: function() {
+            var timer,
+                timers = jQuery.timers,
+                i = 0;
 
-                                // 如果是中止操作
-                                if ( isAbort ) {
-                                    // 如果请求尚未完成(readyState 不为 4),手动中止请求
-                                    if ( xhr.readyState!== 4 ) {
-                                        xhr.abort();
-                                    }
-                                } else {
-                                    // 获取请求的状态码
-                                    status = xhr.status;
-                                    // 获取响应的所有头信息
-                                    responseHeaders = xhr.getAllResponseHeaders();
-                                    // 存储响应信息的对象
-                                    responses = {};
-                                    // 获取响应的 XML 数据
-                                    xml = xhr.responseXML;
-
-
-                                    // 如果响应的 XML 数据存在且有 documentElement,将其存储在 responses.xml 中(#4958)
-                                    if ( xml && xml.documentElement ) {
-                                        responses.xml = xml;
-                                    }
+            for ( ; i < timers.length; i++ ) {
+                timer = timers[ i ];
+                // Checks the timer has not already been removed
+                if ( !timer() && timers[ i ] === timer ) {
+                    timers.splice( i--, 1 );
+                }
+            }
 
+            if ( !timers.length ) {
+                jQuery.fx.stop();
+            }
+        },
 
-                                    // 在请求二进制数据时,IE6-9 访问 responseText 会抛出异常(#11426)
-                                    try {
-                                        responses.text = xhr.responseText;
-                                    } catch( _ ) {
-                                    }
+        interval: 13,
 
+        stop: function() {
+            clearInterval( timerId );
+            timerId = null;
+        },
 
-                                    // Firefox 在访问有问题的跨域请求的 statusText 时会抛出异常
-                                    try {
-                                        statusText = xhr.statusText;
-                                    } catch( e ) {
-                                        // 当出现异常时,使用 Webkit 规范将 statusText 设为空
-                                        statusText = "";
-                                    }
+        speeds: {
+            slow: 600,
+            fast: 200,
+            // Default speed
+            _default: 400
+        },
 
+        step: {
+            opacity: function( fx ) {
+                jQuery.style( fx.elem, "opacity", fx.now );
+            },
 
-                                    // 过滤非标准行为的状态
+            _default: function( fx ) {
+                if ( fx.elem.style && fx.elem.style[ fx.prop ] != null ) {
+                    fx.elem.style[ fx.prop ] = fx.now + fx.unit;
+                } else {
+                    fx.elem[ fx.prop ] = fx.now;
+                }
+            }
+        }
+    });
 
+// Ensure props that can't be negative don't go there on undershoot easing
+    jQuery.each( fxAttrs.concat.apply( [], fxAttrs ), function( i, prop ) {
+        // exclude marginTop, marginLeft, marginBottom and marginRight from this list
+        if ( prop.indexOf( "margin" ) ) {
+            jQuery.fx.step[ prop ] = function( fx ) {
+                jQuery.style( fx.elem, prop, Math.max(0, fx.now) + fx.unit );
+            };
+        }
+    });
 
-                                    // 如果请求是本地的且有数据,假设请求成功;无数据的成功不会被通知,这是根据当前实现的最佳处理方式
-                                    if (!status && s.isLocal &&!s.crossDomain ) {
-                                        status = responses.text? 200 : 404;
-                                        // IE - #1450: 有时会返回 1223 而不是 204
-                                    } else if ( status === 1223 ) {
-                                        status = 204;
-                                    }
-                                }
-                            }
-                        } catch( firefoxAccessException ) {
-                            // 如果不是中止操作,调用 complete 函数并传递错误信息
-                            if (!isAbort ) {
-                                complete( -1, firefoxAccessException );
-                            }
-                        }
+    if ( jQuery.expr && jQuery.expr.filters ) {
+        jQuery.expr.filters.animated = function( elem ) {
+            return jQuery.grep(jQuery.timers, function( fn ) {
+                return elem === fn.elem;
+            }).length;
+        };
+    }
 
+// Try to restore the default display value of an element
+    function defaultDisplay( nodeName ) {
 
-                        // 如果有响应信息,调用 complete 函数传递状态、状态文本、响应和响应头信息
-                        if ( responses ) {
-                            complete( status, statusText, responses, responseHeaders );
-                        }
-                    };
+        if ( !elemdisplay[ nodeName ] ) {
 
+            var body = document.body,
+                elem = jQuery( "<" + nodeName + ">" ).appendTo( body ),
+                display = elem.css( "display" );
+            elem.remove();
 
-                    // 如果是同步模式或请求已在缓存中且直接获取(IE6 & IE7),手动触发回调
-                    if (!s.async || xhr.readyState === 4 ) {
-                        callback();
-                    } else {
-                        // 生成新的请求句柄
-                        handle = ++xhrId;
-                        if ( xhrOnUnloadAbort ) {
-                            // 如果 xhrCallbacks 不存在,创建该对象,并为 window 绑定 unload 事件,在卸载时调用 xhrOnUnloadAbort 函数
-                            if (!xhrCallbacks ) {
-                                xhrCallbacks = {};
-                                jQuery( window ).unload( xhrOnUnloadAbort );
-                            }
-                            // 将回调添加到 xhrCallbacks 中
-                            xhrCallbacks[ handle ] = callback;
-                        }
-                        // 为 xhr 对象添加 onreadystatechange 事件监听器
-                        xhr.onreadystatechange = callback;
-                    }
-                },
+            // If the simple way fails,
+            // get element's real default display by attaching it to a temp iframe
+            if ( display === "none" || display === "" ) {
+                // No iframe to use yet, so create it
+                if ( !iframe ) {
+                    iframe = document.createElement( "iframe" );
+                    iframe.frameBorder = iframe.width = iframe.height = 0;
+                }
 
+                body.appendChild( iframe );
 
-                abort: function() {
-                    // 调用回调函数进行中止操作
-                    if ( callback ) {
-                        callback(0,1);
-                    }
+                // Create a cacheable copy of the iframe document on first call.
+                // IE and Opera will allow us to reuse the iframeDoc without re-writing the fake HTML
+                // document to it; WebKit & Firefox won't allow reusing the iframe document.
+                if ( !iframeDoc || !iframe.createElement ) {
+                    iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document;
+                    iframeDoc.write( ( jQuery.support.boxModel ? "<!doctype html>" : "" ) + "<html><body>" );
+                    iframeDoc.close();
                 }
-            };
-        }
-    });
-}
-
-if ( opt.overflow!= null ) {
-    // 如果 opt 的 overflow 属性不为空,将元素的 overflow 样式设置为 hidden
-    this.style.overflow = "hidden";
-}
-
-for ( p in prop ) {
-    // 遍历 prop 对象的属性
-    e = new jQuery.fx( this, opt, p );
-    val = prop[ p ];
-
-    if ( rfxtypes.test( val ) ) {
-        // 检查 val 是否符合某种效果类型的测试
-        // Tracks whether to show or hide based on private
-        // data attached to the element
-        // 根据元素上的私有数据来确定是显示还是隐藏
-        method = jQuery._data( this, "toggle" + p ) || ( val === "toggle"? hidden? "show" : "hide" : 0 );
-        if ( method ) {
-            // 如果 method 存在,将 toggle 属性的数据更新为相反的操作
-            jQuery._data( this, "toggle" + p, method === "show"? "hide" : "show" );
-            // 调用相应的方法(show 或 hide)
-            e[ method ]();
-        } else {
-            // 调用元素的 val 方法
-            e[ val ]();
-        }
-    } else {
-        parts = rfxnum.exec( val );
-        start = e.cur();
 
-        if ( parts ) {
-            // 解析 val 得到结束值
-            end = parseFloat( parts[2] );
-            unit = parts[3] || ( jQuery.cssNumber[ p ]? "" : "px" );
+                elem = iframeDoc.createElement( nodeName );
 
-            // We need to compute starting value
-            // 我们需要计算起始值
-            if ( unit!== "px" ) {
-                // 如果单位不是 px,将元素的样式设置为结束值加单位
-                jQuery.style( this, p, (end || 1) + unit);
-                // 计算起始值
-                start = ( (end || 1) / e.cur() ) * start;
-                // 将元素的样式设置为起始值加单位
-                jQuery.style( this, p, start + unit);
-            }
+                iframeDoc.body.appendChild( elem );
 
-            // If a +=/-= token was provided, we're doing a relative animation
-            // 如果提供了 += 或 -= 符号,进行相对动画
-            if ( parts[1] ) {
-                end = ( (parts[ 1 ] === "-="? -1 : 1) * end ) + start;
+                display = jQuery.css( elem, "display" );
+                body.removeChild( iframe );
             }
 
-            // 执行自定义动画
-            e.custom( start, end, unit );
-        } else {
-            // 执行自定义动画,使用起始值和 val 作为结束值
-            e.custom( start, val, "" );
+            // Store the correct default display
+            elemdisplay[ nodeName ] = display;
         }
-    }
-}
-
-// For JS strict compliance
-// 为了符合 JavaScript 严格模式
-return true;
-}
-
-return optall.queue === false?
-    // 如果队列选项为 false,对每个元素执行 doAnimation 函数
-    this.each( doAnimation ) :
-    // 否则将 doAnimation 函数添加到队列中
-    this.queue( optall.queue, doAnimation );
-},
-
-stop: function( type, clearQueue, gotoEnd ) {
-    if ( typeof type!== "string" ) {
-        // 调整参数,如果 type 不是字符串
-        gotoEnd = clearQueue;
-        clearQueue = type;
-        type = undefined;
-    }
-    if ( clearQueue && type!== false ) {
-        // 如果 clearQueue 为真且 type 不为 false,将相应队列清空
-        this.queue( type || "fx", [] );
+
+        return elemdisplay[ nodeName ];
     }
 
-    return this.each(function() {
-        var index,
-            hadTimers = false,
-            timers = jQuery.timers,
-            data = jQuery._data( this );
 
-        // clear marker counters if we know they won't be
-        // 如果不跳转到结尾,清除标记
-        if (!gotoEnd ) {
-            jQuery._unmark( true, this );
-        }
 
-        function stopQueue( elem, data, index ) {
-            // 从元素中移除相应数据并停止动画
-            jQuery.removeData( elem, index, true );
-            data[ index ].stop( gotoEnd );
-        }
 
-        if ( type == null ) {
-            for ( index in data ) {
-                if ( data[ index ] && data[ index ].stop && index.indexOf(".run") === index.length - 4 ) {
-                    stopQueue( this, data, index );
-                }
-            }
-        } else if ( data[ index = type + ".run" ] && data[ index ].stop ){
-            stopQueue( this, data, index );
-        }
+    var getOffset,
+        rtable = /^t(?:able|d|h)$/i,
+        rroot = /^(?:body|html)$/i;
 
-        for ( index = timers.length; index--; ) {
-            if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
-                if ( gotoEnd ) {
-                    // force the next step to be the last
-                    // 强制下一个步骤为最后一个
-                    timers[ index ]( true );
-                } else {
-                    // 保存状态
-                    timers[ index ].saveState();
-                }
-                hadTimers = true;
-                // 从定时器数组中移除
-                timers.splice( index, 1 );
-            }
-        }
+    if ( "getBoundingClientRect" in document.documentElement ) {
+        getOffset = function( elem, doc, docElem, box ) {
+            try {
+                box = elem.getBoundingClientRect();
+            } catch(e) {}
 
-        // start the next in the queue if the last step wasn't forced
-        // 如果最后一步不是强制的,开始队列中的下一个元素
-        // timers currently will call their complete callbacks, which will dequeue
-        // but only if they were gotoEnd
-        if (!( gotoEnd && hadTimers ) ) {
-            jQuery.dequeue( this, type );
-        }
-    });
-}
+            // Make sure we're not dealing with a disconnected DOM node
+            if ( !box || !jQuery.contains( docElem, elem ) ) {
+                return box ? { top: box.top, left: box.left } : { top: 0, left: 0 };
+            }
 
-});
+            var body = doc.body,
+                win = getWindow( doc ),
+                clientTop  = docElem.clientTop  || body.clientTop  || 0,
+                clientLeft = docElem.clientLeft || body.clientLeft || 0,
+                scrollTop  = win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop  || body.scrollTop,
+                scrollLeft = win.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft,
+                top  = box.top  + scrollTop  - clientTop,
+                left = box.left + scrollLeft - clientLeft;
 
-// Animations created synchronously will run synchronously
-// 同步创建的动画将同步运行
-function createFxNow() {
-    // 设置一个延迟为 0 的定时器,用于清除 fxNow
-    setTimeout( clearFxNow, 0 );
-    return ( fxNow = jQuery.now() );
-}
-
-function clearFxNow() {
-    // 清除 fxNow
-    fxNow = undefined;
-}
+            return { top: top, left: left };
+        };
 
-// Generate parameters to create a standard animation
-// 生成创建标准动画的参数
-function genFx( type, num ) {
-    var obj = {};
+    } else {
+        getOffset = function( elem, doc, docElem ) {
+            var computedStyle,
+                offsetParent = elem.offsetParent,
+                prevOffsetParent = elem,
+                body = doc.body,
+                defaultView = doc.defaultView,
+                prevComputedStyle = defaultView ? defaultView.getComputedStyle( elem, null ) : elem.currentStyle,
+                top = elem.offsetTop,
+                left = elem.offsetLeft;
+
+            while ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) {
+                if ( jQuery.support.fixedPosition && prevComputedStyle.position === "fixed" ) {
+                    break;
+                }
 
-    jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice( 0, num )), function() {
-        // 为生成的对象添加相应属性
-        obj[ this ] = type;
-    });
+                computedStyle = defaultView ? defaultView.getComputedStyle(elem, null) : elem.currentStyle;
+                top  -= elem.scrollTop;
+                left -= elem.scrollLeft;
 
-    return obj;
-}
+                if ( elem === offsetParent ) {
+                    top  += elem.offsetTop;
+                    left += elem.offsetLeft;
 
-// Generate shortcuts for custom animations
-// 为自定义动画生成快捷方式
-jQuery.each({
-    slideDown: genFx( "show", 1 ),
-    slideUp: genFx( "hide", 1 ),
-    slideToggle: genFx( "toggle", 1 ),
-    fadeIn: { opacity: "show" },
-    fadeOut: { opacity: "hide" },
-    fadeToggle: { opacity: "toggle" }
-}, function( name, props ) {
-    jQuery.fn[ name ] = function( speed, easing, callback ) {
-        // 为 jQuery 元素添加相应的动画方法
-        return this.animate( props, speed, easing, callback );
-    };
-});
-
-jQuery.extend({
-    speed: function( speed, easing, fn ) {
-        var opt = speed && typeof speed === "object"? jQuery.extend( {}, speed ) : {
-            // 解析速度选项
-            complete: fn ||!fn && easing ||
-                jQuery.isFunction( speed ) && speed,
-            duration: speed,
-            easing: fn && easing || easing &&!jQuery.isFunction( easing ) && easing
-        };
+                    if ( jQuery.support.doesNotAddBorder && !(jQuery.support.doesAddBorderForTableAndCells && rtable.test(elem.nodeName)) ) {
+                        top  += parseFloat( computedStyle.borderTopWidth  ) || 0;
+                        left += parseFloat( computedStyle.borderLeftWidth ) || 0;
+                    }
 
-        opt.duration = jQuery.fx.off? 0 : typeof opt.duration === "number"? opt.duration :
-            // 获取持续时间
-            opt.duration in jQuery.fx.speeds? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
+                    prevOffsetParent = offsetParent;
+                    offsetParent = elem.offsetParent;
+                }
 
-        // normalize opt.queue - true/undefined/null -> "fx"
-        // 规范化队列选项
-        if ( opt.queue == null || opt.queue === true ) {
-            opt.queue = "fx";
-        }
+                if ( jQuery.support.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible" ) {
+                    top  += parseFloat( computedStyle.borderTopWidth  ) || 0;
+                    left += parseFloat( computedStyle.borderLeftWidth ) || 0;
+                }
 
-        // Queueing
-        // 处理队列
-        opt.old = opt.complete;
+                prevComputedStyle = computedStyle;
+            }
 
-        opt.complete = function( noUnmark ) {
-            if ( jQuery.isFunction( opt.old ) ) {
-                // 调用旧的完成函数
-                opt.old.call( this );
+            if ( prevComputedStyle.position === "relative" || prevComputedStyle.position === "static" ) {
+                top  += body.offsetTop;
+                left += body.offsetLeft;
             }
 
-            if ( opt.queue ) {
-                // 从队列中移除元素
-                jQuery.dequeue( this, opt.queue );
-            } else if ( noUnmark!== false ) {
-                // 取消标记
-                jQuery._unmark( this );
+            if ( jQuery.support.fixedPosition && prevComputedStyle.position === "fixed" ) {
+                top  += Math.max( docElem.scrollTop, body.scrollTop );
+                left += Math.max( docElem.scrollLeft, body.scrollLeft );
             }
-        };
 
-        return opt;
-    },
+            return { top: top, left: left };
+        };
+    }
 
-    easing: {
-        // 线性缓动函数
-        linear: function( p ) {
-            return p;
-        },
-        // 摆动缓动函数
-        swing: function( p ) {
-            return ( -Math.cos( p*Math.PI ) / 2 ) + 0.5;
+    jQuery.fn.offset = function( options ) {
+        if ( arguments.length ) {
+            return options === undefined ?
+                this :
+                this.each(function( i ) {
+                    jQuery.offset.setOffset( this, options, i );
+                });
         }
-    },
-
-    timers: [],
 
-    fx: function( elem, options, prop ) {
-        this.options = options;
-        this.elem = elem;
-        this.prop = prop;
-
-        options.orig = options.orig || {};
-    }
+        var elem = this[0],
+            doc = elem && elem.ownerDocument;
 
-});
+        if ( !doc ) {
+            return null;
+        }
 
-jQuery.fx.prototype = {
-    // Simple function for setting a style value
-    // 用于设置样式值的简单函数
-    update: function() {
-        if ( this.options.step ) {
-            // 调用步骤函数
-            this.options.step.call( this.elem, this.now, this );
+        if ( elem === doc.body ) {
+            return jQuery.offset.bodyOffset( elem );
         }
 
-        // 调用相应的步骤函数或默认步骤函数
-        ( jQuery.fx.step[ this.prop ] || jQuery.fx.step._default )( this );
-    },
+        return getOffset( elem, doc, doc.documentElement );
+    };
 
-    // Get the current size
-    // 获取当前尺寸
-    cur: function() {
-        if ( this.elem[ this.prop ]!= null && (!this.elem.style || this.elem.style[ this.prop ] == null) ) {
-            return this.elem[ this.prop ];
-        }
+    jQuery.offset = {
 
-        var parsed,
-            r = jQuery.css( this.elem, this.prop );
-        // Empty strings, null, undefined and "auto" are converted to 0,
-        // complex values such as "rotate(1rad)" are returned as is,
-        // simple values such as "10px" are parsed to Float.
-        // 空字符串、null、undefined 和 "auto" 转换为 0,复杂值如 "rotate(1rad)" 原样返回,简单值如 "10px" 解析为浮点数
-        return isNaN( parsed = parseFloat( r ) )?!r || r === "auto"? 0 : r : parsed;
-    },
-
-    // Start an animation from one number to another
-    // 从一个数字开始动画到另一个数字
-    custom: function( from, to, unit ) {
-        var self = this,
-            fx = jQuery.fx;
-
-        this.startTime = fxNow || createFxNow();
-        this.end = to;
-        this.now = this.start = from;
-        this.pos = this.state = 0;
-        this.unit = unit || this.unit || ( jQuery.cssNumber[ this.prop ]? "" : "px" );
-
-        function t( gotoEnd ) {
-            return self.step( gotoEnd );
-        }
+        bodyOffset: function( body ) {
+            var top = body.offsetTop,
+                left = body.offsetLeft;
 
-        t.queue = this.options.queue;
-        t.elem = this.elem;
-        t.saveState = function() {
-            if ( jQuery._data( self.elem, "fxshow" + self.prop ) === undefined ) {
-                if ( self.options.hide ) {
-                    jQuery._data( self.elem, "fxshow" + self.prop, self.start );
-                } else if ( self.options.show ) {
-                    jQuery._data( self.elem, "fxshow" + self.prop, self.end );
-                }
+            if ( jQuery.support.doesNotIncludeMarginInBodyOffset ) {
+                top  += parseFloat( jQuery.css(body, "marginTop") ) || 0;
+                left += parseFloat( jQuery.css(body, "marginLeft") ) || 0;
             }
-        };
 
-        if ( t() && jQuery.timers.push(t) &&!timerId ) {
-            timerId = setInterval( fx.tick, fx.interval );
-        }
-    },
-
-    // Simple 'show' function
-    // 简单的显示函数
-    show: function() {
-        var dataShow = jQuery._data( this.elem, "fxshow" + this.prop );
-
-        // Remember where we started, so that we can go back to it later
-        // 记住开始的位置,以便之后返回
-        this.options.orig[ this.prop ] = dataShow || jQuery.style( this.elem, this.prop );
-        this.options.show = true;
-
-        // Begin the animation
-        // 开始动画
-        // Make sure that we start at a small width/height to avoid any flash of content
-        // 确保从较小的宽度/高度开始,以避免内容闪烁
-        if ( dataShow!== undefined ) {
-            // This show is picking up where a previous hide or show left off
-            // 这个显示操作从上一次隐藏或显示的位置继续
-            this.custom( this.cur(), dataShow );
-        } else {
-            this.custom( this.prop === "width" || this.prop === "height"? 1 : 0, this.cur() );
-        }
+            return { top: top, left: left };
+        },
 
-        // Start by showing the element
-        // 首先显示元素
-        jQuery( this.elem ).show();
-    },
-
-    // Simple 'hide' function
-    // 简单的隐藏函数
-    hide: function() {
-        // Remember where we started, so that we can go back to it.
-        // 记住开始的位置,以便之后返回
-        this.options.orig[ this.prop ] = jQuery._data( this.elem, "fxshow" + this.prop ) || jQuery.style( this.elem, this.prop );
-        this.options.hide = true;
-
-        // Begin the animation
-        // 开始动画
-        this.custom( this.cur(), 0 );
-    },
-
-    // Each step of an animation
-    // 动画的每一步
-    step: function( gotoEnd ) {
-        var p, n, complete,
-            t = fxNow || createFxNow(),
-            done = true,
-            elem = this.elem,
-            options = this.options;
-
-        if ( gotoEnd || t >= options.duration + this.startTime ) {
-            this.now = this.end;
-            this.pos = this.state = 1;
-            this.update();
-
-            options.animatedProperties[ this.prop ] = true;
-
-            for ( p in options.animatedProperties ) {
-                if ( options.animatedProperties[ p ]!== true ) {
-                    done = false;
-                }
-            }
-
-            if ( done ) {
-                // Reset the overflow
-                // 重置 overflow
-                if ( options.overflow!= null &&!jQuery.support.shrinkWrapBlocks ) {
-
-                    jQuery.each( [ "", "X", "Y" ], function( index, value ) {
-                        elem.style[ "overflow" + value ] = options.overflow[ index ];
-                    });
-                }
+        setOffset: function( elem, options, i ) {
+            var position = jQuery.css( elem, "position" );
 
-                // Hide the element if the "hide" operation was done
-                // 如果是执行了隐藏操作,隐藏元素
-                if ( options.hide ) {
-                    jQuery( elem ).hide();
-                }
+            // set position first, in-case top/left are set even on static elem
+            if ( position === "static" ) {
+                elem.style.position = "relative";
+            }
 
-                // Reset the properties, if the item has been hidden or shown
-                // 如果元素已被隐藏或显示,重置属性
-                if ( options.hide || options.show ) {
-                    for ( p in options.animatedProperties ) {
-                        jQuery.style( elem, p, options.orig[ p ] );
-                        jQuery.removeData( elem, "fxshow" + p, true );
-                        // Toggle data is no longer needed
-                        jQuery.removeData( elem, "toggle" + p, true );
-                    }
-                }
+            var curElem = jQuery( elem ),
+                curOffset = curElem.offset(),
+                curCSSTop = jQuery.css( elem, "top" ),
+                curCSSLeft = jQuery.css( elem, "left" ),
+                calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1,
+                props = {}, curPosition = {}, curTop, curLeft;
+
+            // need to be able to calculate position if either top or left is auto and position is either absolute or fixed
+            if ( calculatePosition ) {
+                curPosition = curElem.position();
+                curTop = curPosition.top;
+                curLeft = curPosition.left;
+            } else {
+                curTop = parseFloat( curCSSTop ) || 0;
+                curLeft = parseFloat( curCSSLeft ) || 0;
             }
 
-            // Execute the complete function
-            // in the event that the complete function throws an exception
-            // we must ensure it won't be called twice. #5684
+            if ( jQuery.isFunction( options ) ) {
+                options = options.call( elem, i, curOffset );
+            }
 
-            // 将 options 中的 complete 赋值给 complete 变量
-            complete = options.complete;
-// 如果 complete 为真
-            if ( complete ) {
-                // 将 options.complete 设为 false
-                options.complete = false;
-                // 调用 complete 函数,并将 elem 作为参数传递
-                complete.call( elem );
+            if ( options.top != null ) {
+                props.top = ( options.top - curOffset.top ) + curTop;
             }
-        }
-// 返回 false
-        return false;
-// 否则
-    } else {
-        // 经典的缓动效果不能用于无限时长
-        if ( options.duration == Infinity ) {
-    // 将当前时间 t 赋值给 this.now
-    this.now = t;
-} else {
-    // 计算经过的时间 n,等于当前时间 t 减去开始时间 this.startTime
-    n = t - this.startTime;
-    // 计算动画状态,等于经过的时间 n 除以总时长 options.duration
-    this.state = n / options.duration;
-    // 执行缓动函数,默认为 swing,根据动画属性从 jQuery.easing 中选择相应的缓动函数
-    this.pos = jQuery.easing[ options.animatedProperties[this.prop] ]( this.state, n, 0, 1, options.duration );
-    // 计算当前位置,根据起始位置、结束位置和缓动后的位置比例计算
-    this.now = this.start + ( (this.end - this.start) * this.pos );
-}
-// 执行动画的下一步
-this.update();
-}
-// 返回 true
-return true;
-}
-};
-// 扩展 jQuery.fx 对象
-jQuery.extend( jQuery.fx, {
-    // 定义 tick 函数
-    tick: function() {
-        // 定义变量 timer 和 timers,将 jQuery.timers 赋值给 timers
-        var timer,
-            timers = jQuery.timers,
-            i = 0;
-        // 遍历 timers 数组
-        for ( ; i < timers.length; i++ ) {
-            // 将当前元素赋值给 timer
-            timer = timers[ i ];
-            // 检查定时器是否未被移除,如果是则将其从数组中移除
-            if (!timer() && timers[ i ] === timer ) {
-                timers.splice( i--, 1 );
+            if ( options.left != null ) {
+                props.left = ( options.left - curOffset.left ) + curLeft;
             }
-        }
-        // 如果 timers 数组为空
-        if (!timers.length ) {
-            // 调用 jQuery.fx.stop 函数
-            jQuery.fx.stop();
-        }
-    },
-    // 定义间隔时间为 13
-    interval: 13,
-    // 定义 stop 函数
-    stop: function() {
-        // 清除定时器
-        clearInterval( timerId );
-        // 将 timerId 设为 null
-        timerId = null;
-    },
-    // 定义速度对象
-    speeds: {
-        // 慢速度为 600
-        slow: 600,
-        // 快速度为 200
-        fast: 200,
-        // 默认速度为 400
-        // Default speed
-        _default: 400
-    },
-    // 定义 step 对象
-    step: {
-        // 针对 opacity 属性的动画步骤函数
-        opacity: function( fx ) {
-            // 设置元素的 opacity 样式为 fx.now
-            jQuery.style( fx.elem, "opacity", fx.now );
-        },
-        // 默认的动画步骤函数
-        _default: function( fx ) {
-            // 如果元素有 style 属性且相应的属性不为空
-            if ( fx.elem.style && fx.elem.style[ fx.prop ]!= null ) {
-                // 设置元素的相应属性为 fx.now 加上单位
-                fx.elem.style[ fx.prop ] = fx.now + fx.unit;
+
+            if ( "using" in options ) {
+                options.using.call( elem, props );
             } else {
-                // 直接设置元素的相应属性为 fx.now
-                fx.elem[ fx.prop ] = fx.now;
+                curElem.css( props );
             }
         }
-    }
-});
-// 确保不能为负的属性在缓动时不会出现负值
-jQuery.each( fxAttrs.concat.apply( [], fxAttrs ), function( i, prop ) {
-    // 排除 margin 相关属性(除了 marginTop, marginLeft, marginBottom 和 marginRight)
-    if ( prop.indexOf( "margin" ) ) {
-        // 为相应属性定义动画步骤函数
-        jQuery.fx.step[ prop ] = function( fx ) {
-            // 设置元素的相应属性,取最大值 0 和 fx.now 加上单位
-            jQuery.style( fx.elem, prop, Math.max(0, fx.now) + fx.unit );
-        };
-    }
-});
-// 如果 jQuery.expr 和 jQuery.expr.filters 存在
-if ( jQuery.expr && jQuery.expr.filters ) {
-    // 为 jQuery.expr.filters 定义 animated 函数
-    jQuery.expr.filters.animated = function( elem ) {
-        // 使用 jQuery.grep 过滤 jQuery.timers 数组,筛选出元素等于 fn.elem 的元素
-        return jQuery.grep(jQuery.timers, function( fn ) {
-            return elem === fn.elem;
-        }).length;
-    };
-}
-// 尝试恢复元素的默认显示值
-function defaultDisplay( nodeName ) {
-    // 如果 elemdisplay[ nodeName ] 不存在
-    if (!elemdisplay[ nodeName ] ) {
-        // 创建 body 元素
-        var body = document.body,
-            // 创建一个新元素
-            elem = jQuery( "<" + nodeName + ">" ).appendTo( body ),
-            // 获取元素的显示样式
-            display = elem.css( "display" );
-        // 移除元素
-        elem.remove();
-        // 如果显示样式为 none 或空
-        if ( display === "none" || display === "" ) {
-            // 如果 iframe 不存在,创建 iframe
-            if (!iframe ) {
-                iframe = document.createElement( "iframe" );
-                iframe.frameBorder = iframe.width = iframe.height = 0;
-            }
-            // 将 iframe 添加到 body 中
-            body.appendChild( iframe );
-            // 如果 iframeDoc 不存在或 iframe 不支持 createElement
-            if (!iframeDoc ||!iframe.createElement ) {
-                // 获取 iframe 的文档对象
-                iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document;
-                // 写入文档内容
-                iframeDoc.write( ( jQuery.support.boxModel? "<!doctype html>" : "" ) + "<html><body>" );
-                // 关闭文档
-                iframeDoc.close();
-            }
-            // 在 iframe 文档中创建元素
-            elem = iframeDoc.createElement( nodeName );
-            // 将元素添加到 iframe 文档的 body 中
-            iframeDoc.body.appendChild( elem );
-            // 获取元素的显示样式
-            display = jQuery.css( elem, "display" );
-            // 从 body 中移除 iframe
-            body.removeChild( iframe );
-        }
-        // 存储元素的正确默认显示值
-        elemdisplay[ nodeName ] = display;
-    }
-    // 返回元素的默认显示值
-    return elemdisplay[ nodeName ];
-}
-// 定义变量 getOffset 和正则表达式 rtable、rroot
-var getOffset,
-    rtable = /^t(?:able|d|h)$/i,
-    rroot = /^(?:body|html)$/i;
-// 如果 document.documentElement 支持 getBoundingClientRect 方法
-if ( "getBoundingClientRect" in document.documentElement ) {
-    // 定义 getOffset 函数
-    getOffset = function( elem, doc, docElem, box ) {
-        try {
-            // 获取元素的边界矩形
-            box = elem.getBoundingClientRect();
-        } catch(e) {}
-        // 确保元素在 DOM 中
-        if (!box ||!jQuery.contains( docElem, elem ) ) {
-            // 如果获取失败或元素不在 DOM 中,返回默认的偏移量
-            return box? { top: box.top, left: box.left } : { top: 0, left: 0 };
-        }
-        // 获取 body 元素
-        var body = doc.body,
-            // 获取窗口对象
-            win = getWindow( doc ),
-            // 获取客户端顶部偏移量
-            clientTop  = docElem.clientTop  || body.clientTop  || 0,
-            // 获取客户端左侧偏移量
-            clientLeft = docElem.clientLeft || body.clientLeft || 0,
-            // 获取页面垂直滚动距离
-            scrollTop  = win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop  || body.scrollTop,
-            // 获取页面水平滚动距离
-            scrollLeft = win.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft,
-            // 计算顶部偏移量
-            top  = box.top  + scrollTop  - clientTop,
-            // 计算左侧偏移量
-            left = box.left + scrollLeft - clientLeft;
-        // 返回元素的偏移量
-        return { top: top, left: left };
     };
-// 否则
-} else {
-    // 另一种获取偏移量的函数
-    getOffset = function( elem, doc, docElem ) {
-        // 定义变量 computedStyle
-        var computedStyle,
-            // 获取元素的偏移父元素
-            offsetParent = elem.offsetParent,
-            // 上一个偏移父元素
-            prevOffsetParent = elem,
-            // 获取 body 元素
-            body = doc.body,
-            // 获取文档的默认视图
-            defaultView = doc.defaultView,
-            // 获取元素的计算样式
-            prevComputedStyle = defaultView? defaultView.getComputedStyle( elem, null ) : elem.currentStyle,
-            // 获取元素的顶部偏移量
-            top = elem.offsetTop,
-            // 获取元素的左侧偏移量
-            left = elem.offsetLeft;
-        // 遍历元素的父元素
-        while ( (elem = elem.parentNode) && elem!== body && elem!== docElem ) {
-            // 如果支持固定定位且上一个元素的位置是固定的
-            if ( jQuery.support.fixedPosition && prevComputedStyle.position === "fixed" ) {
-                break;
-            }
-            // 获取元素的计算样式
-            computedStyle = defaultView? defaultView.getComputedStyle(elem, null) : elem.currentStyle;
-            // 减去元素的滚动距离
-            top  -= elem.scrollTop;
-            left -= elem.scrollLeft;
-            // 如果元素是偏移父元素
-            if ( elem === offsetParent ) {
-                // 加上偏移父元素的偏移量
-                top  += elem.offsetTop;
-                left += elem.offsetLeft;
-                // 如果不添加边框且元素不是 table 或单元格
-                if ( jQuery.support.doesNotAddBorder &&!(jQuery.support.doesAddBorderForTableAndCells && rtable.test(elem.nodeName)) ) {
-                    // 加上边框宽度
-                    top  += parseFloat( computedStyle.borderTopWidth  ) || 0;
-                    left += parseFloat( computedStyle.borderLeftWidth ) || 0;
-                }
-                // 更新上一个偏移父元素
-                prevOffsetParent = offsetParent;
-                // 更新偏移父元素
-                offsetParent = elem.offsetParent;
-            }
-            // 如果支持减去不可见溢出元素的边框且元素的溢出不是可见的
-            if ( jQuery.support.subtractsBorderForOverflowNotVisible && computedStyle.overflow!== "visible" ) {
-                // 加上边框宽度
-                top  += parseFloat( computedStyle.borderTopWidth  ) || 0;
-                left += parseFloat( computedStyle.borderLeftWidth ) || 0;
+
+
+    jQuery.fn.extend({
+
+        position: function() {
+            if ( !this[0] ) {
+                return null;
             }
-            // 更新计算样式
-            prevComputedStyle = computedStyle;
-        }
-        // 如果上一个元素的位置是相对或静态的
-        if ( prevComputedStyle.position === "relative" || prevComputedStyle.position === "static" ) {
-            // 加上 body 的偏移量
-            top  += body.offsetTop;
-            left += body.offsetLeft;
-        }
-        // 如果支持固定定位且上一个元素的位置是固定的
-        if ( jQuery.support.fixedPosition && prevComputedStyle.position === "fixed" ) {
-            // 加上最大的滚动距离
-            top  += Math.max( docElem.scrollTop, body.scrollTop );
-            left += Math.max( docElem.scrollLeft, body.scrollLeft );
-        }
-        // 返回元素的偏移量
-        return { top: top, left: left };
-    };
-}
-// 为 jQuery.fn.offset 函数添加方法
-jQuery.fn.offset = function( options ) {
-    // 如果有参数
-    if ( arguments.length ) {
-        // 如果 options 为 undefined,返回 this,否则遍历元素并调用 jQuery.offset.setOffset 函数
-        return options === undefined?
-            this :
-            this.each(function( i ) {
-                jQuery.offset.setOffset( this, options, i );
+
+            var elem = this[0],
+
+                // Get *real* offsetParent
+                offsetParent = this.offsetParent(),
+
+                // Get correct offsets
+                offset       = this.offset(),
+                parentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset();
+
+            // Subtract element margins
+            // note: when an element has margin: auto the offsetLeft and marginLeft
+            // are the same in Safari causing offset.left to incorrectly be 0
+            offset.top  -= parseFloat( jQuery.css(elem, "marginTop") ) || 0;
+            offset.left -= parseFloat( jQuery.css(elem, "marginLeft") ) || 0;
+
+            // Add offsetParent borders
+            parentOffset.top  += parseFloat( jQuery.css(offsetParent[0], "borderTopWidth") ) || 0;
+            parentOffset.left += parseFloat( jQuery.css(offsetParent[0], "borderLeftWidth") ) || 0;
+
+            // Subtract the two offsets
+            return {
+                top:  offset.top  - parentOffset.top,
+                left: offset.left - parentOffset.left
+            };
+        },
+
+        offsetParent: function() {
+            return this.map(function() {
+                var offsetParent = this.offsetParent || document.body;
+                while ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) {
+                    offsetParent = offsetParent.offsetParent;
+                }
+                return offsetParent;
             });
-    }
-    // 获取第一个元素
-    var elem = this[0],
-        // 获取元素的所有者文档
-        doc = elem && elem.ownerDocument;
-    // 如果文档不存在
-    if (!doc ) {
-        // 返回 null
-        return null;
-    }
-    // 如果元素是 body
-    if ( elem === doc.body ) {
-        // 获取 body 的偏移量
-        return jQuery.offset.bodyOffset( elem );
-    }
-    // 调用 getOffset 函数获取偏移量
-    return getOffset( elem, doc, doc.documentElement );
-};
-// 定义 jQuery.offset 对象
-jQuery.offset = {
-    // 获取 body 的偏移量
-    bodyOffset: function( body ) {
-        // 获取 body 的顶部和左侧偏移量
-        var top = body.offsetTop,
-            left = body.offsetLeft;
-        // 如果不包含 body 中的 margin 到偏移量中
-        if ( jQuery.support.doesNotIncludeMarginInBodyOffset ) {
-            // 加上 margin 顶部和左侧的值
-            top  += parseFloat( jQuery.css(body, "marginTop") ) || 0;
-            left += parseFloat( jQuery.css(body, "marginLeft") ) || 0;
-        }
-        // 返回偏移量
-        return { top: top, left: left };
-    },
-    // 设置元素的偏移量
-    setOffset: function( elem, options, i ) {
-        // 获取元素的位置
-        var position = jQuery.css( elem, "position" );
-        // 如果元素是静态位置,将其设为相对位置
-        if ( position === "static" ) {
-            elem.style.position = "relative";
-        }
-        // 获取元素的 jQuery 对象
-        var curElem = jQuery( elem ),
-            // 获取元素的偏移量
-            curOffset = curElem.offset(),
-            // 获取元素的顶部样式
-            curCSSTop = jQuery.css( elem, "top" ),
-            // 获取元素的左侧样式
-            curCSSLeft = jQuery.css( elem, "left" ),
-            // 判断是否需要计算位置
-            calculatePosition = ( position === "absolute" || position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1,
-            // 定义 props 和 curPosition 对象
-            props = {}, curPosition = {}, curTop, curLeft;
-        // 如果需要计算位置
-        if ( calculatePosition ) {
-            // 获取元素的位置
-            curPosition = curElem.position();
-            // 获取元素的顶部位置
-            curTop = curPosition.top;
-            // 获取元素的左侧位置
-            curLeft = curPosition.left;
-        } else {
-            // 获取元素的顶部和左侧位置
-            curTop = parseFloat( curCSSTop ) || 0;
-            curLeft = parseFloat( curCSSLeft ) || 0;
-        }
-        // 如果 options 是一个函数
-        if ( jQuery.isFunction( options ) ) {
-            // 调用函数并传递参数
-            options = options.call( elem, i, curOffset );
-        }
-        // 如果 options 中设置了顶部偏移量
-        if ( options.top!= null ) {
-            // 计算新的顶部偏移量
-            props.top = ( options.top - curOffset.top ) + curTop;
-        }
-        // 如果 options 中设置了左侧偏移量
-        if ( options.left!= null ) {
-            // 计算新的左侧偏移量
-            props.left = ( options.left - curOffset.left ) + curLeft;
-        }
-        // 如果 options 中使用了 using 函数
-        if ( "using" in options ) {
-            // 调用 using 函数
-            options.using.call( elem, props );
-        } else {
-            // 设置元素的样式
-            curElem.css( props );
-        }
-    }
-};
-
-// 扩展 jQuery.fn 对象
-jQuery.fn.extend({
-    // 定义 position 函数
-    position: function() {
-        // 如果没有元素,返回 null
-        if (!this[0] ) {
-            return null;
         }
-        // 获取第一个元素
-        var elem = this[0],
-            // 获取元素的偏移父元素
-            // Get *real* offsetParent
-            offsetParent = this.offsetParent(),
-            // 获取元素的偏移量
-            // Get correct offsets
-            offset       = this.offset(),
-            // 如果偏移父元素是 body 或 html,设置 parentOffset 为 { top: 0, left: 0 },否则获取偏移父元素的偏移量
-            parentOffset = rroot.test(offsetParent[0].nodeName)? { top: 0, left: 0 } : offsetParent.offset();
-        // 减去元素的 marginTop 边距
-        // Subtract element margins
-        // note: when an element has margin: auto the offsetLeft and marginLeft
-        // are the same in Safari causing offset.left to incorrectly be 0
-        offset.top  -= parseFloat( jQuery.css(elem, "marginTop") ) || 0;
-        // 减去元素的 marginLeft 边距
-        offset.left -= parseFloat( jQuery.css(elem, "marginLeft") ) || 0;
-        // 加上偏移父元素的 borderTopWidth 边框宽度
-        // Add offsetParent borders
-        parentOffset.top  += parseFloat( jQuery.css(offsetParent[0], "borderTopWidth") ) || 0;
-        // 加上偏移父元素的 borderLeftWidth 边框宽度
-        parentOffset.left += parseFloat( jQuery.css(offsetParent[0], "borderLeftWidth") ) || 0;
-        // 计算并返回最终的位置,为元素偏移量减去偏移父元素的偏移量
-        // Subtract the two offsets
-        return {
-            top:  offset.top  - parentOffset.top,
-            left: offset.left - parentOffset.left
-        };
-    },
-    // 定义 offsetParent 函数
-    offsetParent: function() {
-        // 对元素集合进行映射操作
-        return this.map(function() {
-            // 获取元素的偏移父元素,如果没有则为 document.body
-            var offsetParent = this.offsetParent || document.body;
-            // 当偏移父元素存在且不是 body 或 html 且位置为 static 时,继续查找上一级偏移父元素
-            while ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) {
-                offsetParent = offsetParent.offsetParent;
-            }
-            // 返回最终的偏移父元素
-            return offsetParent;
-        });
-    }
-});
+    });
 
 
-// 遍历 scrollLeft 和 scrollTop 及其对应的 pageXOffset 和 pageYOffset 属性
 // Create scrollLeft and scrollTop methods
-jQuery.each( {scrollLeft: "pageXOffset", scrollTop: "pageYOffset"}, function( method, prop ) {
-    // 判断 prop 是否包含 Y
-    var top = /Y/.test( prop );
-    // 为 jQuery.fn 扩展相应的方法
-    jQuery.fn[ method ] = function( val ) {
-        // 调用 jQuery.access 函数
-        return jQuery.access( this, function( elem, method, val ) {
-            // 获取元素的窗口对象
-            var win = getWindow( elem );
-            // 如果 val 未定义
-            if ( val === undefined ) {
-                // 如果存在窗口对象,根据不同情况获取滚动值
-                return win? (prop in win)? win[ prop ] :
-                        jQuery.support.boxModel && win.document.documentElement[ method ] ||
-                        win.document.body[ method ] :
-                    elem[ method ];
-            }
-            // 如果存在窗口对象
-            if ( win ) {
-                // 调用 scrollTo 方法设置滚动位置
-                win.scrollTo(
-                    // 根据 top 判断是设置水平还是垂直滚动位置
-                    !top? val : jQuery( win ).scrollLeft(),
-                    top? val : jQuery( win ).scrollTop()
-                );
-            } else {
-                // 直接设置元素的滚动属性
-                elem[ method ] = val;
-            }
-        }, method, val, arguments.length, null );
-    };
-});
+    jQuery.each( {scrollLeft: "pageXOffset", scrollTop: "pageYOffset"}, function( method, prop ) {
+        var top = /Y/.test( prop );
+
+        jQuery.fn[ method ] = function( val ) {
+            return jQuery.access( this, function( elem, method, val ) {
+                var win = getWindow( elem );
+
+                if ( val === undefined ) {
+                    return win ? (prop in win) ? win[ prop ] :
+                            jQuery.support.boxModel && win.document.documentElement[ method ] ||
+                            win.document.body[ method ] :
+                        elem[ method ];
+                }
+
+                if ( win ) {
+                    win.scrollTo(
+                        !top ? val : jQuery( win ).scrollLeft(),
+                        top ? val : jQuery( win ).scrollTop()
+                    );
+
+                } else {
+                    elem[ method ] = val;
+                }
+            }, method, val, arguments.length, null );
+        };
+    });
+
+    function getWindow( elem ) {
+        return jQuery.isWindow( elem ) ?
+            elem :
+            elem.nodeType === 9 ?
+                elem.defaultView || elem.parentWindow :
+                false;
+    }
+
 
-// 定义 getWindow 函数,用于获取元素的窗口对象
-function getWindow( elem ) {
-    // 如果元素是窗口,直接返回
-    return jQuery.isWindow( elem )?
-        elem :
-        // 如果元素是文档节点,返回其默认视图或父窗口
-        elem.nodeType === 9?
-            elem.defaultView || elem.parentWindow :
-            false;
-}
 
 
-// 遍历 Height 和 Width 属性,创建一系列方法
 // Create width, height, innerHeight, innerWidth, outerHeight and outerWidth methods
-jQuery.each( { Height: "width", Width: "height" }, function( name, type ) {
-    // 生成相应的 client、scroll 和 offset 属性
-    var clientProp = "client" + name,
-        scrollProp = "scroll" + name,
-        offsetProp = "offset" + name;
-    // 定义 innerHeight 和 innerWidth 方法
-    // innerHeight and innerWidth
-    jQuery.fn[ "inner" + name ] = function() {
-        // 获取第一个元素
-        var elem = this[0];
-        // 如果元素存在且有样式,使用 jQuery.css 获取元素的尺寸(包含内边距),否则使用元素的相应方法
-        return elem?
-            elem.style?
-                parseFloat( jQuery.css( elem, type, "padding" ) ) :
-                this[ type ]() :
-            null;
-    };
-    // 定义 outerHeight 和 outerWidth 方法
-    // outerHeight and outerWidth
-    jQuery.fn[ "outer" + name ] = function( margin ) {
-        // 获取第一个元素
-        var elem = this[0];
-        // 如果元素存在且有样式,使用 jQuery.css 获取元素的尺寸(根据 margin 参数包含边距或边框),否则使用元素的相应方法
-        return elem?
-            elem.style?
-                parseFloat( jQuery.css( elem, type, margin? "margin" : "border" ) ) :
-                this[ type ]() :
-            null;
-    };
-    // 定义 width 或 height 方法
-    jQuery.fn[ type ] = function( value ) {
-        // 调用 jQuery.access 函数
-        return jQuery.access( this, function( elem, type, value ) {
-            var doc, docElemProp, orig, ret;
-            // 如果元素是窗口
-            if ( jQuery.isWindow( elem ) ) {
-                // 获取文档对象和相应的文档元素属性
-                doc = elem.document;
-                docElemProp = doc.documentElement[ clientProp ];
-                // 根据 boxModel 支持情况获取相应的尺寸
-                return jQuery.support.boxModel && docElemProp ||
-                    doc.body && doc.body[ clientProp ] || docElemProp;
-            }
-            // 如果元素是文档节点
-            if ( elem.nodeType === 9 ) {
-                // 获取文档元素
-                doc = elem.documentElement;
-                // 如果 client 尺寸大于等于 scroll 尺寸,使用 client 尺寸,否则取最大的 scroll 或 offset 尺寸
-                // when a window > document, IE6 reports a offset[Width/Height] > client[Width/Height]
-                // so we can't use max, as it'll choose the incorrect offset[Width/Height]
-                // instead we use the correct client[Width/Height]
-                // support:IE6
-                if ( doc[ clientProp ] >= doc[ scrollProp ] ) {
-                    return doc[ clientProp ];
-                }
-                return Math.max(
-                    elem.body[ scrollProp ], doc[ scrollProp ],
-                    elem.body[ offsetProp ], doc[ offsetProp ]
-                );
-            }
-            // 如果 value 未定义,使用 jQuery.css 获取元素的尺寸,并将结果转为浮点数
-            if ( value === undefined ) {
-                orig = jQuery.css( elem, type );
-                ret = parseFloat( orig );
-                // 如果是数字,返回数字,否则返回原始结果
-                return jQuery.isNumeric( ret )? ret : orig;
-            }
-            // 设置元素的宽度或高度
-            jQuery( elem ).css( type, value );
-        }, type, value, arguments.length, null );
-    };
-});
+    jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
+        var clientProp = "client" + name,
+            scrollProp = "scroll" + name,
+            offsetProp = "offset" + name;
+
+        // innerHeight and innerWidth
+        jQuery.fn[ "inner" + name ] = function() {
+            var elem = this[0];
+            return elem ?
+                elem.style ?
+                    parseFloat( jQuery.css( elem, type, "padding" ) ) :
+                    this[ type ]() :
+                null;
+        };
+
+        // outerHeight and outerWidth
+        jQuery.fn[ "outer" + name ] = function( margin ) {
+            var elem = this[0];
+            return elem ?
+                elem.style ?
+                    parseFloat( jQuery.css( elem, type, margin ? "margin" : "border" ) ) :
+                    this[ type ]() :
+                null;
+        };
+
+        jQuery.fn[ type ] = function( value ) {
+            return jQuery.access( this, function( elem, type, value ) {
+                var doc, docElemProp, orig, ret;
+
+                if ( jQuery.isWindow( elem ) ) {
+                    // 3rd condition allows Nokia support, as it supports the docElem prop but not CSS1Compat
+                    doc = elem.document;
+                    docElemProp = doc.documentElement[ clientProp ];
+                    return jQuery.support.boxModel && docElemProp ||
+                        doc.body && doc.body[ clientProp ] || docElemProp;
+                }
+
+                // Get document width or height
+                if ( elem.nodeType === 9 ) {
+                    // Either scroll[Width/Height] or offset[Width/Height], whichever is greater
+                    doc = elem.documentElement;
+
+                    // when a window > document, IE6 reports a offset[Width/Height] > client[Width/Height]
+                    // so we can't use max, as it'll choose the incorrect offset[Width/Height]
+                    // instead we use the correct client[Width/Height]
+                    // support:IE6
+                    if ( doc[ clientProp ] >= doc[ scrollProp ] ) {
+                        return doc[ clientProp ];
+                    }
+
+                    return Math.max(
+                        elem.body[ scrollProp ], doc[ scrollProp ],
+                        elem.body[ offsetProp ], doc[ offsetProp ]
+                    );
+                }
+
+                // Get width or height on the element
+                if ( value === undefined ) {
+                    orig = jQuery.css( elem, type );
+                    ret = parseFloat( orig );
+                    return jQuery.isNumeric( ret ) ? ret : orig;
+                }
+
+                // Set the width or height on the element
+                jQuery( elem ).css( type, value );
+            }, type, value, arguments.length, null );
+        };
+    });
+
+
 
 
-// 将 jQuery 暴露到全局对象 window 中
 // Expose jQuery to the global object
-window.jQuery = window.$ = jQuery;
+    window.jQuery = window.$ = jQuery;
 
-// 将 jQuery 作为 AMD 模块暴露,但仅适用于理解在页面中加载多个 jQuery 版本问题的 AMD 加载器
 // Expose jQuery as an AMD module, but only for AMD loaders that
 // understand the issues with loading multiple versions of jQuery
 // in a page that all might call define(). The loader will indicate
@@ -9700,10 +9395,10 @@ window.jQuery = window.$ = jQuery;
 // file names, and jQuery is normally delivered in a lowercase file name.
 // Do this after creating the global so that if an AMD module wants to call
 // noConflict to hide this version of jQuery, it will work.
-if ( typeof define === "function" && define.amd && define.amd.jQuery ) {
-    define( "jquery", [], function () { return jQuery; } );
-}
+    if ( typeof define === "function" && define.amd && define.amd.jQuery ) {
+        define( "jquery", [], function () { return jQuery; } );
+    }
 
 
 
-})( window );
\ No newline at end of file
+})( window );