/**
 * Copyright (c) fuchun.org All rights reserved.
 * 
 * v 0.1.2 - 2008/04/11 by Fuchun
 * 
 * Requires jQuery 1.2+
 */

if(typeof FUI === 'undefined') var FUI = {};
if(typeof FUI.fn === 'undefined') FUI.fn = {};
if(typeof FUI.util === 'undefined') FUI.util = {};

/**
 * 在FUI名称空间内添加方法。
 */
FUI = {
    
    /**
     * 如果指定的对象 o 为<code>Array</code>类型，则返回true。
     * @param {Object} o 要检查的对象
     * @return Boolean
     */
    isArray: function(o) {
        if (o) {
           return FUI.isNumber(o.length) && FUI.isFunction(o.splice) && 
                  !FUI.hasOwnProperty(o.length);
        }
        return false;
    },
    
    /**
     * 如果指定的对象 o 为<code>Boolean</code>类型，则返回true。
     * @param {Object} o 要检查的对象
     * @return Boolean
     */
    isBoolean: function(o) {
        return typeof o === 'boolean';
    },
    
    /**
     * 如果指定的对象 o 为<code>Function</code>类型，则返回true。
     * @param {Object} o 要检查的对象
     * @return Boolean
     */
    isFunction: function(o) {
        return typeof o === 'function';
    },
    
    /**
     * 如果指定的对象 o 为<code>NULL</code>，则返回true。
     * @param {Object} o 要检查的对象
     * @return Boolean
     */
    isNull: function(o) {
        return o === null;
    },
    
    /**
     * 如果指定的 o 为空字符串，则返回true。
     * @param {Object} o 要检查的字符串
     * @return Boolean
     */
    isEmpty: function(o) {
        return o === '';
    },
    
    /**
     * 如果指定的对象 o 为<code>NULL</code>或者空字符串，则返回true。
     * @param {Object} o 要检查的对象
     * @return Boolean
     */
    isNullOrEmpty: function(o) {
        return FUI.isNull(o) || FUI.isEmpty(o);
    },
    
    /**
     * 如果指定的对象 o 为<code>Number</code>类型，则返回true。
     * @param {Object} o 要检查的对象
     * @return Boolean
     */
    isNumber: function(o) {
        // isFinite(o) o 为NaN、负无穷或正无穷是返回false
        return typeof o === 'number' && isFinite(o);
    },
    
    /**
     * 如果指定的对象 o 为<code>Object</code>类型，则返回true。
     * @param {Object} o 要检查的对象
     * @return Boolean
     */
    isObject: function(o) {
        return (o && (typeof o === 'object' || FUI.isFunction(o))) || false;
    },
    
    /**
     * 如果指定的对象 o 为<code>String</code>类型，则返回true。
     * @param {Object} o 要检查的对象
     * @return Boolean
     */
    isString: function(o) {
        return typeof o === 'string';
    },
    
    /**
     * 如果指定的对象 o 为<code>undefined</code>类型，则返回true。
     * @param {Object} o 要检查的对象
     * @return Boolean
     */
    isUndefined: function(o) {
        return typeof o === 'undefined';
    },
    
    /**
     * 一个便利的方法检查对象是否是非空值。若该值为 null/undefined/NaN则返回false，
     * 其他类型则返回true。
     * @param {Object} o 要检查的对象
     * @return Boolean
     */
    isValue: function(o) {
        return (FUI.isObject(o) || FUI.isString(o) || FUI.isNumber(o) || FUI.isBoolean(o));
    },
    
    /**
     * 返回一个布尔值，指出一个对象是否具有指定名称的属性。
     * 
     * @param {Object} o 要检查的对象
     * @param {String} prop 要检查的属性名称
     * @return Boolean
     */
    hasOwnProperty: function(o, prop) {
        if(Object.prototype.hasOwnProperty) {
            return o.hasOwnProperty(prop);
        }
        return !FUI.isUndefined(o[prop]) &&
            o.constructor.prototype[prop] !== o[prop];
    }
};

/** 向v 0.1.0版本的FUI.lang库兼容。*/
FUI.lang = jQuery.extend({}, FUI);

/**
 * 一个关于浏览器的静态类，用于验证浏览器种类与版本。
 * @type static class
 * @class FUI.browser
 * @since FUI 1.0.0
 * @author YAHOO
 */
FUI.browser = function() {
    
    var o = {
    
        /**
         * Internet Explorer 浏览器版本，非IE为0。如：IE 6.0
         * @type float
         */
        IE: 0,
        
        /**
         * Opera 浏览器版本，非Opera为0。如：Opera 9.2
         * @type float
         */
        Opera: 0,
        
        /**
         * Gecko 引擎浏览器版本，非Gecko引擎浏览器为0.如：
         * <pre>
         * Firefox 1.0.0.4: 1.7.8   <-- Reports 1.7
         * Firefox 1.5.0.9: 1.8.0.9 <-- Reports 1.8
         * Firefox 2.0.0.3: 1.8.1.3 <-- Reports 1.8
         * Firefox 3 alpha: 1.9a4   <-- Reports 1.9
         * </pre>
         * @type float
         */
        Gecko: 0,
        
        /**
         * AppleWebkit 浏览器版本，如：418.9.1
         * <pre>
         * Safari 1.3.2 (312.6): 312.8.1 <-- Reports 312.8 -- currently the 
         *                                   latest available for Mac OSX 10.3.
         * Safari 2.0.2:         416     <-- hasOwnProperty introduced
         * Safari 2.0.4:         418     <-- preventDefault fixed
         * Safari 2.0.4 (419.3): 418.9.1 <-- One version of Safari may run
         *                                   different versions of webkit
         * Safari 2.0.4 (419.3): 419     <-- Current Safari release
         * Webkit 212 nightly:   522+    <-- Safari 3.0 (with native SVG) should
         *                                   be higher than this
         * </pre>
         * @type float
         */
        Webkit: 0
    };
    
    var ua = navigator.userAgent, m;
    if((/KHTML/).test(ua)) { o.Webkit = 1; }
    m = ua.match(/AppleWebKit\/([^\s]*)/);
    if(m && m[1]) {
        o.Webkit = parseFloat(m[1]);
    }
    if(!o.Webkit) { // 非Webkit浏览器
        m = ua.match(/Opera[\s\/]([^\s]*)/);
        if(m && m[1]) {
            o.Opera = parseFloat(m[1]);
        } else { // 非Webkit、Opera浏览器
            m = ua.match(/MSIE\s([^;]*)/);
            if(m && m[1]) {
                o.IE = parseFloat(m[1]);
            } else { // 非Webkit、Opera、IE浏览器
                m = ua.match(/Gecko\/([^\s]*)/);
                if(m) {
                    o.Gecko = 1;
                    m = ua.match(/rv:([^\s\)]*)/);
                    if(m && m[1]) { o.Gecko = parseFloat(m[1]); }
                }
            }
        }
    }
    return o;
}();

/**
 * 一个关于浏览器的静态类，用于验证操作系统和各种版本。
 * @type static class
 * @class FUI.OS
 * @since FUI v 0.1.0
 * @author Fuchun
 */
FUI.OS = function() {
    
    var o = {
        
        /**
        * Windows OS 版本，非 Windows OS 为空字符串。
        * <pre>
        * Windows 98
        * Windows NT
        * Windows 2000
        * Windows XP
        * Windows 2003
        * </pre>
        * @type string
        */
        Windows: '',
        
        /**
        * Unix OS 版本，非 Unix OS 为空字符串。
        * @type string
        */
        Unix: '',
        
        /**
        * Macintosh OS 版本，非 Macintosh OS 为空字符串。
        * @type string
        */
        MacOS: ''
    };
    
    var ua = navigator.userAgent, pm = navigator.platform;
    if((/(Win32)/).test(pm) || (/(Windows)/).test(pm)) { // Windows OS
        if((/(Win98)/).test(ua) || (/(Windows 98)/).test(ua))
            o.Windows = 'Windows 98';
        if((/(Windows NT 5.0)/).test(ua) || (/(Windows 2000)/).test(ua))
            o.Windows = 'Windows 2000';
        if((/(Windows NT 5.1)/).test(ua) || (/(Windows XP)/).test(ua))
            o.Windows = 'Windows XP';
        if((/(Windows NT 5.2)/).test(ua) || (/(Windows 2003)/).test(ua))
            o.Windows = 'Windows 2003';
        if( ((/(WinNT)/).test(ua) || (/(Windows NT)/).test(ua) || (/(WinNT4.0)/).test(ua) ||
            (/(Windows NT 4.0)/).test(ua)) && o.Windows == '')
        o.Windows = 'Windows NT';
    }
    if((/(Mac68K)/).test(pm) || (/(MacPPC)/).test(pm) || (/(Macintosh)/).test(pm)) { // Macintosh OS
        if((/(Mac_68000)/).test(ua) || (/(68K)/).test(ua))
            o.MacOS = 'Macintosh 68K';
        if((/(Mac_PowerPC)/).test(ua) || (/(PPC)/).test(ua))
            o.MacOS = 'Macintosh PPC';
    }
    // 这里没有判断SunOS，只判断它是否为Unix核心的系统
    if((/(X11)/).test(pm) && o.Windows == '' && o.MacOS == '') {
        o.Unix = 'Unix OS';
    }
    return o;
}();

/**
 * 模拟java API中的StringBuilder类。一个可变的字符序列。
 * 当三个以上字符串连接时，推荐使用该类，提高字符串的操作效率。
 * 
 * @class StringBuilder
 * @since FUI v 0.1.0
 * @author Fuchun
 */
var StringBuilder = function(s) {
    this.__strings__ = new Array();
    if(!FUI.isNull(s) && !FUI.isUndefined(s)) this.append(s);
};
/** zStringBuilder 类只为向后兼容 */
var zStringBuilder = function(s) {
    this.__strings__ = new Array();
    if(!FUI.isNull(s) && !FUI.isUndefined(s)) this.append(s);
};
StringBuilder.prototype = {
    /**
     * 追加 Object 参数的字符串表示形式。
     * 
     * @param object 要添加到此字符序列的对象
     * @return StringBuilder 此对象的一个引用
     */
    append: function(o) {
        this.__strings__.push((FUI.isNull(o) && FUI.isUndefined(o)) ? '' : o.toString());
        return this;
    },
    
    /** 清空字符串缓存区。*/
    clear: function() {
        this.__strings__ = new Array();
    },
    
    /**
     * 返回此序列中数据的字符串表示形式。
     * @return string 此字符序列的字符串表示形式。
     */
    toString: function() {
        return this.__strings__.join('');
    }
};
zStringBuilder.prototype = new StringBuilder();

/**
 * 基于Java API哈希表的 Map 接口的Javascript实现。
 * 
 * @class HashMap
 * @since FUI v 0.1.0
 * @author Fuchun
 */

/**
 * 构造一个具有默认初始容量(0)或者构造一个带指定初始容量或者构造一个映射关系与指定 HashMap 相同的 HashMap。
 * 
 * @param o {undefined|HashMap} 
 * @constructor
 */
var HashMap = function(o) {
    this.__array__ = null;
    if(FUI.isUndefined(o) || FUI.isNullOrEmpty(o)) {
        this.__array__ = [];
    } else if(o instanceof HashMap) {
        var arrTemp = o.__array__;
        this.__array__ = arrTemp;
    }
};
HashMap.prototype = {
    
    /**
     * 从此映射中移除所有映射关系。
     */
    clear: function() {
        this.__array__ = [];
    },
    
    /**
     * 如果此映射包含对于指定的键的映射关系，则返回 true。
     * @param key Object 要测试其是否在此映射中存在的键
     * @return boolean 如果此映射包含对于指定的键的映射关系，则返回 true。
     */
    containsKey: function(key) {
        if(FUI.isUndefined(key) || FUI.isNullOrEmpty(key))
            return false;
        for(var i = 0; i < this.size(); i++) {
            if(!FUI.isUndefined(this.__array__[i]['key']) && this.__array__[i]['key'] == key)
                return true;
        }
        return false;
    },
    
    /**
     * 如果此映射将一个或多个键映射到指定值，则返回 true。
     * @param value Object 要测试其是否在此映射中存在的值。
     * @return boolean 如果此映射将一个或多个键映射到指定值，则返回 true。
     */
    containsValue: function(value) {
        if(FUI.isUndefined(value))
            return false;
        for(var i = 0; i < this.size(); i++) {
            if(!FUI.isUndefined(this.__array__[i]['value']) && this.__array__[i]['value'] == value)
                return true;
        }
        return false;
    },
    
    /**
     * 返回指定键在此标识哈希映射中所映射的值，如果对于此键来说，映射不包含任何映射关系，则返回 null。
     * 返回值为 null 并不一定 表示对于该键来说，映射不包含任何映射关系，也可能是映射显式地将键映射到 null。
     * 使用 containsKey 方法可以区分这两种情况。
     * @param key Object 与要返回的值相关联的键。
     * @return Object 此映射对于指定键所映射的值，如果该映射对于此键不包含任何映射关系，则返回 null。
     */
    get: function(key) {
        if(FUI.isUndefined(key) || FUI.isNullOrEmpty(key)) return null;
        for(var i = 0; i < this.size(); i++) {
            if(this.__array__[i]['key'] == key)
                return this.__array__[i]['value'];
        }
        return null;
    },
    
    /**
     * 如果此映射不包含键-值映射关系，则返回 true。
     * @return boolean 如果此映射不包含键-值映射关系，则返回 true。
     */
    isEmpty: function() {
        return this.size() == 0 ? true : false;
    },
    
    /**
     * 返回此映射中所包含的键的数组。
     * @return Array 返回此映射中所包含的键的数组。
     */
    keySet: function() {
        var keys = [];
        for(var i = 0; i < this.size(); i++) {
            keys[i] = this.__array__[i]['key'];
        }
        return keys;
    },
    
    /**
     * 返回此映射所包含的值的数组。
     * @return Array 返回此映射所包含的值的数组。
     */
    values: function() {
        var vals = [];
        for(var i = 0; i < this.size(); i++) {
            vals[i] = this.__array__[i]['value'];
        }
        return vals;
    },
    
    /**
     * 在此映射中关联指定值与指定键。如果此映射以前包含了一个该键的映射关系，则旧值被替换。
     * @param key Object 指定值将要关联的键。
     * @param value Object 指定键将要关联的值。
     */
    put: function(key, value) {
        if(FUI.isUndefined(key) || FUI.isNullOrEmpty(key))
            throw new Error('This key is a NULL value.');
        if(this.containsKey(key)) {
            for(var i = 0; i < this.size(); i++) {
                if(!FUI.isUndefined(this.__array__[i]['key']) && this.__array__[i]['key'] == key){
                    this.__array__[i]['value'] = value; break;}
            }
        } else {
            var pos = this.__array__.length;
            this.__array__[pos] = new Object();
            this.__array__[pos]['key'] = key;
            this.__array__[pos]['value'] = value;
        }
    },
    
    /**
     * 如果此映射中存在该键的映射关系，则将其删除。
     * @param key Object 其映射关系要从映射中移除的键。
     */
    remove: function(key) {
        if(FUI.isUndefined(key) || FUI.isNullOrEmpty(key)) return;
        var temp = this.__array__;
        this.__array__ = [];
        for(var i = 0, j = 0; i < temp.length; i++) {
            if(temp[i]['key'] != key) {
                this.__array__[j] = temp[i];
                j++;
            }
        }
    },
    
    /**
     * 返回此映射中的键-值映射关系数。
     * @return Integer 此映射中的键-值映射关系数。
     */
    size: function() {
        return this.__array__.length;
    }
};

FUI.xml = {
    /**
     * 返回XML文档中的一个节点的Text值。
     * 
     * @param {Node} n XML的节点对象
     * @return String
     */
    text: function(n) {
        if(FUI.isUndefined(n) || FUI.isUndefined(n.nodeType) || n.nodeType != 1) {
            throw new Error('((((ERROR)))) - The appointed parameter value IS NOT Node.');
        } else {
            if(FUI.browser.IE) {
                return n.text;
            } else {
                return n.firstChild.data;
            }
        }
    },
    
    /**
     * 返回XML文档中的一个节点的给定属性的属性值。
     * 
     * @param {Node} n XML的节点对象
     * @param {String} name 节点属性名
     * @return String
     */
    attr: function(n, name) {
        if(FUI.isUndefined(n) || FUI.isUndefined(n.nodeType) || n.nodeType != 1) {
            throw new Error('((((ERROR)))) - The appointed parameter value IS NOT Node.');
        } else {
            return n.getAttribute(name);
        }
    }
};
if( window.$xml ) var _xml = window.$xml;
window.$xml = FUI.xml;

/**
 * XPath的跨浏览器实现。
 */
FUI.xpath = {
    
    /**
     * 返回模式匹配的第一个节点（Node）。若浏览器不支持XPath，则返回给浏览器错误信息。
     * 
     * @param contextNode XML文档对象的上下文节点。
     * @param xPathString XPath表达式字符串。
     * @param namespace XML文档的名称空间声明的字符串。
     * @return Node 返回模式匹配的第一个节点，若没有查找到，则返回 null。
     */
    findNode: function(contextNode, xPathString, namespace) {
        if(FUI.isUndefined(contextNode) || FUI.isNullOrEmpty(contextNode)) {
            if(FUI.browser.IE) {throw new Error('\u7b2c\u4e00\u4e2a\u53c2\u6570\u5e94\u8be5\u662fXML\u4e0a\u4e0b\u6587\u8282\u70b9\u5bf9\u8c61');}
            else if(Mozilla) {console.error('FUI.xpath.selectSingleNode: \u7b2c\u4e00\u4e2a\u53c2\u6570\u5e94\u8be5\u662fXML\u4e0a\u4e0b\u6587\u8282\u70b9\u5bf9\u8c61');}
        }
        if(FUI.isUndefined(xPathString) || FUI.isNullOrEmpty(xPathString)) {
            if(FUI.browser.IE) {throw new Error('\u7b2c\u4e8c\u4e2a\u53c2\u6570\u7684\u662fXPath\u8868\u8fbe\u5f0f\u5b57\u7b26\u4e32\uff0c\u4e0d\u80fd\u4e3a\u7a7a\u503c\uff0c\u6216\u8005\u7a7a\u5b57\u7b26\u4e32');}
            else if(Mozilla) {console.error('FUI.xpath.selectSingleNode: \u7b2c\u4e8c\u4e2a\u53c2\u6570\u7684\u662fXPath\u8868\u8fbe\u5f0f\u5b57\u7b26\u4e32\uff0c\u4e0d\u80fd\u4e3a\u7a7a\u503c\uff0c\u6216\u8005\u7a7a\u5b57\u7b26\u4e32');}
        }
        var firstNode = null;
        if(FUI.browser.IE) {
            firstNode = contextNode.selectSingleNode(xPathString);
        } else if(FUI.browser.Gecko) {
            var xPath = new XPathEvaluator();
            var nodes = xPath.evaluate(xPathString, contextNode, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
            if(nodes != null) {
                var node;
                while(node = nodes.iterateNext()) {
                    firstNode = node;
                    break;
               }
            }
        }
        return firstNode;
    },
    
    /**
     * 返回模式匹配的节点集合（Nodes）。若浏览器不支持XPath，则返回给浏览器错误信息。
     * 
     * @param contextNode XML文档对象的上下文节点。
     * @param xPathString XPath表达式字符串。
     * @param namespace XML文档的名称空间声明的字符串。
     * @return Array 返回模式匹配的节点集合（Nodes），若没有查找到，则返回 空数组，长度为0。
     */
    findNodes: function(contextNode, xPathString, namespace) {
        if(FUI.isUndefined(contextNode) || FUI.isNullOrEmpty(contextNode)) {
            if(FUI.browser.IE) {throw new Error('\u7b2c\u4e00\u4e2a\u53c2\u6570\u5e94\u8be5\u662fXML\u4e0a\u4e0b\u6587\u8282\u70b9\u5bf9\u8c61');}
            else if(Mozilla) {console.error('FUI.xpath.selectSingleNode: \u7b2c\u4e00\u4e2a\u53c2\u6570\u5e94\u8be5\u662fXML\u4e0a\u4e0b\u6587\u8282\u70b9\u5bf9\u8c61');return;}
        }
        if(FUI.isUndefined(xPathString) || FUI.isNullOrEmpty(xPathString)) {
            if(FUI.browser.IE) {throw new Error('\u7b2c\u4e8c\u4e2a\u53c2\u6570\u7684\u662fXPath\u8868\u8fbe\u5f0f\u5b57\u7b26\u4e32\uff0c\u4e0d\u80fd\u4e3a\u7a7a\u503c\uff0c\u6216\u8005\u7a7a\u5b57\u7b26\u4e32');}
            else if(FUI.browser.Gecko) {console.error('FUI.xpath.selectSingleNode: \u7b2c\u4e8c\u4e2a\u53c2\u6570\u7684\u662fXPath\u8868\u8fbe\u5f0f\u5b57\u7b26\u4e32\uff0c\u4e0d\u80fd\u4e3a\u7a7a\u503c\uff0c\u6216\u8005\u7a7a\u5b57\u7b26\u4e32');return;}
        }
        var nodes = [];
        if(FUI.browser.IE) {
            var nodeList = contextNode.selectNodes(xPathString);
            if(nodeList.length > 0)
                nodes = nodeList;
        } else if(FUI.browser.Gecko) {
            var xPath = new XPathEvaluator();
            var nodeList = xPath.evaluate(xPathString, contextNode, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
            if(nodeList != null) {
                var node;
                while(node = nodeList.iterateNext()) {
                    nodes.push(node);
                }
            }
        }
        return nodes;
    }
};
if( window.$xpath ) var _xpath = window.$xpath;
window.$xpath = FUI.xpath;

(function($) {

    var getStyle, setStyle,      // CSS 属性的getter和setter
        propertyCache = {},      // CSS Property的缓存集合
        reClassNameCache = {};   // CSS Class RegExp的缓存集合

    var IE = $.browser.msie,
        Mozilla = $.browser.mozilla,
        Opera = $.browser.opera,
        Safari = $.browser.safari;
    
    /**
     * 获取指定的CSS Class正则表达式。
     * @param {String} className CSS Class
     * @return {RegExp} 
     */
    var getClassRegExp = function(className) {
        var r = reClassNameCache[className];
        if(!r) {
            r = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)');
            reClassNameCache[className] = r;
        }
        return r;
    };
    
    /** Patterns RegExp Cache */
    var patterns = {
        HYPHEN: /(-[a-z])/i, ROOT_TAG: /^body|html$/i
    };
    
    var toCamel = function(property) {
        if(!patterns.HYPHEN.test(property)) { return property; }
        if(propertyCache[property]) { return propertyCache[property]; }
        var converted = property;
        while(patterns.HYPHEN.exec(converted)) {
            converted = converted.replace(RegExp.$1, RegExp.$1.substr(1).toUpperCase());
        }
        propertyCache[property] = converted;
        return converted;
    };
    
    if (document.defaultView && document.defaultView.getComputedStyle) {
        getStyle = function(el, property) {
            var value = null;
            if (property == 'float') { property = 'cssFloat'; }
            var css = document.defaultView.getComputedStyle(el, '');
            if (css) { value = css[toCamel(property)]; }
            return el.style[property] || value;
        };
    } else if (document.documentElement.currentStyle && IE) { // IE method
        getStyle = function(el, property) {                         
            switch( toCamel(property) ) {
                case 'opacity' :
                    var val = 100;
                    try {
                        val = el.filters['DXImageTransform.Microsoft.Alpha'].opacity;
                    } catch(e) {
                        try { val = el.filters('alpha').opacity; } catch(e) { }
                    }
                    return val / 100;
                case 'float':
                    property = 'styleFloat';
                default:
                    var value = el.currentStyle ? el.currentStyle[property] : null;
                    return ( el.style[property] || value );
            }
        };
    } else {
        getStyle = function(el, property) { return el.style[property]; };
    }
    
    if (IE) {
        setStyle = function(el, property, val) {
            switch (property) {
                case 'opacity':
                    if (FUI.isString(el.style.filter) ) {
                        el.style.filter = 'alpha(opacity=' + val * 100 + ')';
                        if (!el.currentStyle || !el.currentStyle.hasLayout) {
                            el.style.zoom = 1;
                        }
                    }
                    break;
                case 'float': property = 'styleFloat';
                default:
                el.style[property] = val;
            }
        };
    } else {
        setStyle = function(el, property, val) {
            if (property == 'float') { property = 'cssFloat'; }
            el.style[property] = val;
        };
    }

    if(Mozilla) { // 在FireFox中模拟IE的DOMDocument的方法
        Document.prototype.readyState = 0;
        // 模拟IE DOM中的onreadystatechange
        Document.prototype.onreadystatechange = null;
        Document.prototype.__changeReadyState__ = function (iReadyState) {
            this.readyState = iReadyState;
            if(typeof this.onreadystatechange == "function") {
                this.onreadystatechange();
            }
        };
        // 模拟IE DOM中的parseError
        Document.prototype.__initError__ = function() {
            this.parseError.errorCode = 0;
            this.parseError.filepos = -1;
            this.parseError.line = -1;
            this.parseError.linePos = -1;
            this.parseError.reason = null;
            this.parseError.srcText = null;
            this.parseError.url= null;
        };
        
        Document.prototype.__checkForErrors__ = function() {
            if(this.documentElement.tagName == "parseerror") {
                var errorReg = />([\s\S]*?)location:([\s\S]*?)Line Number (\d+),Column (\d+):<sourcetext>([\s\S]*?)(?:\-*\^)/;
                errorReg.test(this.xml);
                this.parseError.errorCode = -999999;
                this.parseError.reason = RegExp.$1;
                this.parseError.url= RegExp.$2;
                this.parseError.line = parseInt(RegExp.$3);
                this.parseError.linePos = parseInt(RegExp.$4);
                this.parseError.srcText = RegExp.$5;
            }
        };
        // 模拟IE DOM中的loadXML方法
        Document.prototype.loadXML = function (sXml) {
            this.__initError__();
            this.__changeReadyState__(1);
            var parser = new DOMParser();
            var xmlDoc = parser.parseFromString(xXml, "text/xml");
            while(this.firstChild) {
                this.removeChild(this.firstChild);
            }
            for(var i = 0; i < xmlDoc.childNodes.length; i++) {
                var newNode = this.importNode(xmlDoc.childNodes[i], true);
                this.appendChild(newNode);
            }
            
            this.__checkForErrors__();
            this.__changeReadyState__(4);
        };
        //  模拟IE DOM中的load方法
        Document.prototype.__load__ = Document.prototype.load;
        
        Document.prototype.load = function (sURL) {
            this.__initError__();
            this.__changeReadyState__(1);
            this.__load__(sURL);
        };
        // 模拟IE DOM中的.xml属性
        Node.prototype.__defineGetter__("xml", function() {
            var oSerializer = new XMLSerializer();
            return oSerializer.serializeToString(this, "text/xml");
        });
    }
    
    if(window.HTMLElement) { // 在Firefox中模拟IE中的HTMLElement的一些属性
        HTMLElement.prototype.__defineSetter__("outerHTML",function(sHTML){
            var r = this.ownerDocument.createRange();
            r.setStartBefore(this);
            var df = r.createContextualFragment(sHTML);
            this.parentNode.replaceChild(df,this);
            return sHTML;
        });
        
        HTMLElement.prototype.__defineGetter__("outerHTML",function(){
            var attr;
            var attrs = this.attributes;
            var str = "<" + this.tagName.toLowerCase();
            for(var i = 0; i < attrs.length; i++) {
                attr = attrs[i];
                if(attr.specified)
                str += " " + attr.name + '="' + attr.value + '"';
            }
            if(!this.canHaveChildren) return str + ">";
            return str + ">" + this.innerHTML + "</" + this.tagName.toLowerCase() + ">";
        });
        
        HTMLElement.prototype.__defineGetter__("canHaveChildren", function() {
            switch(this.tagName.toLowerCase()){
                case "area":
                case "base":
                case "basefont":
                case "col":
                case "frame":
                case "hr":
                case "img":
                case "br":
                case "input":
                case "isindex":
                case "link":
                case "meta":
                case "param":
                return false;
            }
            return true;
        });
    }
    
    // 这里不再检查数据的正确性
    var __addOption__ = function(el, option) {
        try {
            el.add(option, null);
        } catch(e) {
            el.add(option, -1);
        }
    };
    
    FUI.dom = {
        
        /**
         * 返回给定的<code>HTMLDocument</code>水平滚动条离左边界的距离（默认单位：px）。
         *
         * @param HTMLDocument doc 给定的HTMLDocument
         * @return Integer 给定的HTMLDocument水平滚动条离左边界的距离
         */
        getScrollLeft: function(doc) {
            doc = doc || document;
            return Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft);
        },
        
        /**
         * 返回给定的<code>HTMLDocument</code>垂直滚动条离上边界的距离（默认单位：px）。
         *
         * @param HTMLDocument doc 给定的HTMLDocument
         * @return Integer 给定的HTMLDocument垂直滚动条离上边界的距离
         */
        getScrollTop: function(doc) {
            doc = doc || document;
            return Math.max(doc.documentElement.scrollTop, doc.body.scrollTop);
        },
        
        /** @see #getScrollLeft(object) */
        scrollLeft: function(doc) {return FUI.dom.getScrollLeft(doc);},
        
        /** @see #getScrollTop(object) */
        scrollTop: function(doc) {return FUI.dom.getScrollTop(doc);},
        
        /**
         * 返回当前视窗的宽度，单位：px。
         * @return Integer 当前视窗的宽度(不包括滚动条移动的距离)。
         */
        getClientWidth: function() {
            var width = self.innerWidth;  // Safari
            var mode = document.compatMode;
            if (mode || IE) { // IE, Mozilla, Opera
                width = (mode == 'CSS1Compat') ?
                        document.documentElement.clientWidth : // 标准
                        document.body.clientWidth; // IE 的怪异模式
            }
            return width;
        },
        
        /**
         * 返回当前视窗的高度，单位：px。
         * @return Integer 当前视窗的高度(不包括滚动条移动的距离)。
         */
        getClientHeight: function() {
            var height = self.innerHeight; // Safari, Opera
            var mode = document.compatMode;
            if ( (mode || IE) && !Opera ) { // IE, Gecko
                height = (mode == 'CSS1Compat') ?
                        document.documentElement.clientHeight : // 标准
                        document.body.clientHeight; // IE 的怪异模式
            }
            return height;
        },
        
        /** @see #getClientWidth() */
        getViewportWidth: function() {return FUI.dom.getClientWidth();},
        
        /** @see #getClientHeight() */
        getViewportHeight: function() {return FUI.dom.getClientHeight();},
        
        /** @see #getClientWidth() */
        clientWidth: function() {return FUI.dom.getClientWidth();},
        
        /** @see #getClientHeight() */
        clientHeight: function() {return FUI.dom.getClientHeight();},
        
        /**
         * 获取<code>DOMDocument</code>对象。
         * 
         * @return {DOMDocument} 返回一个DOMDocument对象
         * @author Fuchun
         * @since FUI v 0.1.0
         */
        getDOMDocument: function() {
            if(window.ActiveXObject) { // Windows IE
                var xmlVersions = ["MSXML2.DOMDocument.3.0", "MSXML2.DOMDocument.4.0",
                                   "MSXML2.DOMDocument.5.0", "MSXML2.DOMDocument.6.0"];
                for(var i = xmlVersions.length; --i >= 0;) {
                    try {
                        var xmlDoc = new ActiveXObject(xmlVersions[i]);
                        return xmlDoc;
                    } catch(error) {
                    }
                }
                throw new Error("\u60a8\u7684\u7cfb\u7edf\u4e0d\u652f\u6301MSXML\uff01");
            } else if(document.implementation && document.implementation.createDocument) {
                var xmlDoc = document.implementation.createDocument("", "", null);
                xmlDoc.parseError = {
                    valueOf: function () { return this.errorCode; },
                    toString: function () { return this.errorCode.toString(); }
                };
                xmlDoc.__initError__();
                xmlDoc.addEventListener("load", function() {
                    this.__checkForErrors__();
                    this.__changeReadyState__(4);
                }, false);
                return xmlDoc;
            } else {
                throw new Error("\u4f60\u7684\u6d4f\u89c8\u5668\u4e0d\u652f\u6301XML DOMDocument\u5bf9\u8c61\uff01");
            }
        },
        
        /**
         * 给一个指定的HTMLSelectElement元素添加给定的选项(HTMLOptionElement)。
         * <pre>
         * <example>下面是四个简单的方法，给select元素动态添加Option选项</example>
         * var oSelect = document.getElementById('cmbCities');
         * FUI.dom.addOption(oSelect, [["上海市", "上海市"],["北京市", "北京市"]]);
         * FUI.dom.addOption(oSelect, ["上海市", "上海市"]);
         * // 如果text和value的值相同，则可以简写为： FUI.dom.addOption(oSelect, "上海市");
         * FUI.dom.addOption(oSelect, new Option("上海市", "上海市");
         * FUI.dom.addOption(oSelect, [new Option("上海市", "上海市"), new Option("北京市", "北京市")]);
         * </pre>
         *
         * @param {HTMLSelectElement} el 指定的HTMLSelectElement元素。
         * @param {Array|HTMLOptionElement} o 要添加到给定元素的一组HTMLOptionElement或者一个HTMLOptionElement
         */
        addOption: function(el, o) {
            if(FUI.isNull(el) || FUI.isUndefined(o)) return;
            if(el.tagName && el.tagName.toLowerCase() == 'select') {
                if(FUI.isArray(o)) {
                    for(var i = 0, len = o.length; i < len; i++) {
                        if(FUI.isString(o[i]) && !FUI.isNullOrEmpty(o[i])) {
                            __addOption__(el, new Option(o[i], o[i]));
                        } else if(FUI.isArray(o[i])) {
                            if(o[i][0] && o[i][1]) {
                                __addOption__(el, new Option(o[i][0], o[i][1]));
                            } else if(o[i][0] && !o[i][1]) {
                                __addOption__(el, new Option(o[i][0], o[i][0]));
                            }
                        } else if(!FUI.isUndefined(o[i].txt) && !FUI.isUndefined(o[i].val)) {
                            __addOption__(el, new Option(o[i].txt, o[i].val));
                        } else if(!FUI.isUndefined(o[i].text) && !FUI.isUndefined(o[i].value)) {
                            __addOption__(el, new Option(o[i].text, o[i].value));
                        }
                    }
                    return;
                }
                if(!FUI.isNullOrEmpty(o['text']) && !FUI.isUndefined(o['value'])) {
                    __addOption__(el, new Option(o.text, o.value));
                    return;
                }
                if(!FUI.isNullOrEmpty(o['txt']) && o['val']) {//只为向后兼容
                    __addOption__(el, new Option(o.txt, o.val));
                    return;
                }
                if(FUI.isString(o)) {
                    __addOption__(el, new Option(o, o));
                    return;
                }
            } else if(el.tagName && el.tagName.toLowerCase() == 'optgroup') {
                if(FUI.isArray(o)) {
                    for(var i = 0, len = o.length; i < len; i++) {
                        var opt = document.createElement('option');
                        if(FUI.isString(o[i]) && !FUI.isNullOrEmpty(o[i])) {
                            opt.appendChild(document.createTextNode(o[i]));
                            opt.setAttribute('value', o[i]);
                        } else if(FUI.isArray(o[i])) {
                            if(o[i][0] && o[i][1]) {
                                opt.appendChild(document.createTextNode(o[i][0]));
                                opt.setAttribute('value', o[i][1]);
                            } else if(o[i][0] && !o[i][1]) {
                                opt.appendChild(document.createTextNode(o[i][0]));
                                opt.setAttribute('value', o[i][0]);
                            }
                        } else if(o[i]['text'] && o[i]['value']) {
                            opt.appendChild(document.createTextNode(o[i].text));
                            opt.setAttribute('value', o[i].value);
                        } else if(o[i]['txt'] && o[i]['val']) {//只为向后兼容
                            opt.appendChild(document.createTextNode(o[i].txt));
                            opt.setAttribute('value', o[i].val);
                        }
                        el.appendChild(opt);
                    }
                    return;
                }
                var opt = document.createElement('option');
                if(!FUI.isUndefined(o.text) && !FUI.isUndefined(o.value)) {
                    opt.appendChild(document.createTextNode(o.text));
                    opt.setAttribute('value', o.value);
                } else if(!FUI.isUndefined(o.txt) && !FUI.isUndefined(o.val)) {
                    opt.appendChild(document.createTextNode(o.txt));
                    opt.setAttribute('value', o.val);
                } else if(FUI.isString(o)) {
                    opt.appendChild(document.createTextNode(o));
                    opt.setAttribute('value', o);
                } else {
                    throw new Error('');
                }
                el.appendChild(opt);
            }
        },
        
        /**
         * 从给定的HTMLSelectElement元素中移出指定条件的选项。
         * <pre>
         * <example>四种移出方法：</example>
         * // 假设 cmbCities 为select元素的ID
         * var oSelect = document.getElementById('cmbCities'); // 或者用jQuery库： $('#cmbCities')[0]
         * FUI.dom.removeOption(oSelect);                    // 移除oSelect中所有的选项
         * FUI.dom.removeOption(oSelect, 'value1');          // 移除oSelect中text或者value值等于 value1 的选项
         * FUI.dom.removeOption(oSelect, {text:'value1'});   // 移除oSelect中text等于 value1 的选项
         * FUI.dom.removeOption(oSelect, {value:'value1'});  // 移除oSelect中value等于 value1 的选项
         * FUI.dom.removeOption(oSelect, n);                 // 移除oSelect中索引为 n 的选项(n的值大于0小于oSelect的选项数)
         * </pre>
         *
         * @param {HTMLSelectElement} el 指定的HTMLSelectElement元素。
         * @param {String|Hash|Integer|null} o 要移除HTMLSelectElement元素中的HTMLOptionElement选项的条件。
         */
        removeOption: function(el, o) {
            if(FUI.isNull(el)) return;
            if(el.tagName && el.tagName.toLowerCase() == 'select') {
                if(FUI.isNull(o) || FUI.isUndefined(o)) { // 如果选项条件为null或者undefined，则移除全部HTMLOptionElement选项
                    el.options.length = 0;
                } else if(FUI.isString(o)) { // 如果选项条件为字符串，则移除HTMLOptionElement选项中text或者value的值为options的选项
                    for(var i = el.options.length; --i >= 0;) {
                        if(el.options[i].text == o || el.options[i].value == o) {
                            el.removeChild(el.options[i]);
                        }
                    }
                } else if(FUI.isNumber(o)) {
                    if(o > 0 && o < el.options.length) { el.removeChild(el.options[o]); }
                } else if(o.text && !o.value) {
                    for(var i = el.options.length; --i >= 0;) {
                        if(el.options[i].text == o.text) { el.removeChild(el.options[i]) }
                    }
                } else if(!o.text && o.value) {
                    for(var i = el.options.length; --i >= 0;) {
                        if(el.options[i].value == o.value) { el.removeChild(el.options[i]) }
                    }
                } else if(o.text && o.value) {
                    for(var i = el.options.length; --i >= 0;) {
                        if(el.options[i].text == o.text && el.options[i].value == o.value) { el.removeChild(el.options[i]) }
                    }
                }
            }
        },
        
        /**
         * 在给定的HTMLSelectElement元素中选中附合条件的选项。若附合的选项有多个，则选中第一个。
         * <pre>
         * 若 o 为String,则该方法将先去遍历给定的HTMLSelectElement元素的选项的 value 值，
         * 看是否等于 o，有相等的则匹配；若无相等的值，则再遍历选项的 text 值，看是否匹配。
         * 若要提高效率，请选择 Hash 来匹配。
         * var oSelect = document.getElementById('cmbCities');
         * FUI.dom.selectOption(oSelect, {text:'上海市'}); // 选中选项中 text 值为 上海市 的选项
         * FUI.dom.selectOption(oSelect, {value:'上海市'}); // 选中选项中 value 值为 上海市 的选项
         * FUI.dom.selectOption(oSelect, {text:'上海市', value:'ShangHai'});
         * // 选中选项中 text 值为 上海市 value 值为 ShangHai 的选项。
         * </pre>
         *
         * @param {HTMLSelectElement} el 指定的HTMLSelectElement元素。
         * @param {String|Hash} o 要选中的选项的条件。
         */
        selectOption: function(el, o) {
            if(el === null || !el.options) { return false; }
            if(el.tagName && el.tagName.toLowerCase() == 'select') {
                if(FUI.isString(o)) {
                    for(var i = 0; i < el.length; i++) {
                        if(el.options[i].value === o) {
                            el.options[i].selected = 'selected';
                            return;
                        }
                    }
                    for(var i = 0; i < el.options.length; i++) {
                        if(el.options[i].text === o) {
                            el.options[i].selected = 'selected';
                            return;
                        }
                    }
                } else if(o.text && FUI.isUndefined(o.value)) {
                    for(var i = 0; i < el.length; i++) {
                        if(el.options[i].text == o.text) {
                            el.options[i].selected = 'selected';
                            return;
                        }
                    }
                } else if(o.value && FUI.isUndefined(o.text)) {
                    for(var i = 0; i < el.length; i++) {
                        if(el.options[i].value == o.value) {
                            el.options[i].selected = 'selected';
                            return;
                        }
                    }
                } else if(o.text && !FUI.isUndefined(o.value)) {
                    for(var i = 0; i < el.length; i++) {
                        if(el.options[i].text == o.text && el.options[i].value == o.value) {
                            el.options[i].selected = 'selected';
                            return;
                        }
                    }
                }
            }
        }
    };
    
    if( window.$dom ) var _dom = window.$dom;
    window.$dom = FUI.dom;
    
    /** 扩展jQuery的DOM操作方法 */
    jQuery.fn.extend({
        
        /** 获得指定的CSS属性的值 */
        getStyle: function(prop) {
            return this.length ? getStyle(this[0], toCamel(prop)) : null;
        },
        
        /** 设置指定的CSS属性 */
        setStyle: function(prop, val) {
            this.each(function() { setStyle(this, toCamel(prop), val); });
        },
        
        /** 获取第一个匹配元素当前的(相对于document)绝对坐标值 [x, y] */
        getXY: function() {
            var el = this.length ? this[0] : null;
            if(el == null) return false;
            if((el.parentNode == null || el.offsetParent == null ||
                    jQuery(el).getStyle('display') == 'none') && el != document.body) {
                return false;
            }
            var parentNode = null;
            var pos = [];
            var box;
            var doc = el.ownerDocument;
            if(el.getBoundingClientRect) { // IE 浏览器
                box = el.getBoundingClientRect();
                return [box.left + FUI.dom.scrollLeft(el.ownerDocument), 
                        box.top + FUI.dom.scrollTop(el.ownerDocument)];
            } else { // Safari, Opera, & Mozilla 浏览器
                pos = [el.offsetLeft, el.offsetTop];
                parentNode = el.offsetParent;
                var hasAbs = jQuery(el).getStyle('position') == 'absolute';
                if (parentNode != el) {
                    while (parentNode) {
                        pos[0] += parentNode.offsetLeft;
                        pos[1] += parentNode.offsetTop;
                        if (Safari && !hasAbs && 
                                jQuery(parentNode).getStyle('position') == 'absolute' ) {
                            hasAbs = true;
                        }
                        parentNode = parentNode.offsetParent;
                    }
                }
                if (Safari && hasAbs) { //safari doubles in this case
                    pos[0] -= el.ownerDocument.body.offsetLeft;
                    pos[1] -= el.ownerDocument.body.offsetTop;
                }
            }
            parentNode = el.parentNode;
            while ( parentNode.tagName && !patterns.ROOT_TAG.test(parentNode.tagName) ) 
            {
               if (jQuery(parentNode).getStyle('display').search(/^inline|table-row.*$/i)) { 
                    pos[0] -= parentNode.scrollLeft;
                    pos[1] -= parentNode.scrollTop;
                }
                parentNode = parentNode.parentNode; 
            }
            return pos;
        },
        
        /** 获取第一个匹配元素当前的(相对于document)绝对横坐标(x)值 */
        getX: function() { return this.getXY()[0]; },
        
        /** 获取第一个匹配元素当前的(相对于document)绝对纵坐标(y)值 */
        getY: function() { return this.getXY()[1]; },
        
        /** 设置所有匹配元素的绝对坐标值 pos = [x, y] */
        setXY: function(pos, noRetry) {
            this.each(function() {
                var el = this;
                var stylePosition = jQuery(el).getStyle("position");
                if(stylePosition == "static") { // 默认为relative
                    jQuery(el).setStyle("position", "relative");
                    stylePosition = "relative";
                }
                var elementXY = jQuery(el).getXY();
                if(elementXY == false) { return false; }
                var delta = [
                    parseInt(jQuery(el).getStyle("left"), 10),
                    parseInt(jQuery(el).getStyle("top"), 10)
                ];
                if(isNaN(delta[0])) { delta[0] = (stylePosition == "relative") ? 0 : el.offsetLeft; }
                if(isNaN(delta[1])) { delta[1] = (stylePosition == "relative") ? 0 : el.offsetTop; }
                if(pos[0] !== null) { el.style.left = pos[0] - elementXY[0] + delta[0] + "px"; }
                if(pos[1] !== null) { el.style.top  = pos[1] - elementXY[1] + delta[1] + "px"; }
                if(!noRetry) {
                    var newXY = jQuery(el).getXY();
                    if((pos[0] !== null && newXY[0] !== pos[0]) ||
                            (pos[1] !== null && newXY[1] !== pos[1])) {
                        jQuery(el).setXY(pos, true);
                    }
                }
            });
        },
        
        /** 设置第一个匹配元素的绝对横坐标(x)值 */
        setX: function(x) { this.setXY([x, null]); },
        
        /** 设置第一个匹配元素的绝对横坐标(y)值 */
        setY: function(y) { this.setXY([null, y]); },
        
        /**
         * 为HTMLSelectElement元素添加HTMLOptGroupElement标签。（只适用于Select标签的元素）
         *
         * @param {String} o OptGroupElement的Label属性
         */
        addOptGroup: function(o,oid) {
            if(FUI.isNullOrEmpty(o)) return;
            var self = this.length ? this[0] : null;
            if(FUI.isNull(self)) throw new Error('((((ERROR)))) - It is not HTMLSelectElement!');
            if(self.tagName && self.tagName.toLowerCase() == 'select') {
                var optg = document.createElement('optgroup');
                optg.setAttribute('label', o);
                if(!FUI.isUndefined(oid)) optg.setAttribute('id', oid);
                this[0].appendChild(optg);
                return optg;
            }
        },
        
        /**
         * 为HTMLSelectElement元素添加HTMLOptionElement选项。（只适用于Select标签的元素）
         *
         * @param {Array|HTMLOptionElement} o 要添加到给定元素的一组HTMLOptionElement或者一个HTMLOptionElement
         * @see FUI.dom.addOption(HTMLSelectElement, {any})
         */
        addOption: function(o) {
            return this.each(function() { FUI.dom.addOption(this, o); });
        },
        
        /**
         * 从给定的HTMLSelectElement元素中移出指定条件的选项。（只适用于Select标签的元素）
         *
         * @param {String|Hash|Integer|null} o 要移除HTMLSelectElement元素中的HTMLOptionElement选项的条件。
         * @see FUI.dom.removeOption(HTMLSelectElement, {any})
         */
        removeOption: function(o) {
            if(FUI.isString(o) && o==='_all') {
                return this.each(function() {
                    if(!FUI.isUndefined(this.tagName)) {
                        if(this.tagName.toLowerCase() == 'select') {
                            this.options.length = 0;
                            $(this).empty();
                        }
                    }
                });
            }
            return this.each(function() { FUI.dom.removeOption(this, o); });
        },
        
        /**
         * 在给定的HTMLSelectElement元素中选中附合条件的选项。若附合的选项有多个，则选中第一个。（只适用于Select标签的元素）
         *
         * @param {String|Hash|Integer|null} o 要移除HTMLSelectElement元素中的HTMLOptionElement选项的条件。
         * @see FUI.dom.removeOption(HTMLSelectElement, {any})
         */
        selectOption: function(o) {
            return this.each(function() { FUI.dom.selectOption(this, o); });
        },
        
        /** 清除给定的HTMLSelectElement元素中的所有选项。*/
        clearOption: function(o) {
            return this.each(function() {
                if(!FUI.isUndefined(this.tagName)) {
                    if(this.tagName.toLowerCase() == 'select') {
                        this.options.length = 0;
                        $(this).empty();
                    }
                }
            });
        }
    });
    
    FUI.fn = $.extend(FUI.fn, {
    
        /** 常用验证函数 */
        valid: {
            len: function(s) { // 计算字符串长度（按UTF-8编码计算）
                var length = 0;
                for(var i = 0; i < s.length; i++) {
                    length = ( s.charCodeAt(i) > 128 ) ? length + 3 : length + 1; }
                return length;
            },
            
            /** 替换危险脚本 */
            replaceScript: function(o) {
                if(o.val().indexOf('\u003C') > 0 || o.val().indexOf('\u003E') > 0
                        || o.val().indexOf('\u002F')) {
                    o.val(o.val().replace(/[<>]/ig, ''));
                }
            }
        },
        
        /** 计算给定字符串的长度，其中所有全角字符占3位长度。*/
        length: function(s) {
            if(FUI.isUndefined(s) || FUI.isNullOrEmpty(s)) return 0;
            var temp = s.toString();
            return s.replace(/[^\x00-xFF]/g,'***').length;
        },
        
        /** 验证Email的格式 */
        isEmail: function(s) {
            var re = /(\w+@\w+\.\w+)(\.{0,1}\w*)(\.{0,1}\w*)/i, email;
            re.exec(s);
            if (RegExp.$3!=""&&RegExp.$3!="."&&RegExp.$2!=".")
                email = RegExp.$1 + RegExp.$2 + RegExp.$3;
            else {
                if(RegExp.$2!="" && RegExp.$2!=".") email=RegExp.$1+RegExp.$2;
                else email=RegExp.$1;
            }
            if(email != s) { return false; }
            return true;
        },
        
        /** 分析给定的DOMDocument对象，返回Hash对象。 */
        data: function(xmlDoc) {
            var rs = {state:'', message:'', value:''};
            if(FUI.isUndefined(xmlDoc) || FUI.isString(xmlDoc)) return rs;
            var oInfo = $xpath.findNode(xmlDoc.documentElement, '//messages', null);
            if(oInfo !== null) {
                rs.state = FUI.xml.attr(oInfo, 'state');
                rs.message  = FUI.xml.attr(oInfo, 'message');
                rs.value = FUI.xml.attr(oInfo, 'value');
            }
            return rs;
        },
        
        /** 初始化页面的所有链接。通常于Ajax载入页面完成时，或页面加载完时调用。 */
        anchor: function() {
            if(!document.getElementsByTagName) return;
            var anchor, anchors = document.getElementsByTagName("a");
            for(var i = 0, len = anchors.length; i < len; i++) {
                anchor = anchors[i];
                if(anchor.getAttribute("href") && anchor.getAttribute("rel") == "external")
                    anchor.target = "_blank";
            }
        },
        
        /**
         * 基于CSS+DIV的提示工具。
         * 
         * @param {Event} ev 事件
         * @param {String} pos 生成的提示框位于鼠标或者事件触发的方位（tl-左上角、tr-右上角、bl-左下角、br-右下角）
         * @param {Hash} options 提示工具的实施参数
         */
        tooltip: function(ev, pos, options) {
            ev = window.event || ev;
            el = jQuery(ev.srcElement || ev.target);
            if(FUI.isUndefined(pos)) pos = 'bl';
            var elpos = [el.getX(), el.getY()]; // 事件元素的绝对坐标
            
            options = options || {};
            if(ev.type == 'mouseover' || ev.type == 'mousemove') {
                var mspos = [ev.clientX + FUI.dom.scrollLeft(), ev.clientY + FUI.dom.scrollTop()];
                var tw,tt,ttwrap;
                var ttpos = [0, 0];
                var tipcontent = '';
                if(jQuery('#tooltip_'+el.attr('id')).length > 0) {
                    ttwrap = jQuery('#tooltip_'+el.attr('id'));
                    tt = ttwrap.children('.tooltip');
                    tipcontent = tt.html();
                } else {
                    if(FUI.isNullOrEmpty(el.attr('title'))) return;
                    else {tipcontent = el.attr('title');el.removeAttr('title');}
                    ttwrap = jQuery('<div id="tooltip_'+el.attr('id')+'" class="toolwrap"></div>');
                    tw = jQuery('<div class="toolway">&nbsp;</div>');
                    tt = jQuery('<div class="tooltip"></div>');
                    if(pos == 'tl') {
                        tw.addClass('tw_t_l');
                        tt.html(tipcontent).addClass('tt_t_l');
                    } else if(pos == 'tr') {
                        tw.addClass('tw_t_r');
                        tt.html(tipcontent).addClass('tt_t_r');
                    } else if(pos == 'bl') {
                        tw.addClass('tw_b_l');
                        tt.html(tipcontent).addClass('tt_b_l');
                    } else {
                        tw.addClass('tw_b_r');
                        tt.html(tipcontent).addClass('tt_b_r');
                    }
                    ttwrap.append(tw[0]);
                    ttwrap.append(tt[0]);
                    ttwrap.append(tw[0]).append(tt[0]);
                    ttwrap.appendTo('body')[0];
                }
                
                if($fn.length(tipcontent) > 60) {
                    ttwrap.css({width:'300px',minWidth:'300px'});
                    tt.css({width:'300px',minWidth:'300px'});
                } else {
                    ttwrap.css({width:'100px', minWidth:'100px'});
                    tt.css({width:'100px',minWidth:'100px'});
                }
                // 定位提示框
                if(pos == 'tl') {
                    ttpos = [mspos[0] - 10, mspos[1] + 20];
                } else if(pos == 'tr') {
                    ttpos = [mspos[0] + ttwrap.width(), mspos[1] + 20];
                } else if(pos == 'bl') {
                    ttpos = [mspos[0] - 10, mspos[1] - ttwrap.height() - 10];
                } else if(pos == 'br') {
                    ttpos = [mspos[0] - ttwrap.width(), mspos[1] - ttwrap.height() - 20];
                }
                ttwrap.setXY(ttpos);
                ttwrap.show();
            } else if(ev.type == 'mouseout') {
                jQuery('#tooltip_'+el.attr('id')).hide();
            }
        }
    });
    
    window.$util = FUI.util = $.extend(FUI.util, {
		checkAll: function(o){
			$.each($("input[name="+o+"]"), function(){
		 		this.checked = true;
		 	});
		},
		checkReverse: function(o){
			$.each($("input[name="+o+"]"), function(){
				if(this.checked)
		 			this.checked = false;
		 		else
		 			this.checked = true;
		 	});
		},
		cancelCheck: function(o){
			$.each($("input[name="+o+"]"), function(){
				this.checked = false;
		 	});
		},
		checkedNum: function(o){
			var num = 0;
			$.each($("input[name="+o+"]"), function(){
				if(this.checked)
					num += 1;
		 	});
		 	return num;
		}
    });

})(jQuery);