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

            // constants
            POLL_RETRYS = 200,
            POLL_INTERVAL = 20,
            EL = 0,
            TYPE = 1,
            FN = 2,
            WFN = 3,
            OBJ = 3,
            ADJ_SCOPE = 4,
            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 _getCacheIndex(el, eventName, fn) {
            for(var v, index = -1, len = listeners.length, i = len - 1; i >= 0; --i){
                v = listeners[i];
                if (v && v[FN] == fn && v[EL] == el && v[TYPE] == eventName) {
                    index = i;
                    break;
                }
            }
            return index;
        }

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

            if (!locked) {
                locked = true;

                Ext.each(onAvailStack, function (v,i,a){
                    if(v && (element = doc.getElementById(v.id))){
                        if(!v.checkReady || loadComplete || element.nextSibling || (doc && doc.body)) {
                            element = v.override ? (v.override === true ? v.obj : v.override) : element;
                            v.fn.call(element, v.obj);
                            onAvailStack[i] = null;
                        } 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 =  {
            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();
            },

            addListener: function(el, eventName, fn) {
                var ret;
                el = Ext.getDom(el);
                if (el && fn) {
                    if (UNLOAD == eventName) {
                        ret = !!(unloadListeners[unloadListeners.length] = [el, eventName, fn]);
                    } else {
                        listeners.push([el, eventName, fn, ret = doAdd(el, eventName, fn, false)]);
                    }
                }
                return !!ret;
            },

            removeListener: function(el, eventName, fn) {
                var ret = false,
                    index,
                    cacheItem;

                el = Ext.getDom(el);

                if(!fn) {
                    ret = this.purgeElement(el, false, eventName);
                } else if (UNLOAD == eventName) {
                    Ext.each(unloadListeners, function(v, i, a) {
                        if( v && v[0] == el && v[1] == eventName && v[2] == fn) {
                            unloadListeners.splice(i, 1);
                            ret = true;
                        }
                    });
                } else {
                    index = arguments[3] || _getCacheIndex(el, eventName, fn);
                    cacheItem = listeners[index];

                    if (el && cacheItem) {
                        doRemove(el, eventName, cacheItem[WFN], false);
                        cacheItem[WFN] = cacheItem[FN] = null;
                        listeners.splice(index, 1);
                        ret = true;
                    }
                }
                return ret;
            },

            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 ||
                        (ev.type == MOUSEOUT ? ev.toElement :
                         ev.type == MOUSEOVER ? 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)];
            },

    // Is this useful?  Removing to save space unless use case exists.
    //             getTime: function(ev) {
    //                 ev = ev.browserEvent || ev;
    //                 if (!ev.time) {
    //                     var t = new Date().getTime();
    //                     try {
    //                         ev.time = t;
    //                     } catch(ex) {
    //                         return t;
    //                     }
    //                 }

    //                 return ev.time;
    //             },

            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() {},

            _load : function(e) {
                loadComplete = true;
                var EU = Ext.lib.Event;
                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);
                }
            },

            purgeElement : function(el, recurse, eventName) {
                var me = this;
                Ext.each( me.getListeners(el, eventName), function(v){
                    if(v){
                        me.removeListener(el, v.type, v.fn, v.index);
                    }
                });

                if (recurse && el && el.childNodes) {
                    Ext.each(el.childNodes, function(v){
                        me.purgeElement(v, recurse, eventName);
                    });
                }
            },

            getListeners : function(el, eventName) {
                var me = this,
                    results = [],
                    searchLists;

                if (eventName){
                    searchLists = eventName == UNLOAD ? unloadListeners : listeners;
                }else{
                    searchLists = listeners.concat(unloadListeners);
                }

                Ext.each(searchLists, function(v, i){
                    if (v && v[EL] == el && (!eventName || eventName == v[TYPE])) {
                        results.push({
                                    type:   v[TYPE],
                                    fn:     v[FN],
                                    obj:    v[OBJ],
                                    adjust: v[ADJ_SCOPE],
                                    index:  i
                                });
                    }
                });

                return results.length ? results : null;
            },

            _unload : function(e) {
                 var EU = Ext.lib.Event,
                    i,
                    j,
                    l,
                    len,
                    index,
                    scope;

                Ext.each(unloadListeners, function(v) {
                    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){}
                    }
                });

                unloadListeners = null;

                if(listeners && (j = listeners.length)){
                    while(j){
                        if((l = listeners[index = --j])){
                            EU.removeListener(l[EL], l[TYPE], l[FN], index);
                        }
                    }
                    //EU.clearCache();
                }

                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;
    }();