// 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 = "0.061004.0";

if (!window.Web) window.Web = {};

// Stub debug functions
if (!Web.Debug || !Web.Debug.Enabled)
{
	Web.Debug = new function()
	{
		this.Enabled = false;
		this.Assert = this.Trace = function() {};
		this.Performance = {};
		this.Performance.Start  = function()
		{
			this.End = function(){};
			return this;
		}
	}
}

window.Debug = new function() {
	this.writeln = this.write = function(text) {};
	this.breakIntoDebugger = function(message) {throw new Error(message)};
}


// Need more robust checks

Web.Browser = new function()
{
	var _isMozilla = (navigator.userAgent.indexOf("Mozilla")>=0) && (!window.opera);
	this.isMozilla = function()
	{
		return _isMozilla;
	}

	this.isOpera = function()
	{
		return window.opera!=null;
	}
}



// Mozilla implementation of CreatePopup
Web.Browser._Private = function() {}

		// This rewraps the xml response object in Firefox to avoid security errors when accessing the DOM.
Web.Browser._Private.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 (ex)
				{
					el = null;
				}
			}
			else
				el = null;
		}
	}	
	return el;	
}

Web.Browser._Private.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 (!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;
}


// Stub out filters
Web.Browser._Private.MozillaFilterMethods = new Array("addAmbient","addCone","addPoint","apply","changeColor","changeStrength","clear","moveLight")
Web.Browser._Private.MozillaFilterEventMethods  = new Array("play","stop");
Web.Browser._Private.MozillaFilterSub = function()
{
	// Need to implement item, etc)
	// Use prototype to make more efficient

	var privFilter = Web.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;
}

Web.Browser._Private.Filters={};
Web.Browser._Private.Filters._filterDeclarationExpression=/progid:([^\(]+)\(([^\)]+)\)/gi;
Web.Browser._Private.Filters._styleElements = [];
Web.Browser._Private.Filters._currentElid = 0;
Web.Browser._Private.Filters.findElementByStyle=function(style)
{
	if(style.__styleElNotFound__ || null != style.__styleElid__)
	{
		return Web.Browser._Private.Filters._styleElements[style.__styleElid__];
	}
	var iterator = document.evaluate("//node()", document, null, XPathResult.UNORDERED_NODE_ITERATOR_TYPE,null);
	var el;
	while(el = iterator.iterateNext())
	{
	    if(el.style==style)
		{
			style.__styleElid__ = Web.Browser._Private.Filters._currentElid++;
			Web.Browser._Private.Filters._styleElements[style.__styleElid__] = el;
			return Web.Browser._Private.Filters._styleElements[style.__styleElid__];
		}	
	}
	style.__styleElNotFound__ = true
	return null;
}
Web.Browser._Private.Filters.applyFilter=function(style,declaration)
{
	var a,filters={};
	while(a=Web.Browser._Private.Filters._filterDeclarationExpression.exec(declaration))
	{
		var t=Web.Type.resolve("Web.Browser._Private.Filters."+a[1]);
		if(t)
		{    
			filters[a[1]]=new t(style,Web.Browser._Private.Filters.parseParams(a[2]));
		}
	}
	style.filters=filters;
}
Web.Browser._Private.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()]=Web.Browser._Private.Filters.cleanParam(param[1]);
	}
	return v;
}
Web.Browser._Private.Filters.cleanParam=function(p_strParam)
{
	if(p_strParam.indexOf("'")==0)
		return p_strParam.substring(1,p_strParam.length-1);
	return p_strParam.toLowerCase();
}

Web.Browser._Private.Filters.DXImageTransform=
{
    Microsoft:
    {
        Alpha:function(style,v)
        {
	        var num = Number(v.opacity);
	        style.opacity=Web.Conversion.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 = Web.Conversion.coerceFloat(v.shadowopacity);
		        style.opacity = opacity;
		        style.mozOpacity = opacity;
		        style.backgroundColor="#000000";
		        style.margin = "3px";
	        }	
        }
    }
}


Web.Browser.AttachMozillaCompatibility = function (w)
{
	// Mozilla->IE Compatibility Library

	w.CollectGarbage = function() {};

	function EstablishMode()
	{
		var el = w.document.getElementsByName("Web.moz-custom");
		if (el.length>0)
			Web.Browser.MozillaCompatMode = el[0].getAttribute("content").toLowerCase()=="enabled";
		else
			Web.Browser.MozillaCompatMode = false;
	}

	EstablishMode();
	function GenWindowEvent(e) {
		window.event = e; 
	}	
	
	Web.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(event.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()
	{
		if (!this.contains(event.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";
		}
		if (strMozillaType!="mouseenter" && strMozillaType!="mouseleave")
		{
			el.removeEventListener(strMozillaType, GenWindowEvent, true);
		}
		else // Simulate events
		{
			el.removeEventListener("mouseover", GenWindowEvent, true);
			el.removeEventListener("mouseout", GenWindowEvent, true);
			el.removeEventListener("mouseover",CheckEnter,false);
			el.removeEventListener("mouseout",CheckLeave,false);
		}
		el.removeEventListener(strMozillaType, callback, false);
	}
	
	function GetNonTextNode(n)
	{
		try
		{
			while (n && n.nodeType!=1) n=n.parentNode;
		}
		catch(ex)
		{
			n = null;
		}
		return n;
	}
	var elementProto = w.HTMLElement.prototype;
	var htmlProto = w.HTMLDocument.prototype;
	var eventProto = w.Event.prototype;
	var cssProto = w.CSSStyleDeclaration.prototype;
	var docProto = w.Document.prototype;
	var nodeProto = w.Node.prototype;

	w.attachEvent = w.HTMLDocument.prototype.attachEvent = w.HTMLElement.prototype.attachEvent = function (type, callback) {Map(this,type,callback);return true;}
	w.detachEvent = w.HTMLDocument.prototype.detachEvent = w.HTMLElement.prototype.detachEvent = function (type, callback) {RemoveMap(this,type,callback);return true;}
	w.createPopup = Web.Browser._Private.CreatePopup;

	docProto.__proto__ = {
		__proto__ : docProto.__proto__
	};
	
	
	docProto.__defineGetter__('xml',function() {return (new XMLSerializer()).serializeToString(this);});
		
	w.Document.prototype.scripts = document.getElementsByTagName("script");

	w.Document.prototype.selection = new Object();
	w.Document.prototype.selection.clear = function() {window.getSelection().deleteFromDocument();}
	w.Document.prototype.selection.empty = function() {window.getSelection().removeAllRanges();}
	w.Document.prototype.selection.createRange = function() {return window.getSelection().getRangeAt(0);}

	w.HTMLElement.prototype.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;
	}	
	w.HTMLElement.prototype.contains = function (el) 
	{	
		while (el!=null && el!=this)
			el = el.parentElement;
		return (el!=null)
	};


	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;
	}

	
	w.HTMLElement.prototype.filters = Web.Browser._Private.MozillaFilterSub(); // stub out
	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 = 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 = 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)

	w.HTMLElement.prototype.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;
			}
		}
	}


	w.HTMLElement.prototype.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);	
	};
	
	w.HTMLElement.prototype.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);	
	}; 
	
	w.HTMLElement.prototype.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;
	}

	// IE CSS Properties
	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){Web.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;
		});


	// HTML Element
	elementProto.__proto__ = {
		__proto__ : elementProto.__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;
        });

	var intID = 0;	
	elementProto.__defineGetter__('uniqueID',function() {if (this.uid == null) {this.uid = "ms_id" + (intID++);} return this.uid;});       
	elementProto.__defineGetter__('parentElement',function() {return GetNonTextNode(this.parentNode);});
	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;
			}});

    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);
		}
		else {
			this.innerHTML = '';
		}});
	elementProto.__defineGetter__('currentStyle',function() {return new CurrentStyle(this);});
	
	elementProto.swapNode = function (node) {
		var nextSibling = this.nextSibling;
		var parentNode = this.parentNode;
		node.parentNode.replaceChild(this, node);
		parentNode.insertBefore(node, nextSibling);  
	}
	
	elementProto.replaceNode = function(node)
	{
		this.parentNode.replaceChild(node,this);
	}

	
	
	// 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 = 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 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 GetNonTextNode(n);
			});
			
	// End Event


}

// TODO - Needs thorough testing (especially timing related tests)
Web.Browser._Private.MozillaModal = function(sURL,oArguments,sFeatures,fnCallback)
{
	if (!sFeatures) sFeatures = "";
	sFeatures = sFeatures.removeSpaces();
	var featureList = sFeatures.split(",");
	sFeatures = "";
	var bCenter = bNoCenter = false;
	var w=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) && Web.Conversion)
	{
		
		if (w!=0) w = Web.Conversion.CoerceInt(w); else w=300;
		if (h!=0) h = Web.Conversion.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);
	Web.Browser._Private.MozillaCompat(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)
}

if (Web.Browser.isMozilla())  // Can only be true if compat library is installed and mozilla
{
	document.documentElement.className+= " Mozilla";
	Web.Browser.AttachMozillaCompatibility(window);
}

Web.Browser.AttachOperaCompatibility = function(w)
{

	w.CollectGarbage = function() {};
	
    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=w.Document.prototype.selectNodes= function(path,contextNode)
    { 
        return selectNodesOpera(this,path,contextNode);
    }
    w.Document.prototype.selectSingleNode=function(path,contextNode)
    {
        return selectSingleNodeOpera(this,path,contextNode);
    }
	w.Element.prototype.setCapture = function() {};
	w.Element.prototype.releaseCapture = function() {};
}

if (Web.Browser.isOpera())
{
	document.documentElement.className+= " Opera";
	Web.Browser.AttachOperaCompatibility(window);
}


function _ce(s)
{
	return document.createElement(s);
}

function _ge(s)
{
	return document.getElementById(s);
}

function _get(s)
{
	return document.getElementsByTagName(s);
}
