    /*!
     * Ext JS Library 3.3.0
     * Copyright(c) 2006-2010 Ext JS, Inc.
     * licensing@extjs.com
     * http://www.extjs.com/license
     */
    Ext.lib.Event = function() {
        var loadComplete = false,
            unloadListeners = {},
            retryCount = 0,
            onAvailStack = [],
            _interval,
            locked = false,
            win = window,
            doc = document,

            // constants
            POLL_RETRYS = 200,
            POLL_INTERVAL = 20,
            TYPE = 0,
            FN = 1,
            OBJ = 2,
            ADJ_SCOPE = 3,
            SCROLLLEFT = 'scrollLeft',
            SCROLLTOP = 'scrollTop',
            UNLOAD = 'unload',
            MOUSEOVER = 'mouseover',
            MOUSEOUT = 'mouseout',
            // private
            doAdd = function() {
                var ret;
                if (win.addEventListener) {
                    ret = function(el, eventName, fn, capture) {
                        if (eventName == 'mouseenter') {
                            fn = fn.createInterceptor(checkRelatedTarget);
                            el.addEventListener(MOUSEOVER, fn, (capture));
                        } else if (eventName == 'mouseleave') {
                            fn = fn.createInterceptor(checkRelatedTarget);
                            el.addEventListener(MOUSEOUT, fn, (capture));
                        } else {
                            el.addEventListener(eventName, fn, (capture));
                        }
                        return fn;
                    };
                } else if (win.attachEvent) {
                    ret = function(el, eventName, fn, capture) {
                        el.attachEvent("on" + eventName, fn);
                        return fn;
                    };
                } else {
                    ret = function(){};
                }
                return ret;
            }(),
            // private
            doRemove = function(){
                var ret;
                if (win.removeEventListener) {
                    ret = function (el, eventName, fn, capture) {
                        if (eventName == 'mouseenter') {
                            eventName = MOUSEOVER;
                        } else if (eventName == 'mouseleave') {
                            eventName = MOUSEOUT;
                        }
                        el.removeEventListener(eventName, fn, (capture));
                    };
                } else if (win.detachEvent) {
                    ret = function (el, eventName, fn) {
                        el.detachEvent("on" + eventName, fn);
                    };
                } else {
                    ret = function(){};
                }
                return ret;
            }();

        function checkRelatedTarget(e) {
            return !elContains(e.currentTarget, pub.getRelatedTarget(e));
        }

        function elContains(parent, child) {
           if(parent && parent.firstChild){
             while(child) {
                if(child === parent) {
                    return true;
                }
                child = child.parentNode;
                if(child && (child.nodeType != 1)) {
                    child = null;
                }
              }
            }
            return false;
        }

        // private
        function _tryPreloadAttach() {
            var ret = false,
                notAvail = [],
                element, i, v, override,
                tryAgain = !loadComplete || (retryCount > 0);

            if(!locked){
                locked = true;

                for(i = 0; i < onAvailStack.length; ++i){
                    v = onAvailStack[i];
                    if(v && (element = doc.getElementById(v.id))){
                        if(!v.checkReady || loadComplete || element.nextSibling || (doc && doc.body)) {
                            override = v.override;
                            element = override ? (override === true ? v.obj : override) : element;
                            v.fn.call(element, v.obj);
                            onAvailStack.remove(v);
                            --i;
                        }else{
                            notAvail.push(v);
                        }
                    }
                }

                retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;

                if (tryAgain) {
                    startInterval();
                } else {
                    clearInterval(_interval);
                    _interval = null;
                }
                ret = !(locked = false);
            }
            return ret;
        }

        // private
        function startInterval() {
            if(!_interval){
                var callback = function() {
                    _tryPreloadAttach();
                };
                _interval = setInterval(callback, POLL_INTERVAL);
            }
        }

        // private
        function getScroll() {
            var dd = doc.documentElement,
                db = doc.body;
            if(dd && (dd[SCROLLTOP] || dd[SCROLLLEFT])){
                return [dd[SCROLLLEFT], dd[SCROLLTOP]];
            }else if(db){
                return [db[SCROLLLEFT], db[SCROLLTOP]];
            }else{
                return [0, 0];
            }
        }

        // private
        function getPageCoord (ev, xy) {
            ev = ev.browserEvent || ev;
            var coord  = ev['page' + xy];
            if (!coord && coord !== 0) {
                coord = ev['client' + xy] || 0;

                if (Ext.isIE) {
                    coord += getScroll()[xy == "X" ? 0 : 1];
                }
            }

            return coord;
        }

        var pub =  {
            extAdapter: true,
            onAvailable : function(p_id, p_fn, p_obj, p_override) {
                onAvailStack.push({
                    id:         p_id,
                    fn:         p_fn,
                    obj:        p_obj,
                    override:   p_override,
                    checkReady: false });

                retryCount = POLL_RETRYS;
                startInterval();
            },

            // This function should ALWAYS be called from Ext.EventManager
            addListener: function(el, eventName, fn) {
                el = Ext.getDom(el);
                if (el && fn) {
                    if (eventName == UNLOAD) {
                        if (unloadListeners[el.id] === undefined) {
                            unloadListeners[el.id] = [];
                        }
                        unloadListeners[el.id].push([eventName, fn]);
                        return fn;
                    }
                    return doAdd(el, eventName, fn, false);
                }
                return false;
            },

            // This function should ALWAYS be called from Ext.EventManager
            removeListener: function(el, eventName, fn) {
                el = Ext.getDom(el);
                var i, len, li, lis;
                if (el && fn) {
                    if(eventName == UNLOAD){
                        if((lis = unloadListeners[el.id]) !== undefined){
                            for(i = 0, len = lis.length; i < len; i++){
                                if((li = lis[i]) && li[TYPE] == eventName && li[FN] == fn){
                                    unloadListeners[el.id].splice(i, 1);
                                }
                            }
                        }
                        return;
                    }
                    doRemove(el, eventName, fn, false);
                }
            },

            getTarget : function(ev) {
                ev = ev.browserEvent || ev;
                return this.resolveTextNode(ev.target || ev.srcElement);
            },

            resolveTextNode : Ext.isGecko ? function(node){
                if(!node){
                    return;
                }
                // work around firefox bug, https://bugzilla.mozilla.org/show_bug.cgi?id=101197
                var s = HTMLElement.prototype.toString.call(node);
                if(s == '[xpconnect wrapped native prototype]' || s == '[object XULElement]'){
                    return;
                }
                return node.nodeType == 3 ? node.parentNode : node;
            } : function(node){
                return node && node.nodeType == 3 ? node.parentNode : node;
            },

            getRelatedTarget : function(ev) {
                ev = ev.browserEvent || ev;
                return this.resolveTextNode(ev.relatedTarget ||
                    (/(mouseout|mouseleave)/.test(ev.type) ? ev.toElement :
                     /(mouseover|mouseenter)/.test(ev.type) ? ev.fromElement : null));
            },

            getPageX : function(ev) {
                return getPageCoord(ev, "X");
            },

            getPageY : function(ev) {
                return getPageCoord(ev, "Y");
            },

            getXY : function(ev) {
                return [this.getPageX(ev), this.getPageY(ev)];
            },

            stopEvent : function(ev) {
                this.stopPropagation(ev);
                this.preventDefault(ev);
            },

            stopPropagation : function(ev) {
                ev = ev.browserEvent || ev;
                if (ev.stopPropagation) {
                    ev.stopPropagation();
                } else {
                    ev.cancelBubble = true;
                }
            },

            preventDefault : function(ev) {
                ev = ev.browserEvent || ev;
                if (ev.preventDefault) {
                    ev.preventDefault();
                } else {
                    ev.returnValue = false;
                }
            },

            getEvent : function(e) {
                e = e || win.event;
                if (!e) {
                    var c = this.getEvent.caller;
                    while (c) {
                        e = c.arguments[0];
                        if (e && Event == e.constructor) {
                            break;
                        }
                        c = c.caller;
                    }
                }
                return e;
            },

            getCharCode : function(ev) {
                ev = ev.browserEvent || ev;
                return ev.charCode || ev.keyCode || 0;
            },

            //clearCache: function() {},
            // deprecated, call from EventManager
            getListeners : function(el, eventName) {
                Ext.EventManager.getListeners(el, eventName);
            },

            // deprecated, call from EventManager
            purgeElement : function(el, recurse, eventName) {
                Ext.EventManager.purgeElement(el, recurse, eventName);
            },

            _load : function(e) {
                loadComplete = true;

                if (Ext.isIE && e !== true) {
                    // IE8 complains that _load is null or not an object
                    // so lets remove self via arguments.callee
                    doRemove(win, "load", arguments.callee);
                }
            },

            _unload : function(e) {
                 var EU = Ext.lib.Event,
                    i, v, ul, id, len, scope;

                for (id in unloadListeners) {
                    ul = unloadListeners[id];
                    for (i = 0, len = ul.length; i < len; i++) {
                        v = ul[i];
                        if (v) {
                            try{
                                scope = v[ADJ_SCOPE] ? (v[ADJ_SCOPE] === true ? v[OBJ] : v[ADJ_SCOPE]) :  win;
                                v[FN].call(scope, EU.getEvent(e), v[OBJ]);
                            }catch(ex){}
                        }
                    }
                };

                Ext.EventManager._unload();

                doRemove(win, UNLOAD, EU._unload);
            }
        };

        // Initialize stuff.
        pub.on = pub.addListener;
        pub.un = pub.removeListener;
        if (doc && doc.body) {
            pub._load(true);
        } else {
            doAdd(win, "load", pub._load);
        }
        doAdd(win, UNLOAD, pub._unload);
        _tryPreloadAttach();

        return pub;
    }();