// This must be the first script file (except for the optional debug library)
// Dependencies: none
// Note: This file should only be downloaded by Mozilla or Opera
//   If you can't exclude this file via server processing, it can be included using
//   a conditional comment such as:
//	<![if !IE]><script src="AtlasCompat.js"></script><![endif]>


var CompatVersion = "8.070705.0";

// Need more robust checks

new function()
{
	var _isSafari = (navigator.userAgent.indexOf("WebKit")>=0);
	var _isOpera = window.opera!=null;
	var _isMozilla = (navigator.userAgent.indexOf("Mozilla")>=0) && (!_isOpera) && (!_isSafari);
    var intID = 0;	

    window.$Browser = 
    {
	    isMozilla : function()
	    {
    		return _isMozilla;
    	},

	    isOpera : function()
	    {
    		return _isOpera;
    	},
	
	    isSafari : function()
	    {
	        return _isSafari;
	    },
        attachEventCompatibility : function(w)
        {
            //cv
            var xulProto = w.XULElement.prototype;
            
            var elementProto = w.HTMLElement.prototype;
        
            function GenWindowEvent(e) {
	            window.event = e; 
            }	
        	
            $Browser.Button = {LEFT:0,RIGHT:2,MIDDLE:1};
            function Map(el,mozillaType, callback)
            {
	            var strMozillaType = mozillaType.slice(2);
	            if (strMozillaType=="mousewheel")
	            {
		            strMozillaType = "DOMMouseScroll";
	            }
	            if (strMozillaType!="mouseenter" && strMozillaType!="mouseleave")
	            {
		            el.addEventListener(strMozillaType, GenWindowEvent, true); // Grab events first to establish window object
	            }
	            else // Simulate events
	            {
		            el.addEventListener("mouseover", GenWindowEvent, true); // Grab events first to establish window object
		            el.addEventListener("mouseout", GenWindowEvent, true); // Grab events first to establish window object
		            el.addEventListener("mouseover",CheckEnter,false);
		            el.addEventListener("mouseout",CheckLeave,false);
	            }
	            el.addEventListener(strMozillaType, callback, false);		// Hook the actual event		
            }
        	
            // NOTE - the "event.type" property will return mouseover instead of mouseenter for firefox
            function CheckEnter(ev)
            {
	            if (!this.contains(ev.fromElement))
	            {
		            var oEvent = document.createEvent("MouseEvents");
		            oEvent.initEvent("mouseenter",false,false);
		            this.dispatchEvent(oEvent);
	            }
            }

            // NOTE - the "event.type" property will return mouseout instead of mouseleave for firefox	
            function CheckLeave(ev)
            {
	            if (!this.contains(ev.toElement))
	            {
		            var oEvent = document.createEvent("MouseEvents");
		            oEvent.initEvent("mouseleave",false,false);
		            this.dispatchEvent(oEvent)
	            }
            }

            function RemoveMap(el,mozillaType,callback)
            {
	            var strMozillaType = mozillaType.slice(2)
	            if (mozillaType=="mousewheel")
	            {
		            strMozillaType = "DOMMouseScroll";
	            }
	            el.removeEventListener(strMozillaType, callback, false);
            }

            w.attachEvent = w.HTMLDocument.prototype.attachEvent = elementProto.attachEvent = function (type, callback) {Map(this,type,callback);return true;}
            w.detachEvent = w.HTMLDocument.prototype.detachEvent = elementProto.detachEvent = function (type, callback) {RemoveMap(this,type,callback);return true;}
            //cv
            xulProto.attachEvent = elementProto.attachEvent;
            w.XULDocument.prototype.attachEvent = xulProto.attachEvent;
            xulProto.detachEvent = elementProto.detachEvent;
            w.XULDocument.prototype.detachEvent = xulProto.detachEvent;
        },
        attachStyleCompatibility : function(w)
        {
            var cssProto = w.CSSStyleDeclaration.prototype;
            var elementProto = w.HTMLElement.prototype;


            function currentStyle(el)
            {
	            // Extend this if additional CurrentStyle properties are required
	            var PropertyList = new Array("Top","Left","Right","Bottom");
	            var cs = document.defaultView.getComputedStyle(el,null);
	            for (var i=0;i<PropertyList.length;i++)
	            {
		            var p = PropertyList[i]
		            this["border" + p + "Width"] = cs.getPropertyValue("border-" + p + "-width")
		            this["margin" + p] = cs.getPropertyValue("margin-" + p)
		            this["padding" + p] = cs.getPropertyValue("padding-" + p)
	            }
	            this["position"] = cs.getPropertyValue("position");
	            this["height"] = cs.getPropertyValue("height");
	            this["width"] = cs.getPropertyValue("width");
	            this["zIndex"] = cs.getPropertyValue("z-index");
	            this["color"] = cs.getPropertyValue("color");
	            this["direction"] = cs.getPropertyValue("direction");
	            this["overflowY"] = cs.getPropertyValue("overflow-y");
	            this["display"] = cs.getPropertyValue("display");
	            return this;
            }
            elementProto.__defineGetter__('currentStyle',function() {return new currentStyle(this);});
        	
            cssProto.__proto__ = 
            {
	            __proto__ : cssProto.__proto__
            }	
        	
            cssProto.__defineGetter__('pixelLeft',function() {return parseInt(this.left) || 0;});
            cssProto.__defineSetter__('pixelLeft',function(v) {this.left = v + "px";});
            cssProto.__defineGetter__('pixelHeight',function() {return parseInt(this.height) || 0;});
            cssProto.__defineSetter__('pixelHeight',function(v) {this.height = v + "px";});
            cssProto.__defineGetter__('pixelTop',function() {return parseInt(this.top) || 0;});
            cssProto.__defineSetter__('pixelTop',function(v) {this.top = v + "px";});
            cssProto.__defineGetter__('pixelWidth',function() {return parseInt(this.width) || 0;});
            cssProto.__defineSetter__('pixelWidth',function(v) {this.width = v + "px";});
            cssProto.__defineSetter__('filter',function(v){$Browser._Private.Filters.applyFilter(this,v);});
            cssProto.__defineGetter__('cssText',function() {	
		            var s = "";
		            for (var j=0;j<this.cssRules.length;j++)
			            s += this.cssRules[j].cssText;
		            return s;
	            });
        },
        attachMozillaCompatibility : function (w)
        {
            // Mozilla->IE Compatibility Library
	        w.document.documentElement.className+= " Mozilla";

            var elementProto = w.HTMLElement.prototype;
            var htmlProto = w.HTMLDocument.prototype;
            
            //CV
            var xulProto = w.XULElement.prototype;
            var xulDocProto = w.XULDocument.prototype;
            
            var eventProto = w.Event.prototype;
            var cssProto = w.CSSStyleDeclaration.prototype;
            var docProto = w.Document.prototype;
            var nodeProto = w.Node.prototype;
            var styleProto = w.StyleSheet.prototype;
            var htmlStyleProto = w.HTMLStyleElement.prototype;

            //<cv>
            if(w.document.getElementsByName)
            {
                //</cv>
                var el = w.document.getElementsByName("Web.moz-custom");
                if (el.length>0)
	                $Browser.MozillaCompatMode = el[0].getAttribute("content").toLowerCase()=="enabled";
                else
	                $Browser.MozillaCompatMode = false;
	        }

            $Browser.attachSharedCompatibility(w);
            $Browser.attachEventCompatibility(w);



            w.createPopup = $Browser._Private.CreatePopup;

            docProto.__proto__ = {
	            __proto__ : docProto.__proto__
            };
        	
        	
            docProto.__defineGetter__('xml',function() {return (new XMLSerializer()).serializeToString(this);});
        		
            docProto.scripts = document.getElementsByTagName("script");

            docProto.__defineGetter__('parentWindow', function() { return window; });

            docProto.createStyleSheet = function()
            {
	            var el = document.createElement("style");
	            el.type = "text/css";
	            document.getElementsByTagName("head")[0].appendChild(el);
	            return el;
            }
            docProto.selection = new Object();
            docProto.selection.clear = function() {window.getSelection().deleteFromDocument();}
            docProto.selection.empty = function() {window.getSelection().removeAllRanges();}
            docProto.selection.createRange = function() {return window.getSelection().getRangeAt(0);}

            elementProto.contains = function (el) 
            {	
	            while (el!=null && el!=this)
		            el = el.parentElement;
	            return (el!=null)
            };
            xulProto.contains = elementProto.contains;



            elementProto.filters = $Browser._Private.MozillaFilterSub(); // stub out
            xulProto.filters = elementProto.filters;
            
            var m_Capturing = false;
            var root = document.getElementsByTagName("HTML")[0];
            function CaptureMouse(ev)
            {
	            if (m_Capturing)
	            {
		            ev.preventDefault();
		            ev.returnValue = false;
		            document.removeEventListener("mousemove",CaptureMouse,true);
		            var oEvent = document.createEvent("MouseEvents");
		            oEvent.initMouseEvent(ev.type,
                        ev.bubbles, ev.cancelable, ev.view, ev.detail,
                        ev.screenX, ev.screenY, ev.clientX, ev.clientY,
                        ev.ctrlKey, ev.altKey, ev.shiftKey, ev.metaKey,
                        ev.button, ev.relatedTarget);
                    oEvent._FixOffset = $Browser._Private.getNonTextNode(ev.srcElement);
                    if (oEvent._FixOffset == root)
			            oEvent._FixOffset = document.body;
		            m_Capturing.dispatchEvent(oEvent);
		            document.addEventListener("mousemove",CaptureMouse,true);
		            ev.stopPropagation();
		            ev._FixOffset = null;
	            }					
            }
        	
            function ReleaseMouse(ev)
            {
	            if (m_Capturing)
	            {
		            document.removeEventListener("mouseup",ReleaseMouse,true);
		            document.removeEventListener("mousemove",CaptureMouse,true);
		            var eventCanBubble = ev.bubbles;
		            var eventIsCancelable = ev.cancelable;
        			
		            if (ev.type == "mouseup")
		            {
			            eventCanBubble = false;
			            eventIsCancelable = false;
		            }
        			
		            var oEvent = document.createEvent("MouseEvents");
		            oEvent.initMouseEvent(ev.type,
			            eventCanBubble, eventIsCancelable, ev.view, ev.detail,
			            ev.screenX, ev.screenY, ev.clientX, ev.clientY,
			            ev.ctrlKey, ev.altKey, ev.shiftKey, ev.metaKey,
			            ev.button, ev.relatedTarget);
		            oEvent._FixOffset = $Browser._Private.getNonTextNode(ev.srcElement);
		            if (oEvent._FixOffset == root)
			            oEvent._FixOffset = document.body;			
		            m_Capturing.dispatchEvent(oEvent);
		            m_Capturing = null;		
		            ev.stopPropagation();
		            ev.preventDefault();
		            ev._FixOffset = null;
	            }			
            }


            function StopEvent(ev)
            {
	            ev.stopPropagation();
	            ev.preventDefault();
            }

            function ValidateButton(ev)
            {
	            if (ev.button!=0 && ev.button!=1)	// Fix Firefox bug with right click button firing onclick event
		            ev.stopPropagation();
            }

            function Dispose()
            {
	            w.detachEvent("onunload",Dispose, true);
	            w.document.removeEventListener("click",ValidateButton,true);
            }

            w.attachEvent("onunload",Dispose,true);

            w.document.addEventListener("click",ValidateButton,true)

            elementProto.click = function()
            {
	            var oEvent = document.createEvent("MouseEvents");
	            oEvent.initEvent("click",true,true);
	            var blnRet = this.dispatchEvent(oEvent);
	            // Special case link default actions
	            if (blnRet || (typeof(event.returnValue)=="boolean" && event.returnValue))
	            {
		            var elRoot = this;
		            while (elRoot)
		            {
			            if (elRoot.tagName=="A" && elRoot.href!="")
			            {
				            if (elRoot.target)
					            window.open(elRoot.href,elRoot.target)
				            else
					            document.location = elRoot.href;
				            elRoot = null;
			            }
			            else
				            elRoot = elRoot.parentElement;
		            }
	            }
            }
            xulProto.click = elementProto.click;


            elementProto.setCapture = function(ev) 
            {
	            m_Capturing = this;
	            document.addEventListener("mousemove",CaptureMouse,true);
	            document.addEventListener("mouseover",StopEvent,true);	
	            document.addEventListener("mouseout",StopEvent,true);	
	            document.addEventListener("mouseenter",StopEvent,true);	
	            document.addEventListener("mouseleave",StopEvent,true);	
	            document.addEventListener("mouseup",ReleaseMouse,true);	
            };
            xulProto.setCapture = elementProto.setCapture;
        	
            elementProto.releaseCapture = function() 
            {
	            m_Capturing = null;
	            document.removeEventListener("mousemove",CaptureMouse,true);
	            document.removeEventListener("mouseover",StopEvent,true);	
	            document.removeEventListener("mouseout",StopEvent,true);	
	            document.removeEventListener("mouseenter",StopEvent,true);	
	            document.removeEventListener("mouseleave",StopEvent,true);	
	            document.removeEventListener("mouseup",ReleaseMouse,true);	
            }; 
            xulProto.releaseCapture = elementProto.releaseCapture;
        	
            elementProto.insertAdjacentElement = function (sWhere,oElement)
            {
	            switch (sWhere.toLowerCase())
	            {
		            case "beforebegin":
			            return this.parentNode.insertBefore(oElement,this);
			            break;
		            case "beforeend":
			            return this.appendChild(oElement);
			            break;
		            case "afterbegin":
			            return this.insertBefore(oElement,this.firstChild);
			            break;				
		            case "afterend":
			            if (this.nextSibling) 
				            return this.parentNode.insertBefore(oElement,this.nextSibling);
			            else 
				            return this.parentNode.appendChild(oElement);
			            break;
		            default:
			            throw "Invalid Argument"; // TODO - see if I can get the error number set to 201 (match IE)
			            break;
	            }
	            return null;
            }
        	xulProto.insertAdjacentElement = elementProto.insertAdjacentElement;

          
        	
            $Browser.attachStyleCompatibility(w);



            styleProto.__defineSetter__('cssText',function(s) {this.ownerNode.innerHTML = s;});
            styleProto.__defineGetter__('cssText',function() {return this.ownerNode.innerHTML;});
            htmlStyleProto.__defineSetter__('cssText',function(s) {this.innerHTML = s;});
            htmlStyleProto.__defineGetter__('cssText',function() {return this.innerHTML;});


            // HTML Element
            elementProto.__proto__ = {
	            __proto__ : elementProto.__proto__
            }
            xulProto.__proto__ = {
                __proto__ : xulProto.__proto__
            }
        	
            elementProto.__defineGetter__('children', function () {
                    var elementNodes = [];
                    var childCount = this.childNodes.length;
                    for (var i = 0; i < childCount; i++) {
                        // nodeType == 1 is an element node
                        var childNode = this.childNodes[i];
                        if (childNode.nodeType == 1) {
                            elementNodes.add(childNode);
                        }
                    }
                    return elementNodes;
                });
            xulProto.__defineGetter__('children', function () {
                    var elementNodes = [];
                    var childCount = this.childNodes.length;
                    for (var i = 0; i < childCount; i++) {
                        // nodeType == 1 is an element node
                        var childNode = this.childNodes[i];
                        if (childNode.nodeType == 1) {
                            elementNodes.add(childNode);
                        }
                    }
                    return elementNodes;
                });

            elementProto.__defineGetter__('parentElement',function() {return $Browser._Private.getNonTextNode(this.parentNode);});
            elementProto.__defineGetter__('document',function() {return this.ownerDocument});

            elementProto.__defineGetter__('onfilterchange',function() {return this.filters.onfilterchange;});
            elementProto.__defineSetter__('onfilterchange',function(v) {this.filters.onfilterchange = v;});
            elementProto.__defineGetter__('filters',function() {return [];});
            elementProto.__defineGetter__('innerText',function() {	
		            try 
			            {return this.textContent} 
		            catch(ex) 
		            {
			            var str = "";
			            for (var i=0;i<this.childNodes.length;i++)
			            {
				            if (this.childNodes[i].nodeType==3)
					            str += this.childNodes[i].textContent;
			            }
		            return str;
		            }});
		            
		    xulProto.__defineGetter__('parentElement',function() {return $Browser._Private.getNonTextNode(this.parentNode);});
            xulProto.__defineGetter__('document',function() {return this.ownerDocument});

            xulProto.__defineGetter__('onfilterchange',function() {return this.filters.onfilterchange;});
            xulProto.__defineSetter__('onfilterchange',function(v) {this.filters.onfilterchange = v;});
            xulProto.__defineGetter__('filters',function() {return [];});
            xulProto.__defineGetter__('innerText',function() {	
		            try 
			            {return this.textContent} 
		            catch(ex) 
		            {
			            var str = "";
			            for (var i=0;i<this.childNodes.length;i++)
			            {
				            if (this.childNodes[i].nodeType==3)
					            str += this.childNodes[i].textContent;
			            }
		            return str;
		            }});


            function formatPlainTextAsHtml(str) {
                var sb = [];

                var numChars = str.length;
                var prevCh;

                for (var i=0; i < numChars; i++) {
                    var ch = str.charAt(i);
                    switch (ch) {
                        case "<":
                            sb.push("&lt;");
                            break;
                        case ">":
                            sb.push("&gt;");
                            break;
                        case "\"":
                            sb.push("&quot;");
                            break;
                        case "&":
                            sb.push("&amp;");
                            break;
                        case " ":
                            if (prevCh == " ") {
                                sb.push("&nbsp;");
                            }
                            else {
                                sb.push(" ");
                            }
                            break;
                        case "\r":
                            // Ignore \r, only handle \n
                            break;
                        case "\n":
                            // Insert line breaks before and after the <br>, so the HTML looks better.
                            sb.push("\r\n\r\n<br />");
                            break;
                        default:
                            sb.push(ch);;
                            break;
                    }

                    prevCh = ch;
                }

                return sb.join("");
            }			
        			
            elementProto.__defineSetter__('innerText',function(v) {
	            if (v) {
		            this.innerHTML = formatPlainTextAsHtml(v.toString());
	            }
	            else {
		            this.innerHTML = '';
	            }});
      	
      	    xulProto.__defineSetter__('innerText',function(v) {
	            if (v) {
		            this.innerHTML = formatPlainTextAsHtml(v.toString());
	            }
	            else {
		            this.innerHTML = '';
	            }});
        	
            // End HTML Element

        	

            // XMLDocument
            w.XMLDocument.prototype.transformNodeToObject = function(p_objXsl)
            {
	            var objXslProcessor = new XSLTProcessor();
	            objXslProcessor.importStylesheet(p_objXsl);
 	            var ownerDocument = document.implementation.createDocument("", "", null);
	            return objXslProcessor.transformToFragment(this, ownerDocument);
            }

            w.XMLDocument.prototype.loadXML = function (v) {
                // parse the string to a new doc.
                var doc = (new DOMParser()).parseFromString(v, "text/xml");               

                // remove all initial children
                while (this.hasChildNodes())
		            this.removeChild(this.lastChild);

                // insert and import nodes
                for (var i=0; i < doc.childNodes.length; i++)
                {
		            this.appendChild(this.importNode(doc.childNodes[i], true));
                }
            }



            w.XMLDocument.prototype.transformNode = function(xsl) {
                var xslProcessor = new XSLTProcessor();
                xslProcessor.importStylesheet(xsl);

                var ownerDocument = document.implementation.createDocument("", "", null);
                var transformedDoc = xslProcessor.transformToDocument(this);
                
                return transformedDoc.xml;
            }

            w.XMLDocument.prototype.setProperty = function(p, v)
            {
	            return null;
            }
            
            w.XMLDOMParser = w.DOMParser;
            // End XMLDocument

        	
            // DocumentFragment
            w.DocumentFragment.prototype.getElementById = function(id) {
                var nodeQueue = [];
                var childNodes = this.childNodes;
                var node;
                var c;
                
                for (c = 0; c < childNodes.length; c++) {
                    node = childNodes[c];
                    if (node.nodeType == 1) {
                        nodeQueue.queue(node);
                    }
                }
                
                while (nodeQueue.length) {
                    node = nodeQueue.dequeue();
                    if (node.id == id) {
                        return node;
                    }
                    childNodes = node.childNodes;
                    if (childNodes.length != 0) {
                        for (c = 0; c < childNodes.length; c++) {
                            node = childNodes[c];
                            if (node.nodeType == 1) {
                                nodeQueue.queue(node);
                            }
                        }
                    }
                }
                
                return null;
            }
            
            w.DocumentFragment.prototype.createElement = function(tagName) {
                return document.createElement(tagName);
            }
            // End Document Fragment


            // XPath helpers
            function selectNodes(doc, path, contextNode) {
                contextNode = contextNode ? contextNode : doc;
                var xpath = new XPathEvaluator();
                var result = xpath.evaluate(path, contextNode,
                                            doc.createNSResolver(doc.documentElement),
                                            XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);

                var nodeList = new Array(result.snapshotLength);
                for(var i = 0; i < result.snapshotLength; i++) {
                    nodeList[i] = result.snapshotItem(i);
                }

                return nodeList;
            }

            function selectSingleNode(doc, path, contextNode) {
                path += '[1]';
                var nodes = selectNodes(doc, path, contextNode);
                if (nodes.length != 0) {
                    for (var i = 0; i < nodes.length; i++) {
                        if (nodes[i]) {
                            return nodes[i];
                        }
                    }
                }
                return null;
            }
        	
            w.XMLDocument.prototype.selectNodes = function(path, contextNode) {
                return selectNodes(this, path, contextNode);
            }
            w.XMLDocument.prototype.selectSingleNode = function(path, contextNode) {
                return selectSingleNode(this, path, contextNode);
            }
            w.Node.prototype.selectNodes = function(path) {
                var doc = this.ownerDocument;
                return doc.selectNodes(path, this);
            }
            
            w.Node.prototype.selectSingleNode = function(path) {
                var doc = this.ownerDocument;        
                return doc.selectSingleNode(path, this);
            }


            // Node Prototype
            nodeProto.__proto__ = {
	            __proto__ : nodeProto.__proto__
            }
        	
            nodeProto.__defineGetter__('baseName', function() {
                return this.localName;
            });
        	
            nodeProto.__defineGetter__('xml', function() {
                return (new XMLSerializer()).serializeToString(this);
            });
            
            nodeProto.__defineGetter__('text', function() {
                return this.textContent;
            });
            
            nodeProto.__defineSetter__('text', function(value) {
                this.textContent = value;
            });
                

            
            // end Node Prototype

            // IE Event Object
            
            function QuickLoc (el) 
            {
	            var c = {x : 0, y : 0};
	            while (el) {
		            c.x += el.offsetLeft;
		            c.y += el.offsetTop;
		            el = el.offsetParent;
	            }
	            return c;
            }
        	
            eventProto.__proto__ = {
	            __proto__:eventProto.__proto__};

            eventProto.__defineGetter__('srcElement',function() {var n = this._FixOffset; if (!n) {n = $Browser._Private.getNonTextNode(this.target)};return n;});
            eventProto.__defineSetter__('cancelBubble',function(v) {if (v) this.stopPropagation();});
            eventProto.__defineGetter__('offsetX',function() {return window.pageXOffset + this.clientX - ((this._FixOffset) ? QuickLoc(this._FixOffset).x : QuickLoc(this.srcElement).x);});
            eventProto.__defineGetter__('offsetY',function() {return window.pageYOffset + this.clientY - ((this._FixOffset) ? QuickLoc(this._FixOffset).y : QuickLoc(this.srcElement).y);});
            eventProto.__defineGetter__('x',function() {return this.offsetX;});
            eventProto.__defineGetter__('y',function() {return this.offsetY;});
            eventProto.__defineGetter__('returnValue',function() {return this.cancelDefault;});
            eventProto.__defineSetter__('returnValue',function(v) {if (!v) {this.preventDefault()}; this.cancelDefault = v;return v;});
            eventProto.__defineGetter__('button', function() {return (this.which == 1) ? 1 : (this.which == 3) ? 2 : 0});	
            eventProto.__defineGetter__('fromElement',function() {			
		            var n;
		            if (this.type == "mouseover")
			            n = this.relatedTarget;
		            else if (this.type == "mouseout")
			            n = this.target;
		            return $Browser._Private.getNonTextNode(n);});
            eventProto.__defineGetter__('toElement',function() {		
		            var n =null;
		            var ex;
		            try
		            {
			            if (this.type == "mouseout")
				            n = this.relatedTarget;
			            else if (this.type == "mouseover")
				            n = this.target;
		            }
		            catch(ex){}
		            return $Browser._Private.getNonTextNode(n);
		            });
        			
            // End Event

        },
        attachOperaCompatibility : function(w)
        {
            var docProto = w.Document.prototype;

            w.document.documentElement.className+= " Opera";

            $Browser.attachSharedCompatibility(w);
            
            function selectNodesOpera(doc,path,contextNode)
            {
                contextNode=contextNode?contextNode:doc;
                // next line to support calling someElement.selectNodes and be able to use document.evaluate
                if( ! (doc instanceof Document) ){doc=doc.ownerDocument;}
            	
                var result=doc.evaluate(path,contextNode,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null);
                var nodeList=new Array(result.snapshotLength);
                for(var i=0;i<result.snapshotLength;i++){nodeList[i]=result.snapshotItem(i);}
                return nodeList;

            }
            
            function selectSingleNodeOpera(doc,path,contextNode)
            {
                path+='[1]';var nodes=selectNodesOpera(doc,path,contextNode);
                if(nodes.length!=0)
                    {for(var i=0;i<nodes.length;i++){if(nodes[i]){return nodes[i];}}} return null;
            } 

            w.Element.prototype.selectNodes=docProto.selectNodes= function(path,contextNode)
            { 
                return selectNodesOpera(this,path,contextNode);
            }
            docProto.selectSingleNode=function(path,contextNode)
            {
                return selectSingleNodeOpera(this,path,contextNode);
            }
            w.Element.prototype.setCapture = function() {};
            w.Element.prototype.releaseCapture = function() {};
        },
        attachSafariCompatibility : function(w)
        {
            w.document.documentElement.className+= " Safari";
            w.Element.prototype.setCapture = function() {};
            w.Element.prototype.releaseCapture = function() {};            
            $Browser.attachSharedCompatibility(w);
            $Browser.attachEventCompatibility(w);
            $Browser.attachStyleCompatibility(w);   	
        },
        attachSharedCompatibility : function(w)
        {
            var elementProto = w.HTMLElement.prototype;
            //cv
            var xulProto = w.XULElement.prototype;

            w.CollectGarbage = function() {};
            w._ce = function(s)
            {
                return document.createElement(s);
            }

            w._ge = function(s)
            {
                return document.getElementById(s);
            }

            w._get = function(s)
            {
                return document.getElementsByTagName(s);
            }        
            
            if (!_isOpera)
            {
        	    elementProto.removeNode = function(b) 
                {
	                // Only remove if it has a parent.
                    // In all cases, return the node back.
	                return this.parentNode ? this.parentNode.removeChild(this) : this;
                },
                elementProto.__defineGetter__('uniqueID',function() {var id = this._uniqueID;if (!id) id = this._uniqueID = "ms_id" + (intID++); return id});       
                xulProto.removeNode = elementProto.removeNode;
                xulProto.__defineGetter__('uniqueID',function() {var id = this._uniqueID;if (!id) id = this._uniqueID = "ms_id" + (intID++); return id});       

                elementProto.insertAdjacentHTML = function (sWhere, sHTML)
                {
                    var n; 
                    var r = this.ownerDocument.createRange();
                    switch (sWhere.toLowerCase()) {  
                        case "beforebegin":
                            r.setStartBefore(this);
                            n = r.createContextualFragment(sHTML);
                            return this.parentNode.insertBefore(n, this);
                        case "afterbegin":
                            r.selectNodeContents(this);
                            r.collapse(true);
                            n = r.createContextualFragment(sHTML);
                            return this.insertBefore(n, this.firstChild);
                        case "beforeend":
                            r.selectNodeContents(this);
                            r.collapse(false);
                            n = r.createContextualFragment(sHTML);
                            return this.appendChild(n);
                        case "afterend":
                            r.setStartAfter(this);
                            n = r.createContextualFragment(sHTML);
                            return this.parentNode.insertBefore(n, this.nextSibling);
		                default:
			                throw "Invalid Argument";
			                break;
                    }   
                }
                xulProto.insertAdjacentHTML = elementProto.insertAdjacentHTML;
                
                elementProto.swapNode = function (node) {
	                var nextSibling = this.nextSibling;
	                var parentNode = this.parentNode;
	                node.parentNode.replaceChild(this, node);
	                parentNode.insertBefore(node, nextSibling);  
                }
            	xulProto.swapNode = elementProto.swapNode;
            	
                elementProto.replaceNode = function(node)
                {
	                this.parentNode.replaceChild(node,this);
                }
                xulProto.swapNode = elementProto.swapNode;
            }
        },
        _Private : 
        {
	        // This rewraps the xml response object in Firefox to avoid security errors when accessing the DOM.
        
	        cleanupFirefox : function(el,obj)
	        {
		        var newXML;
		        var status;
		        try
		        {
			        status = el.status;
		        }
		        catch (ex)
		        {
			        // if FireFox is offline, it may throw NS_ERROR_NOT_AVAILABLE when
			        // attempting to access el.status
		        }
		        if (status==200)
		        {
			        try
			        {
				        var testAccess = el.responseXML.documentElement;	// See if an exception is thrown - if so Firefox still has bug accessing DOM - rewrap results
			        }
			        catch (ex)
			        {
				        if (window.DOMParser)
				        {
					        try
					        {
						        var parser = new DOMParser;
						        var domDoc = parser.parseFromString(el.responseText.toString(), "text/xml");
						        newXML = {};
						        newXML.responseText = el.responseText;
						        newXML.responseXML = domDoc;
						        var strHeaders = el.getAllResponseHeaders();
						        var arrHeaders = {};

						        function parseH(v)
						        {
							        var p = v.split(":");
							        if (p[1])
	  							        arrHeaders[p[0]] = p[1].trim();
						        };
						        strHeaders.split("\n").forEach(parseH);
						        newXML.getAllResponseHeaders = function() {return strHeaders};
						        newXML.getResponseHeader = function(s) {
							        return arrHeaders[s];
						        };
						        newXML.statusText = el.statusText;
						        newXML.status = el.status;
						        el = newXML;
					        }
					        catch (ex2)
					        {
						        el = null;
					        }
				        }
				        else
					        el = null;
			        }
		        }	
		        return el;	
	        },
            getNonTextNode : function(n)
            {
	            try
	            {
		            while (n && n.nodeType!=1) n=n.parentNode;
	            }
	            catch(ex)
	            {
		            n = null;
	            }
	            return n;
            },
	        
	        CreatePopup : function()
	        {
		        var obj = new Object();
		        obj.document = document.createDocumentFragment();
		        obj.document.body = obj.document.appendChild(document.createElement("div"));
		        obj.document.close = obj.document.open = function() {};
		        obj.document.write = function(v)
		        {
			        obj.document.body.innerHTML += v;
		        }

		        obj.show = function(x,y,width,height,offset)
		        {
			        if (!Web.Dom) throw new Error("Missing Coreui.js");
			        if (!offset) offset = document.body;
			        var offsetLoc = Web.Dom.GetLocation(offset);
			        obj.document.body.style.cssText = "z-index:100;position:absolute;margin:0px;padding:0px;top:{0}px;left:{1}px;width:{2}px;height:{3}px;background:white".format(y+offsetLoc.top,x+offsetLoc.left,width,height);
        			
			        var r = document.body.appendChild(obj.document.body);
			        document.addEventListener("mousedown",doHide,true)
			        r.onclicktemp = obj.document.onclick;
			        r.onclick = doClick
			        function doHide(ev)
			        {
				        if (!obj.document.body.contains(ev.target)) 
				        {
					        ev.stopPropagation()
					        r.removeNode();
				        }
				        document.removeEventListener("mousedown",doHide,true);
			        }
        			
			        function doClick(ev)
			        {
				        if (this.onclicktemp)
					        this.onclicktemp()
				        r.removeNode();
			        }

		        }

		        return obj;
	        },
	        // TODO - Needs thorough testing (especially timing related tests)
	        MozillaModal : function(sURL,oArguments,sFeatures,fnCallback)
	        {
		        if (!sFeatures) sFeatures = "";
		        sFeatures = sFeatures.removeSpaces();
		        var featureList = sFeatures.split(",");
		        var s = sFeatures = "";
		        var bCenter = false,bNoCenter = false;
		        var w=0,h=0;
		        for (var i=0;i<featureList.length;i++)
		        {
			        var feature = featureList[i].split(":");
			        var k = feature[0].toLowerCase();
			        var v = feature[1];
			        switch (k)
			        {
				        case "dialogheight": s+="height=" + v; w=v;break;
				        case "dialogwidth": s+="width=" + v; h=v;break;
				        case "dialogtop": s+="top=" + v; bNoCenter = true; break;
				        case "dialogleft": s+="left=" + v; bNoCenter = true; break;
				        case "resizable": s+="resizable=" + v; break;
				        case "status": s+="status=" + v; break;
				        case "center": bCenter = true; break;
			        }
			        if (k!="center") s+=",";
		        }
		        if (bCenter && (!bNoCenter))
		        {
        			
			        if (w!=0) w = $Number.coerceInt(w); else w=300;
			        if (h!=0) h = $Number.coerceInt(h); else h=300;
			        if (w!="" || h!="")
			        {
				        s+="screenX=" + ((screen.availHeight-h)/2) + ",";
				        s+="screenY=" + ((screen.availWidth-w)/2);
			        }
		        }
		        var mWin = window.open(sURL,"",s);
		        $Browser.AttachMozillaCompatibility(mWin);
		        mWin.dialogArguments = oArguments;

		        resetModal = function(ev)
		        {
			        if (mWin && !mWin.closed)
			        {
				        ev.stopPropagation();
				        mWin.focus()
			        }
		        }
        		
		        var rValue = "";
		        grabReturn = function()
		        {
			        if (mWin && !mWin.closed)
			        {
				        rValue = mWin.returnValue;
				        setTimeout(CheckClose,0); // Test timer
			        }
		        }
        		
		        CheckClose = function()
		        {
			        if (mWin.closed)
			        {				
				        if (fnCallback)
					        fnCallback(rValue);
				        window.removeEventListener("focus",resetModal,true);
			        }
		        }
        		
		        hookEvents = function()
		        {
			        mWin.onunload = grabReturn; //("onunload",grabReturn,true);
			        window.addEventListener("focus",resetModal,true);
		        }		
		        setTimeout(hookEvents,0) // Need to test timing of this (e.g., slow connection)
	        },
        	
	        // Stub out filters
	        MozillaFilterMethods : new Array("addAmbient","addCone","addPoint","apply","changeColor","changeStrength","clear","moveLight"),
	        MozillaFilterEventMethods  : new Array("play","stop"),
	        MozillaFilterSub : function()
	        {
		        // Need to implement item, etc)
		        // Use prototype to make more efficient

		        var privFilter = $Browser._Private;
		        for (var i=0;i<privFilter.MozillaFilterMethods.length;i++)
			        this[privFilter.MozillaFilterMethods[i]] = doblank;
		        for (var i=0;i<privFilter.MozillaFilterEventMethods.length;i++)
			        this[privFilter.MozillaFilterEventMethods[i]] = doevent;
		        function doblank() {}
        		
		        function doevent() 
		        {	// TODO - need to hook up event object and related properties
			        if (this.onfilterchange) this.onfilterchange();
		        }
        		
		        return this;
	        },
	        Filters :{
		        _filterDeclarationExpression : /progid:([^\(]+)\(([^\)]+)\)/gi,
		        applyFilter:function(style,declaration)
		        {
			        var a,filters={};
			        while(a=$Browser._Private.Filters._filterDeclarationExpression.exec(declaration))
			        {
				        var t=Object.resolve("$Browser._Private.Filters."+a[1]);
				        if(t)
				        {    
					        filters[a[1]]=new t(style,$Browser._Private.Filters.parseParams(a[2]));
				        }
			        }
			        style.filters=filters;
		        },
		        parseParams:function(p_strParams)
		        {
			        var params = p_strParams.split(",");
			        var v={};
			        for(var i=0;i<params.length;i++)
			        {
				        var param=params[i].split("=");
				        v[param[0].toLowerCase()]=$Browser._Private.Filters.cleanParam(param[1]);
			        }
			        return v;
		        },
		        cleanParam:function(p_strParam)
		        {
			        if(p_strParam.indexOf("'")==0)
				        return p_strParam.substring(1,p_strParam.length-1);
			        return p_strParam.toLowerCase();
		        },
		        DXImageTransform:
		        {
			        Microsoft:
			        {
				        Alpha:function(style,v)
				        {
					        var num = Number(v.opacity);
					        style.opacity=Number.coerceFloat(v.opacity)/100;
					        style.mozOpacity=style.opacity;
				        },
				        AlphaImageLoader:function(style,v)
				        {
					        style.backgroundImage="url("+v.src+")";
					        switch(v.sizingMethod)
					        {
						        case "crop" :
							        style.backgroundRepeat="no-repeat";
					        }
				        },
				        Blur:function(style,v)
				        {
					        if(v.makeshadow=="true")
					        {
						        var opacity = Number.coerceFloat(v.shadowopacity);
						        style.opacity = opacity;
						        style.mozOpacity = opacity;
						        style.backgroundColor="#000000";
						        style.margin = "3px";
					        }	
				        }
			        }
		        }    
		    } 
		}
    }


    if (window.HTMLElement && _isMozilla)  // Can only be true if compat library is installed and mozilla
    {
	    $Browser.attachMozillaCompatibility(window);
    }
    else
        if (_isOpera)
        {
	        $Browser.attachOperaCompatibility(window);
        }
    else
        if (_isSafari)
        {
	        $Browser.attachSafariCompatibility(window);
        }

    // Global Additions
}
