//<script>
//////////////////
// Helper Stuff //
//////////////////

/* predefine node type string */
var NODE_ELEMENT                =  1;
var NODE_ATTRIBUTE              =  2;
var NODE_TEXT                   =  3;
var NODE_CDATA_SECTION          =  4;
var NODE_ENTITY_REFERENCE       =  5;
var NODE_ENTITY                 =  6;
var NODE_PROCESSING_INSTRUCTION =  7;
var NODE_COMMENT                =  8;
var NODE_DOCUMENT               =  9;
var NODE_DOCUMENT_TYPE          = 10;
var NODE_DOCUMENT_FRAGMENT      = 11;
var NODE_NOTATION               = 12;

/** 
 * Unescape the given string. This turns the occurences of the predefined XML 
 * entities to become the characters they represent correspond to the five predefined XML entities
 * @param sXml the string to unescape
 */
function xmlEscape(sXml) {
	var txt = sXml;
	txt = txt.replace("&", /&amp;/g);
	txt = txt.replace("'", /&apos;/g);
	// txt = txt.replace('"', /&quot;/g);
	txt = txt.replace(">", /&gt;/g);
	txt = txt.replace("<", /&lt;/g);
	return txt;
}

// ****************************************************************************
/**
 * used to get title
 *     @param object node : get title of node
 *     @param string node_name : title node name
 *     @return string title
 **/
function getCaption(node, node_name) {
	var code = "";
	var nodes = null, def = null, titles = null;
	var re = /^(big5|gb2312|en|euc-jp|user-define)$/gi;
	var syslang = (typeof(lang) == "undefined") ? 'big5' : lang.toLowerCase();
	if ((typeof(node) != "object") || (node == null) || !node.hasChildNodes())
		return '';

	if ((typeof(node_name) == "undefined") || (node_name == "")) node_name = "title";

	nodes = node.childNodes;
	for (var i = 0; i < nodes.length; i++) {
		if ((nodes[i].nodeType != 1) || (nodes[i].nodeName != node_name)) continue;
		if (typeof(syslang) == "undefined" || syslang.search(re) < 0) {
			code = "big5";
			def = nodes.item(i).getAttribute('default');
			if ((def != null) && (def.search(re) > 0)) code = def;
		} else {
			code = syslang;
		}

		titles = nodes[i].getElementsByTagName(code);
		if ((titles == null) || (titles.length < 1)) {
			return '';
		} else {
			if (titles[0].firstChild != null)
				return titles[0].firstChild.nodeValue;
			else
				return '';
		}
	}
	return '';
}

/**
 * used to get title
 *     @param object node : get title of node
 *     @param string node_name : title node name
 *     @return string title
 **/
function getNodeValue(node, node_name) {
	var nodes = null;

	if ((typeof(node) != "object") || (node == null) || !node.hasChildNodes())
		return "";

	if ((typeof(node_name) == "undefined") || (node_name == "")) return "";

	nodes = node.childNodes;
	for (var i = 0; i < nodes.length; i++) {
		if ((nodes[i].nodeType != 1) || (nodes[i].nodeName != node_name)) continue;
		if (nodes[i].firstChild != null)
			return nodes[i].firstChild.nodeValue;
		else
			return "";
	}
	return "";
}
// ****************************************************************************
/**
 * used to clean empty text node
 * @param object node
 */
function rm_whitespace(node){
	if (node == null) return false;
	var nodes = node.childNodes;
	if (nodes.length == 0 || (nodes.length == 1 && nodes.item(0).nodeType == 3)) return;

	var i = nodes.length - 1;
	var prev_node;
	var cur_node = nodes.item(i);

	while(i > -1){
		cur_node = nodes.item(i);
		if (cur_node.nodeType == 3 && cur_node.nodeValue.search(/^\s+$/) == 0){
			node.removeChild(nodes.item(i));

		}
		else if(cur_node.nodeType == 1){
			rm_whitespace(cur_node);
		}
		i--;
	}
}

// used to find the Automation server name
function getDomDocumentPrefix() {
	if (getDomDocumentPrefix.prefix)
		return getDomDocumentPrefix.prefix;

	var prefixes = ["MSXML2", "Microsoft", "MSXML", "MSXML3"];
	var o;
	for (var i = 0; i < prefixes.length; i++) {
		try {
			// try to create the objects
			o = new ActiveXObject(prefixes[i] + ".DomDocument");
			return getDomDocumentPrefix.prefix = prefixes[i];
		}
		catch (ex) {};
	}

	throw new Error("Could not find an installed XML parser");
}

function getXmlHttpPrefix() {
	if (getXmlHttpPrefix.prefix)
		return getXmlHttpPrefix.prefix;

	var prefixes = ["MSXML2", "Microsoft", "MSXML", "MSXML3"];
	var o;
	for (var i = 0; i < prefixes.length; i++) {
		try {
			// try to create the objects
			o = new ActiveXObject(prefixes[i] + ".XmlHttp");
			return getXmlHttpPrefix.prefix = prefixes[i];
		}
		catch (ex) {};
	}

	throw new Error("Could not find an installed XML parser");
}

//////////////////////////
// Start the Real stuff //
//////////////////////////


// XmlHttp factory
function XmlHttp() {}

XmlHttp.create = function () {
	try {
		if (window.XMLHttpRequest) {
			var req = new XMLHttpRequest();

			// some versions of Moz do not support the readyState property
			// and the onreadystate event so we patch it!
			if (req.readyState == null) {
				req.readyState = 1;
				req.addEventListener("load", function () {
					req.readyState = 4;
					if (typeof req.onreadystatechange == "function")
						req.onreadystatechange();
				}, false);
			}

			return req;
		}
		if (window.ActiveXObject) {
			return new ActiveXObject(getXmlHttpPrefix() + ".XmlHttp");
		}
	}
	catch (ex) {}
	// fell through
	throw new Error("Your browser does not support XmlHttp objects");
};

// XmlDocument factory
function XmlDocument() {}

XmlDocument.create = function () {
	try {
		// DOM2
		if (document.implementation && document.implementation.createDocument) {
			var doc = document.implementation.createDocument("", "", null);
			doc.preserveWhiteSpace = false;

			if (window.opera) {
				doc.loadXML = function (s) {
					// parse the string to a new doc
					try {
						var doc2 = (new DOMParser()).parseFromString(s, "text/xml");
						// if parse error, it will return parse error message, package by xml
						// it whil be not always, so need check of have change on mozilla version change
						// mozilla 1.3 tested
						//var nodes = doc2.getElementsByTagNameNS("http://www.mozilla.org/newlayout/xml/parsererror.xml", "parsererror");
						var nodes = doc2.getElementsByTagName("parsererror");
						if ((nodes != null) && (nodes.length > 0)) {
							throw new Error("Parse Error.");
						}

						if (!this.preserveWhiteSpace) rm_whitespace(doc2.documentElement);
						// remove all initial children
						while (this.childNodes.length) {
							this.removeChild(this.lastChild);
						}

						// insert and import nodes
						var node = null;
						for (var i = 0; i < doc2.childNodes.length; i++) {
							this.appendChild(this.importNode(doc2.childNodes[i], true));
						}
						return true;
					}
					catch (ex) {
						return false;
					}
				};
				doc._xml = function () {
					return (new XMLSerializer()).serializeToString(this);
				};
				/** dummy, used to accept IE's stuff without throwing errors */
				doc.setProperty  = function(x,y){};
				doc.selectNodes = function (sExpr, contextNode) {
					try {
						return Array(0);
					}
					catch (ex) {
					}
					throw new Error("Your browser does not support function [selectNodes].");
				}
				doc.selectSingleNode = function(sExpr, contextNode) {
					var ctx = contextNode ? contextNode : null;
					sExpr += "[1]";
					var nodeList = this.selectNodes(sExpr, ctx);
					if (nodeList.length > 0)
						return nodeList[0];
					else 
						return null;
				};
			}

			// some versions of Moz do not support the readyState property
			// and the onreadystate event so we patch it!
			if (doc.readyState == null) {
				doc.readyState = 1;
				doc.addEventListener("load", function () {
					doc.readyState = 4;
					if (!doc.preserveWhiteSpace) rm_whitespace(doc.documentElement);
					if ((doc.onreadystatechange != null) && (typeof doc.onreadystatechange == "function"))
						doc.onreadystatechange();
				}, false);
			}

			return doc;
		}
		if (window.ActiveXObject)
			return new ActiveXObject(getDomDocumentPrefix() + ".DomDocument");
	}
	catch (ex) {}
	throw new Error("Your browser does not support XmlDocument objects");
};

// Create the loadXML method and xml getter for Mozilla
if (window.DOMParser &&
	window.XMLSerializer &&
	window.Node && Node.prototype && Node.prototype.__defineGetter__) {

	/**
	 * <p>Deletes all child Nodes of the Document. Internal use</p>
	 * @private
	 */
	XMLDocument.prototype._clearDOM = function () {
		while (this.hasChildNodes())
			this.removeChild(this.firstChild);
	};

	/**
	 * <p>Replaces the childNodes of the Document object with the childNodes of
	 * the object given as the parameter</p>
	 * @private 
	 * @argument oDoc the Document to copy the childNodes from
	 */
	XMLDocument.prototype._copyDOM = function (oDoc) {
		this._clearDOM();
		if (oDoc.nodeType == NODE_DOCUMENT || oDoc.nodeType == NODE_DOCUMENT_FRAGMENT) {
			var oNodes = oDoc.childNodes;
			for (var i = 0; i < oNodes.length; i++)
				this.appendChild(this.importNode(oNodes[i], true));
		} else if (oDoc.nodeType == NODE_ELEMENT)
			this.appendChild(this.importNode(oDoc, true));
	};

	// XMLDocument did not extend the Document interface in some versions
	// of Mozilla. Extend both!
	XMLDocument.prototype.loadXML =
	Document.prototype.loadXML = function (s) {

		// parse the string to a new doc
		try {
			var doc2 = (new DOMParser()).parseFromString(s, "text/xml");
			// if parse error, it will return parse error message, package by xml
			// it whil be not always, so need check of have change on mozilla version change
			// mozilla 1.3 tested
			//var nodes = doc2.getElementsByTagNameNS("http://www.mozilla.org/newlayout/xml/parsererror.xml", "parsererror");
			var nodes = doc2.getElementsByTagName("parsererror");
			if ((nodes != null) && (nodes.length > 0)) {
				throw new Error("Parse Error.");
			}

			if (!this.preserveWhiteSpace) rm_whitespace(doc2.documentElement);
			this._copyDOM(doc2);
			return true;
		}
		catch (ex) {
			return false;
		}
	};


	/*
	 * xml getter
	 *
	 * This serializes the DOM tree to an XML String
	 *
	 * Usage: var sXml = oNode.xml
	 *
	 */
	// XMLDocument did not extend the Document interface in some versions
	// of Mozilla. Extend both!
	XMLDocument.prototype.__defineGetter__("xml", function () {
		return (new XMLSerializer()).serializeToString(this);
	});
	Document.prototype.__defineGetter__("xml", function () {
		return (new XMLSerializer()).serializeToString(this);
	});
	Node.prototype.__defineGetter__("xml", function () {
		return (new XMLSerializer()).serializeToString(this);
	});

	XMLDocument.prototype.__defineSetter__("xml", function () {
		throw new Error("Invalid assignment on read-only property 'xml'. Hint: Use the 'loadXML(String xml)' method instead.");
	});

	/**
	 * <p>Emulates IE's innerText (read/write). Note that this removes all
	 * childNodes of an HTML Element and just replaces it with a textNode</p>
	 */
	HTMLElement.prototype.innerText;
	HTMLElement.prototype.__defineSetter__("innerText", function (sText) {
		var s = "" + sText;
		s = s.replace(/\&/g, "&amp;");
		s = s.replace(/</g, "&lt;");
		s = s.replace(/>/g, "&gt;");
		this.innerHTML = s;
	});

	HTMLElement.prototype.__defineGetter__("innerText", function () {
		var _WSMULT = new RegExp("^\\s*|\\s*$", "g");
		var _WSENDS = new RegExp("\\s\\s+", "g");
		var s = this.innerHTML;
		s = s.replace(/<[^>]+>/g,"");
		s = s.replace(_WSENDS, " ");
		s = s.replace(_WSMULT, " ");
		return s;
	});

	/**
	 * Emulate IE's onreadystatechange attribute
	 */ 
	Document.prototype.onreadystatechange = null;

	// NOTE: setting async to false will only work with documents
	// called over HTTP (meaning a server), not the local file system,
	// unless you are using Moz 1.4+.
	// BTW the try>catch block is for 1.4; I haven't found a way to check if
	// the property is implemented without
	// causing an error and I dont want to use user agent stuff for that...
	var _SYNC_NON_IMPLEMENTED = false; 
	try {
		/**
		 * <p>Emulates IE's async property for Moz versions prior to 1.4.
		 * It controls whether loading of remote XML files works
		 * synchronously or asynchronously.</p>
		 */
		XMLDocument.prototype.async = true;
		_SYNC_NON_IMPLEMENTED = true;
	}
	catch (ex) {
		/* trap */
	}
	XMLDocument.prototype.debug = false;
	/**
	 * <p>Overrides the original load method to provide synchronous loading for
	 * Mozilla versions prior to 1.4, using an XMLHttpRequest object (if
	 * async is set to false)</p>
	 * @returns the DOM Object as it was before the load() call (may be  empty)
	 */
	XMLDocument.prototype.load = function (sURI) {
		var oDoc = document.implementation.createDocument("", "", null);
		oDoc._copyDOM(this);
		try {
			if (this.async == false && _SYNC_NON_IMPLEMENTED) {
				var tmp = new XMLHttpRequest();
				tmp.open("GET", sURI, false);
				tmp.send(null);
				if (!this.preserveWhiteSpace) rm_whitespace(tmp.responseXML.documentElement);
				this._copyDOM(tmp.responseXML);
			}
			else
				this.load(sURI);
		}
		catch (ex) {
		}
		finally {
		}
		return oDoc;
	}; 

	function WMNodeList(i) {
		this.length = i;
	};
	/** <p>Set an Array as the prototype object</p> */
	WMNodeList.prototype = new Array(0);
	/** <p>Inherit the Array constructor </p> */
	WMNodeList.prototype.constructor = Array;
	/**
	* <p>Returns the node at the specified index or null if the given index
	* is greater than the list size or less than zero </p>
	* <p><b>Note</b> that in ECMAScript you can also use the square-bracket
	* array notation instead of calling <code>item</code>
	* @argument i the index of the member to return
	* @returns the member corresponding to the given index
	*/
	WMNodeList.prototype.item = function(i) {
		return (i < 0 || i >= this.length) ? null : this[i];
	};
	/**
	* <p>Emulate IE's expr property
	* (Here the SarissaNodeList object is given as the result of selectNodes).</p>
	* @returns the XPath expression passed to selectNodes that resulted in
	*		  this SarissaNodeList
	*/
	WMNodeList.prototype.expr = "";
	/** dummy, used to accept IE's stuff without throwing errors */
	XMLDocument.prototype.setProperty  = function(x,y){};
	/**
	* <p>Programmatically control namespace URI/prefix mappings for XPath
	* queries.</p>
	* <p>This method comes especially handy when used to apply XPath queries
	* on XML documents with a default namespace, as there is no other way
	* of mapping that to a prefix.</p>
	* <p>Using no namespace prefix in DOM Level 3 XPath queries, implies you
	* are looking for elements in the null namespace. If you need to look
	* for nodes in the default namespace, you need to map a prefix to it
	* first like:</p>
	* <pre>Sarissa.setXpathNamespaces(oDoc, &quot;xmlns:myprefix=&amp;aposhttp://mynsURI&amp;apos&quot;);</pre>
	* <p><b>Note 1 </b>: Use this method only if the source document features
	* a default namespace (without a prefix), otherwise just use IE's setProperty
	* (moz will rezolve non-default namespaces by itself). You will need to map that
	* namespace to a prefix for queries to work.</p>
	* <p><b>Note 2 </b>: This method calls IE's setProperty method to set the
	* appropriate namespace-prefix mappings, so you dont have to do that.</p>
	* @param oDoc The target XMLDocument to set the namespace mappings for.
	* @param sNsSet A whilespace-seperated list of namespace declarations as
	*			those would appear in an XML document. E.g.:
	*			<code>&quot;xmlns:xhtml=&apos;http://www.w3.org/1999/xhtml&apos;
	* xmlns:&apos;http://www.w3.org/1999/XSL/Transform&apos;&quot;</code>
	* @throws An error if the format of the given namespace declarations is bad.
	*/
	XMLDocument.prototype.setXpathNamespaces = function(sNsSet) {
		//oDoc._sarissa_setXpathNamespaces(sNsSet);
		this.__useCustomResolver = true;
		var namespaces = sNsSet.indexOf(" ") > -1 ? sNsSet.split(" ") : new Array(sNsSet);
		this.__xpathNamespaces = new Array(namespaces.length);
		for (var i = 0; i < namespaces.length; i++) {
			var ns = namespaces[i];
			var colonPos = ns.indexOf(":");
			var assignPos = ns.indexOf("=");
			if (colonPos == 5 && assignPos > colonPos + 2) {
				var prefix = ns.substring(colonPos + 1, assignPos);
				var uri = ns.substring(assignPos + 2, ns.length - 1);
				this.__xpathNamespaces[prefix] = uri;
			} else {
				throw "Bad format on namespace declaration(s) given";
			};
		};
	};
    /**
    * @private Flag to control whether a custom namespace resolver should
    *          be used, set to true by Sarissa.setXpathNamespaces
    */
    XMLDocument.prototype.__useCustomResolver = false;
    /** @private */
    XMLDocument.prototype.__xpathNamespaces = new Array();

	XMLDocument.prototype.selectNodes = function(sExpr, contextNode) {
		try {
			var nsDoc = this;
			var nsresolver = this.__useCustomResolver
			? function(prefix) {
				var s = nsDoc.__xpathNamespaces[prefix];
				if (s) return s;
				else throw "No namespace URI found for prefix: '" + prefix + "'";
			}
			: this.createNSResolver(this.documentElement);
				var oResult = this.evaluate(sExpr,
					(contextNode?contextNode:this),
					nsresolver,
					XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
			var nodeList = new WMNodeList(oResult.snapshotLength);
			nodeList.expr = sExpr;
			for (var i = 0; i < nodeList.length; i++)
				nodeList[i] = oResult.snapshotItem(i);
			return nodeList;
		} catch (ex) {
			if (this.debug) {
				alert(ex);
				// document.body.innerHTML = '<pre style="width: 500px; overflow: auto;">' + xmlEscape(this.xml) + "</pre>";
				var debug = window.open("about:blank");
				debug.document.write('<textarea style="width: 100%; height: 100%"> ' + this.xml + ' </textarea>');
			}
		}
	};
	/*
	XMLDocument.prototype.selectNodes = function(sExpr, contextNode) {
		if (this.documentElement == null) return new Array();
		var oResult = this.evaluate(sExpr, (contextNode ? contextNode : this), 
							this.createNSResolver(this.documentElement),
							XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
		var nodeList = new WMNodeList(oResult.snapshotLength);
		nodeList.expr = sExpr;
		for(i = 0; i < nodeList.length; i++)
			nodeList[i] = oResult.snapshotItem(i);
		return nodeList;
	};
	*/
	/**
	 * <p>Extends the Element to emulate IE's selectNodes</p>
	 * @argument sExpr the XPath expression to use
	 * @returns the result of the XPath search as an (Sarissa)NodeList
	 * @throws An
	 *			 error if invoked on an HTML Element as this is only be
	 *			 available to XML Elements.
	 */
	Element.prototype.selectNodes = function(sExpr) {
		var doc = this.ownerDocument;
		if (doc.selectNodes)
			return doc.selectNodes(sExpr, this);
		else
			throw new Error("Method selectNodes is only supported by XML Elements");
	};
	/**
	 * <p>Extends the XMLDocument to emulate IE's selectSingleNodes.</p>
	 * @argument sExpr the XPath expression to use
	 * @argument contextNode this is for internal use only by the same
	 *		   method when called on Elements
	 * @returns the result of the XPath search as an (Sarissa)NodeList
	 */
	XMLDocument.prototype.selectSingleNode = function(sExpr, contextNode) {
		var ctx = contextNode ? contextNode : null;
		sExpr += "[1]";
		var nodeList = this.selectNodes(sExpr, ctx);
		if (nodeList && nodeList.length > 0)
			return nodeList[0];
		else 
			return null;
	};
	/**
	 * <p>Extends the Element to emulate IE's selectNodes.</p>
	 * @argument sExpr the XPath expression to use
	 * @returns the result of the XPath search as an (Sarissa)NodeList
	 * @throws An error if invoked on an HTML Element as this is only be
	 *			 available to XML Elements.
	 */
	Element.prototype.selectSingleNode = function(sExpr) {
		var doc = this.ownerDocument;
		if (doc.selectSingleNode)
			return doc.selectSingleNode(sExpr, this);
		else
			throw new Error("Method selectNodes is only supported by XML Elements");
	};
}

var isXmlExtras = true;

