    	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,
                // 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) {
                var related = e.relatedTarget,
                    isXulEl = Object.prototype.toString.apply(related) == '[object XULElement]';
                if (!related) return false;
                return (!isXulEl && related != this && this.tag != 'document' && !elContains(this, related));
            }

            function elContains(parent, child) {
                while(child) {
                    if(child === parent) {
                        return true;
                    }
                    try {
                        child = child.parentNode;
                    } catch(e) {
                        // In FF if you mouseout an text input element
                        // thats inside a div sometimes it randomly throws
                        // Permission denied to get property HTMLDivElement.parentNode
                        // See https://bugzilla.mozilla.org/show_bug.cgi?id=208427
                        return false;
                    }
                    if(child && (child.nodeType != 1)) {
                        child = null;
                    }
                }
                return false;
            }

            // private
            function _getCacheIndex(el, eventName, fn) {
                var index = -1;
                Ext.each(listeners, function (v,i) {
    	            if(v && v[FN] == fn && v[EL] == el && v[TYPE] == eventName) {
    		            index = i;
    	            }
                });
                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(item);
    		            	}
    	            	}
                    });

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

                    if (tryAgain) {
                        startInterval();
                    } else {
                        clearInterval(_interval);
                        _interval = null;
                    }

                    ret = !(locked = false);
    			}
    			return ret;
            }

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

            // private
            function getScroll() {
                var scroll = Ext.get(doc).getScroll();
                return [scroll.top, scroll.top];
            }

            // private
            function getPageCoord (ev, xy) {
                ev = ev.browserEvent || ev;
                var coord  = ev['page' + xy];
                if (!coord && 0 != coord) {
                    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 = this.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] == evantName && 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 : function(node) {
                    return Ext.isSafari && node && 3 == node.nodeType ? node.parentNode : node;
                },

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

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

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

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

    // 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) {
                        doRemove(win, "load", EU._load);
                    }
                },

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

                    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 = [listeners, unloadListeners];

    				if (eventName) {
    					searchLists.splice(eventName == "unload" ? 0 : 1 ,1);
    				} else {
    					searchLists = searchLists[0].concat(searchLists[1]);
    				}

    				Ext.each(searchLists, function(v, i){
    					if (v && v[me.EL] == el && (!eventName || eventName == v[me.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) {
    						scope =  v[ADJ_SCOPE] ? (v[ADJ_SCOPE] === true ? v[OBJ] : v[ADJ_SCOPE]) :  win;
    						v[FN].call(scope, EU.getEvent(e), v[OBJ]);
    					}
    				});

                    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();
    	    } else {
    	        doAdd(win, "load", pub._load);
    	    }
    	    doAdd(win, "unload", pub._unload);
    	    _tryPreloadAttach();

            return pub;
        }();