/* namespacing object */
var net = {};

net.READY_STATE_UNINITIALIZED = 0;
net.READY_STATE_LOADING = 1;
net.READY_STATE_LOADED = 2;
net.READY_STATE_INTERACTIVE = 3;
net.READY_STATE_COMPLETE = 4;

net.SoapEnvelope = '<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><#method# xmlns="http://edeptive.com/webservices/">#params#</#method#></soap:Body></soap:Envelope>';

/*--- content loader object for cross-browser requests ---*/
net.ContentLoader = function(url, params, onload, method, soapMethod, contentType, onerror) {
	var temp;
	
    net.currentLoader = this;
    this.req = null;
    this.onload = onload;
    this.onerror = (onerror) ? onerror : this.defaultError;
	this.soapMethod = soapMethod;
	
	if (params && typeof(params) != "string") {
		if (this.soapMethod) {
			temp = "";
			for (key in params) {
				temp += "<" + key + ">" + String(params[key]) + "</" + key + ">";
			}
		} else {
			temp = "";
			for (key in params) {
				temp += (temp.length > 0 ? "&" : "") + key + "=" + (!method || method.toLowerCase() == "get" ? escape(params[key]) : params[key]);
			}
		}
		params = temp;
	} else if (!params) {
		params = "";
	}
		
    this.loadXMLDoc(url, method, params, contentType);
};

net.ContentLoader.prototype.loadXMLDoc = function(url, method, params, contentType) {
    if (!method) {
        method = (this.soapMethod ? "POST" : "GET");
    }
	
    if (!contentType && method == "POST") {
        contentType = (this.soapMethod ? "text/xml; charset=utf-8" : "application/x-www-form-urlencoded");
    }
	
    if (window.XMLHttpRequest) {
        this.req = new XMLHttpRequest();
    } else if (window.ActiveXObject) {
        this.req = new ActiveXObject("Microsoft.XMLHTTP");
    }
	
	if (this.soapMethod) {
		params = net.SoapEnvelope.replace(/#method#/gi, this.soapMethod).replace(/#params#/gi, params);
	}
	
    if (this.req) {
        //try {
            var loader = this;
            this.req.onreadystatechange = function() {
                net.ContentLoader.onReadyState.call(loader);
            };
            this.req.open(method, url, true);
            if (contentType) {
                this.req.setRequestHeader('Content-Type', contentType);
				if (this.soapMethod) {
					this.req.setRequestHeader("SOAPAction", "http://edeptive.com/webservices/" + this.soapMethod);
				}
            }
            this.req.send(params);
        //} catch (err) {
        //    this.onerror.call(this);
        //}
    }
};

net.ContentLoader.onReadyState = function() {
    var req = this.req;
    var ready = req.readyState;
    if (ready == net.READY_STATE_COMPLETE) {
        var httpStatus = req.status;
        if (httpStatus == 200 || httpStatus === 0) {
        	if (typeof(this.onload) != "undefined" && this.onload) {
	            this.onload.call(this);
	        }
        } else {
            this.onerror.call(this);
        }
    }
};

net.ContentLoader.prototype.defaultError = function() {
    alert("error fetching data!"
            + "\n\nreadyState:" + this.req.readyState
            + "\nstatus: " + this.req.status
            + "\nheaders: " + this.req.getAllResponseHeaders());
};

net.ContentLoader.prototype.getSoapResult = function() {
	var rx = new RegExp("<" + this.soapMethod + "Result>(.*?)</" + this.soapMethod + "Result>");
	var matches = this.req.responseText.match(rx);
	return (matches && matches.length > 0 ? matches[1] : null);
};


// *** Bunzl Netherlands functions ***

var waitingForAjax = 0;
var pageErrors = 0;
var pageErrorsHighSev = 0;
var errorDetail = {};
var cachedBreaks = {};
var catalogue = "arnhem"; // which catalogue are we looking at? ( arnhem / almere)
var processingAjaxComplete = false;
var ajaxCompleteFunctions = [];
var ajaxCompleteFunctionsReadIndex = 0;
var ajaxCompleteFunctionsAddIndex = 0;

function getPrice(productCode, qty) {
	var url = "BunzlProxy.asmx";
	var newQty;
	
	qty = qty.toString();
	if (qty.length > 0) {
		qty = parseInt(qty.replace(/\..*/g, ""), 10);
		if (isNaN(qty) || qty < 0) {
			qty = 1;
		}
		newQty = qty;
	} else {
		qty = 1;
		newQty = "";
	}

	document.getElementById("prod_" + productCode + "_price").innerHTML = "<img src='assets/images/wait.gif' width='16' height='16' />";
	ajaxStart();
	var loader = new net.ContentLoader(
		url, 
		{ "strProductCode": productCode, "iQty": qty },
		function() {
			document.getElementById("prod_" + productCode + "_price").innerHTML = formatPriceString(this.getSoapResult());
			ajaxEnd();
		},
		null, 
		"GetPrice"
	);
	
	return newQty;
}

function renderPrice(productCode, qty, fromCallback, onComplete) {
	var html = "";
	var price = -1;
	var priceContainer = document.getElementById("prod_" + productCode + "_price");
	var linePriceContainer = document.getElementById("prod_" + productCode + "_lineprice");
	var newQty;
	
	qty = qty.toString();
	if (qty.length > 0) {
		qty = parseInt(qty.replace(/\..*/g, ""), 10);
		if (isNaN(qty) || qty < 0) {
			qty = 1;
		}
		newQty = qty;
	} else {
		qty = 1;
		newQty = "";
	}
	
	if (qty > 0) {
		price = getPriceFromBreaks(productCode, qty);
		
		if (price < 0) {
			if (!fromCallback) {
				document.getElementById("prod_" + productCode + "_price").innerHTML = "<img src='assets/images/wait.gif' width='16' height='16' />";
				getBreaks(
					productCode, 
					function() {
						renderPrice(productCode, qty, true, onComplete);
						renderBreaks(productCode, qty, true);
					}
				);
			}
			return newQty;
		}
	}
	
	if (typeof(priceContainer) != "undefined" && priceContainer) {
		priceContainer.innerHTML = formatPriceString(price);
	}
	if (typeof(linePriceContainer) != "undefined" && linePriceContainer) {
		linePriceContainer.innerHTML = formatPriceString(parseInt(price, 10) * qty);
	}
	if (typeof(onComplete) != "undefined" && onComplete) {
		onComplete(productCode, qty, price);
	}
	return newQty;
}

function getPriceFromBreaks(productCode, qty) {
	var price = -1;
	var breaks = cachedBreaks[productCode];
	
	if (breaks) {
		for (seq in breaks) {
			if (qty >= breaks[seq].qty) {
				price = breaks[seq].price;
				break;
			}
		}
	}
	return price;
}

function formatPrice(price) {
	price = String(price);
	price = price.replace(/(\.\d\d)0+/, "$1");
	if (price.indexOf(".") > -1) {
		if (price.indexOf(".") == price.length - 2) {
			price += "0";
		}
	} else {
		price += ".00"
	}
	return "&euro;&nbsp;" + price;
}

function formatPriceString(price, noSymbol) {
	var priceFormatted = "00000" + String(price);
	if (price != null && price != -1) {
		priceFormatted = priceFormatted.slice(0, -4) + "." + priceFormatted.slice(-4);
		//priceFormatted = priceFormatted.replace(/(\.\d\d[123456789]{0,2})0+/, "$1"); // remove trailing zeros
		priceFormatted = priceFormatted.replace(/^0+([123456789]*\d\.)/, "$1");
		priceFormatted = (noSymbol ? "" : "&euro;&nbsp;") + priceFormatted.replace(/\./, ",");
	} else {
		priceFormatted = "...";
	}
	//alert(price + " -- " + priceFormatted);
	return priceFormatted;
}

function getProductDetails(productCode, onComplete, defaultTitle, fieldSuffix) {
	var url = "webservices/io.asmx";
	var prodTitle = "~~~";
	
	defaultTitle = defaultTitle || "";
	fieldSuffix = fieldSuffix || productCode;

	ajaxStart();
	var loader = new net.ContentLoader(
		url, 
		{ "ParentID": (catalogue == "arnhem" ? "4:34173" : "34815"), "ModuleID": 5, "MatchField": "product_code", "MatchValue": productCode, "ExactMatch": "true", "ImpersonateAdmin": "false" },
		function() {
			var item = eval("(" + xml2json(this.getSoapResult(), "") + ")");
			
			var elem = document.getElementById("title_" + fieldSuffix);
			if (typeof(elem) != "undefined" && elem) {
				prodTitle = getValueByPath(item, "content/content_item/title/#cdata", defaultTitle);
				elem.innerHTML = prodTitle;
			}
			
			elem = document.getElementById("units_" + fieldSuffix);
			if (typeof(elem) != "undefined" && elem) {
				elem.innerHTML = getValueByPath(item, "content/content_item/units", "");
			}
			
			elem = document.getElementById("qty_" + fieldSuffix);
			if (typeof(elem) != "undefined" && elem) {
				elem.name = "qty" + getValueByPath(item, "content/content_item/@id", "qty_" + productCode);
			}
			
			elem = document.getElementById("prod_" + fieldSuffix + "_minqty");
			if (typeof(elem) != "undefined" && elem) {
				elem.value = getValueByPath(item, "content/content_item/min_order_quantity", "1");
			}
			
			elem = document.getElementById("prod_" + fieldSuffix + "_maxqty");
			if (typeof(elem) != "undefined" && elem) {
				elem.value = getValueByPath(item, "content/content_item/max_order_quantity", "100000");
			}
			
			elem = document.getElementById("prod_" + fieldSuffix + "_stepqty");
			if (typeof(elem) != "undefined" && elem) {
				elem.value = getValueByPath(item, "content/content_item/base_product_code", "1");
			}
			
			elem = document.getElementById("base_product_code_" + fieldSuffix);
			if (typeof(elem) != "undefined" && elem) {
				elem.value = getValueByPath(item, "content/content_item/base_product_code", "1");
			}
			
			if (typeof(onComplete) != "undefined" && onComplete && prodTitle != defaultTitle) {
				onComplete(productCode);
			}
			ajaxEnd();
		},
		null, 
		"getItemsExtended"
	);
}

function detailPopup(iID) {
	window.open("product_image_1.aspx?cat=" + iID, "detail_win", "width=600,height=300,resizable=yes,scrollbars=yes");
}

function checkQty(productCode) {
	var ok = true;
	var qty = document.getElementById("qty_" + productCode).value;
	var min, max, step;
	var errorText;

	qty = parseInt(qty, 10);
	if (isNaN(qty) || String(qty) != document.getElementById("qty_" + productCode).value) {
		errorText = document.getElementById("QtyErrorText").value;
		ok = false;
	} else {
		min = parseInt(document.getElementById("prod_" + productCode + "_minqty").value, 10);
		max = parseInt(document.getElementById("prod_" + productCode + "_maxqty").value, 10);
		step = parseInt(document.getElementById("prod_" + productCode + "_stepqty").value, 10);
	
		if (min > 0 && qty < min) {
			errorText = document.getElementById("MinQtyText").value + min;
			ok = false;
		} else if (max > 0 && qty > max) {
			errorText = document.getElementById("MaxQtyText").value + max;
			ok = false;
		} else if (step > 1 && qty / step != Math.round(qty / step)) {
			errorText = document.getElementById("StepQtyText").value + step;
			ok = false;
		}
	}

	if (!ok) {
		addPageError("qty_" + productCode, errorText, true);
		alert(errorText);
	} else {
		clearPageError("qty_" + productCode);
	}
	
	return ok;
}
				
function updateShortcut(itemID, desc) {
	var url = "webservices/io.asmx";

	var loader = new net.ContentLoader(
		url, 
		{ "ItemID": itemID, "ModuleID": 5, "Description": desc },
		function() {
			var result = this.getSoapResult();
			
			if (result) {
				alert(result);
			}
		},
		null, 
		"updateShortcut"
	);
}

function modifyShortcut(action, itemID, productCode, hiddenItemsAreShown, page, multiItems) {
	// action = hide / unhide / delete / add
	var url = "webservices/io.asmx";
	var img = null;
	
	img = document.getElementById("regbuyimg_" + itemID + "_" + action);
	if (img) {
		img.prevsrc = img.src;
		img.src = "assets/images/wait.gif";
		img.width = "16";
		img.height = "16";
	}
	
	var loader = new net.ContentLoader(
		url, 
		{ "Action": action, "ItemID": (multiItems ? multiItems : itemID), "ModuleID": 5 },
		function() {
			var result = this.getSoapResult();
			var img, link;
			
			if (result) {
				alert(result);
			} else {
				img = document.getElementById("regbuyimg_" + itemID + "_hide");
				if (img) {
					img.width = "25";
					img.height = "12";
					img.src = img.prevsrc;
				}
				if (action != "add") {
					link = document.getElementById("regbuylink_" + itemID + "_hide");
					if (link)
						link.style.display = "none";
					link = document.getElementById("regbuylink_" + itemID + "_add");
					if (link)
						link.style.display = "inline";
				} else {
					link = document.getElementById("regbuylink_" + itemID + "_hide");
					if (link)
						link.style.display = "inline";
					link = document.getElementById("regbuylink_" + itemID + "_add");
					if (link)
						link.style.display = "none";
				}
				if (page == "regbuys" && action == "hide") {
					document.getElementById("qty_" + productCode).value = "";
					if (!hiddenItemsAreShown) {
						//document.getElementById("regbuyrow_" + itemID).style.display = "none";
						var temp = document.getElementById("regbuyrow_" + itemID).getElementsByTagName("TD");
						for (var i = temp.length - 1; i >= 0; i--) {
							if (temp[i].id) {
								opacity(temp[i].id, 100, 0, 1200, function() { regbuysHideRow(itemID); });
							}
						}
					}
				}
			}
		},
		null, 
		"modifyShortcut"
	);
}

function regbuysHideRow(itemID) {
	var row = document.getElementById("regbuyrow_" + itemID);
	if (row.style.display != "none") {
		row.style.display = "none";
		regbuysUpdateRowCss();
	}
}

function regbuysUpdateRowCss() {
	var rows = document.getElementById("regbuystable").getElementsByTagName("TR");
	var rowCount = 0;
	
	for (var i = 0; i < rows.length; i++) {
		if (rows[i].id && rows[i].id.substr(0, 10) == "regbuyrow_") {
			if (rows[i].style.display != "none") {
				rows[i].className = "catrow" + (1 + (rowCount % 2));
				rowCount++;
			}
		}
	}
}

function getBreaks(productCode, completeFnc) {
	var url = "BunzlProxy.asmx"; //http://193.128.120.227/

	ajaxStart();
	var loader = new net.ContentLoader(
		url, 
		{ "strProductCode": productCode },
		function() {
			var priceBreak, html;
			var breaks = eval("(" + this.getSoapResult() + ")");
			
			if (!breaks) {
				alert("Unable to obtain price information. Your session may have expired - please log in again and re-try.");
				location.reload();
			} else {
				cachedBreaks[productCode] = breaks;
				if (completeFnc) {
					completeFnc();
				}
			}
			ajaxEnd();
		},
		null, 
		"GetLaddersForItem"
	);
}

function renderBreaks(productCode, currentQty, fromCallback) {
	var html = "";
	var breaks = cachedBreaks[productCode];
	var breaksContainer = document.getElementById("prod_" + productCode + "_breaks");
	var qty, found;
	
	if (!breaksContainer) {
		return false;
	}
	
	if (typeof(currentQty) == "string") {
		if (currentQty.length === 0) {
			currentQty = 0;
		} else {
			currentQty = parseInt(currentQty, 10);
			if (isNaN(currentQty) || currentQty < 0) {
				currentQty = 1;
			}
		}
	}
	
	if (!breaks) {
		if (!fromCallback) {
			breaksContainer.innerHTML = "<img src='assets/images/wait.gif' width='16' height='16' />";
			getBreaks(
				productCode, 
				function() {
					renderBreaks(productCode, currentQty, true);
				}
			);
		} else {
			alert("There was an error obtaining the price information. This may be because your session has timed-out - please ensure that you are logged in and try again.\n\n If you continue to receive this error please contact us.");
			window.location.reload();
		}
		return;
	}
	
	found = false;
	for (var i = 0; i < breaks.length; i++) {
		qty = parseInt(breaks[i].qty, 10);
		html += "<tr><td>";
		if (!found && currentQty >= qty) {
			found = true;
			html += "<img src='assets/images/right_arrow.gif' width='16' height='16' alt='' align='absmiddle' />";
		} else {
			html += "<img src='assets/images/shim.gif' width='16' height='16' alt='' align='absmiddle' />";
		}
		html += "</td><td>" + breaks[i].qty + "</td><td>&nbsp;&nbsp;&nbsp;</td><td>" + formatPriceString(breaks[i].price) + "</td>";
		html += "<td><img src='assets/images/shim.gif' width='16' height='16' alt='' align='absmiddle' /></td></tr>";
	}
	document.getElementById("prod_" + productCode + "_breaks").innerHTML = "<table border='0' cellpadding='1' cellspacing='1' style='border: 1px solid #999;'>" + html + "</table>";

	return (currentQty === 0 ? "" : currentQty);
}

function addPageError(errorKey, errorText, highSev) {
	if (!errorDetail[errorKey]) {
		if (highSev) {
			pageErrorsHighSev++;
		}
		pageErrors++;
	}
	errorDetail[errorKey] = { "msg": errorText, "highSev": (highSev ? true : false) };
	checkSubmitButton();
}

function clearPageError(errorKey) {
	if (errorDetail[errorKey]) {
		if (errorDetail[errorKey].highSev) {
			pageErrorsHighSev--;
		}
		pageErrors--;
		errorDetail[errorKey] = null;
	}
}

function ajaxStart() {
	waitingForAjax++;
}

function ajaxEnd() {
	waitingForAjax--;
	checkAjaxComplete();
}

function submitForm(formId, waitImages) {
	onAjaxComplete(
		function() {
			document.getElementById(formId).submit();
		},
		waitImages,
		true
	);
}

function onAjaxComplete(fnc, waitImages, blocking) {
	setDisplayStyle(waitImages, "inline");
	ajaxCompleteFunctions[ajaxCompleteFunctionsAddIndex++] = {
		"fnc": fnc, 
		"waitImages": waitImages, 
		"blocking": (typeof(blocking) != "undefined" && fnc ? true : false)
	};
	checkAjaxComplete();
}

function setDisplayStyle(arrElems, displayValue) {
	var elem;
	
	if (!arrElems) return;
	for (var i = arrElems.length - 1; i >= 0; i--) {
		elem = document.getElementById(arrElems[i]);
		if (typeof(elem) != "undefined" && elem) {
			elem.style.display = displayValue;
		}
	}
}

function checkAjaxComplete() {
	var fncDef;
	
	if (processingAjaxComplete) return false;
	processingAjaxComplete = true;
	
	while (waitingForAjax === 0 && ajaxCompleteFunctionsReadIndex < ajaxCompleteFunctionsAddIndex) {
		fncDef = ajaxCompleteFunctions[ajaxCompleteFunctionsReadIndex];
		if (fncDef && fncDef.fnc) {
			if (!fncDef.blocking) {
				setTimeout(
					function() {
						fncDef.fnc();
						setDisplayStyle(fncDef.waitImages, "none");
					},
					1
				);
			} else {
				fncDef.fnc();
				setDisplayStyle(fncDef.waitImages, "none");
			}
		}
		ajaxCompleteFunctions[ajaxCompleteFunctionsReadIndex++] = null;
	}
	
	processingAjaxComplete = false;
	return true;
}

function checkSubmitButton() {
	var button1 = document.getElementById("add_to_basket");
	var button2 = document.getElementById("checkout");
	
	if (button1) {
		button1.disabled = pageErrorsHighSev > 0;
	}
	if (button2) {
		button2.disabled = pageErrors > 0;
	}
}


/*	This work is licensed under Creative Commons GNU LGPL License.

	License: http://creativecommons.org/licenses/LGPL/2.1/
   Version: 0.9
	Author:  Stefan Goessner/2006
	Web:     http://goessner.net/ 
*/
function xml2json(xml, tab) {
   if (typeof(xml) == "string") {
      xml = parseXml(xml);
   }
   var X = {
      toObj: function(xml) {
         var o = {};
         if (xml.nodeType==1) {   // element node ..
            if (xml.attributes.length)   // element with attributes  ..
               for (var i=0; i<xml.attributes.length; i++)
                  o["@"+xml.attributes[i].nodeName] = (xml.attributes[i].nodeValue||"").toString();
            if (xml.firstChild) { // element has child nodes ..
               var textChild=0, cdataChild=0, hasElementChild=false;
               for (var n=xml.firstChild; n; n=n.nextSibling) {
                  if (n.nodeType==1) hasElementChild = true;
                  else if (n.nodeType==3 && n.nodeValue.match(/[^ \f\n\r\t\v]/)) textChild++; // non-whitespace text
                  else if (n.nodeType==4) cdataChild++; // cdata section node
               }
               if (hasElementChild) {
                  if (textChild < 2 && cdataChild < 2) { // structured element with evtl. a single text or/and cdata node ..
                     X.removeWhite(xml);
                     for (var n=xml.firstChild; n; n=n.nextSibling) {
                        if (n.nodeType == 3)  // text node
                           o["#text"] = X.escape(n.nodeValue);
                        else if (n.nodeType == 4)  // cdata node
                           o["#cdata"] = X.escape(n.nodeValue);
                        else if (o[n.nodeName]) {  // multiple occurence of element ..
                           if (o[n.nodeName] instanceof Array)
                              o[n.nodeName][o[n.nodeName].length] = X.toObj(n);
                           else
                              o[n.nodeName] = [o[n.nodeName], X.toObj(n)];
                        }
                        else  // first occurence of element..
                           o[n.nodeName] = X.toObj(n);
                     }
                  }
                  else { // mixed content
                     if (!xml.attributes.length)
                        o = X.escape(X.innerXml(xml));
                     else
                        o["#text"] = X.escape(X.innerXml(xml));
                  }
               }
               else if (textChild) { // pure text
                  if (!xml.attributes.length)
                     o = X.escape(X.innerXml(xml));
                  else
                     o["#text"] = X.escape(X.innerXml(xml));
               }
               else if (cdataChild) { // cdata
                  if (cdataChild > 1)
                     o = X.escape(X.innerXml(xml));
                  else
                     for (var n=xml.firstChild; n; n=n.nextSibling)
                        o["#cdata"] = X.escape(n.nodeValue);
               }
            }
            if (!xml.attributes.length && !xml.firstChild) o = null;
         }
         else if (xml.nodeType==9) { // document.node
            o = X.toObj(xml.documentElement);
         }
         else
            alert("unhandled node type: " + xml.nodeType);
         return o;
      },
      toJson: function(o, name, ind) {
         var json = name ? ("\""+name+"\"") : "";
         if (o instanceof Array) {
            for (var i=0,n=o.length; i<n; i++)
               o[i] = X.toJson(o[i], "", ind+"\t");
            json += (name?":[":"[") + (o.length > 1 ? ("\n"+ind+"\t"+o.join(",\n"+ind+"\t")+"\n"+ind) : o.join("")) + "]";
         }
         else if (o == null)
            json += (name&&":") + "null";
         else if (typeof(o) == "object") {
            var arr = [];
            for (var m in o)
               arr[arr.length] = X.toJson(o[m], m, ind+"\t");
            json += (name?":{":"{") + (arr.length > 1 ? ("\n"+ind+"\t"+arr.join(",\n"+ind+"\t")+"\n"+ind) : arr.join("")) + "}";
         }
         else if (typeof(o) == "string")
            json += (name&&":") + "\"" + o.toString() + "\"";
         else
            json += (name&&":") + o.toString();
         return json;
      },
      innerXml: function(node) {
         var s = ""
         if ("innerHTML" in node)
            s = node.innerHTML;
         else {
            var asXml = function(n) {
               var s = "";
               if (n.nodeType == 1) {
                  s += "<" + n.nodeName;
                  for (var i=0; i<n.attributes.length;i++)
                     s += " " + n.attributes[i].nodeName + "=\"" + (n.attributes[i].nodeValue||"").toString() + "\"";
                  if (n.firstChild) {
                     s += ">";
                     for (var c=n.firstChild; c; c=c.nextSibling)
                        s += asXml(c);
                     s += "</"+n.nodeName+">";
                  }
                  else
                     s += "/>";
               }
               else if (n.nodeType == 3)
                  s += n.nodeValue;
               else if (n.nodeType == 4)
                  s += "<![CDATA[" + n.nodeValue + "]]>";
               return s;
            };
            for (var c=node.firstChild; c; c=c.nextSibling)
               s += asXml(c);
         }
         return s;
      },
      escape: function(txt) {
         return txt.replace(/[\\]/g, "\\\\")
                   .replace(/[\"]/g, '\\"')
                   .replace(/[\n]/g, '\\n')
                   .replace(/[\r]/g, '\\r');
      },
      removeWhite: function(e) {
         e.normalize();
         for (var n = e.firstChild; n; ) {
            if (n.nodeType == 3) {  // text node
               if (!n.nodeValue.match(/[^ \f\n\r\t\v]/)) { // pure whitespace text node
                  var nxt = n.nextSibling;
                  e.removeChild(n);
                  n = nxt;
               }
               else
                  n = n.nextSibling;
            }
            else if (n.nodeType == 1) {  // element node
               X.removeWhite(n);
               n = n.nextSibling;
            }
            else                      // any other node
               n = n.nextSibling;
         }
         return e;
      }
   };
   if (xml.nodeType == 9) // document node
      xml = xml.documentElement;
   var json = X.toJson(X.toObj(X.removeWhite(xml)), xml.nodeName, "\t");
   return "{\n" + tab + (tab ? json.replace(/\t/g, tab) : json.replace(/\t|\n/g, "")) + "\n}";
}

function parseXml(xml) {
   var dom = null;
   if (window.DOMParser) {
      try { 
         dom = (new DOMParser()).parseFromString(xml, "text/xml"); 
      } 
      catch (e) { dom = null; }
   }
   else if (window.ActiveXObject) {
      try {
         dom = new ActiveXObject('Microsoft.XMLDOM');
         dom.async = false;
         if (!dom.loadXML(xml)) // parse error ..

            window.alert(dom.parseError.reason + dom.parseError.srcText);
      } 
      catch (e) { dom = null; }
   }
   else
      alert("cannot parse xml string!");
   return dom;
}

function getValueByPath(obj, path, dflt) {
	var keys = path.split("/");
	var found = true;
	
	for (var i = 0; i < keys.length; i++) {
		if (typeof(obj[keys[i]]) != "undefined" && obj[keys[i]]) {
			obj = obj[keys[i]];
		} else {
			found = false;
			break;
		}
	}
	return (found ? obj : dflt);
}

/*
AddEvent Manager (c) 2005-2006 Angus Turnbull http://www.twinhelix.com
Free usage permitted as long as this credit notice remains intact.
*/

if (typeof addEvent != 'function')
{
 var addEvent = function(o, t, f, l)
 {
  var d = 'addEventListener', n = 'on' + t, rO = o, rT = t, rF = f, rL = l;
  if (o[d] && !l) return o[d](t, f, false);
  if (!o._evts) o._evts = {};
  if (!o._evts[t])
  {
   o._evts[t] = o[n] ? { b: o[n] } : {};
   o[n] = new Function('e',
    'var r = true, o = this, a = o._evts["' + t + '"], i; for (i in a) {' +
     'o._f = a[i]; r = o._f(e||window.event) != false && r; o._f = null;' +
     '} return r');
   if (t != 'unload') addEvent(window, 'unload', function() {
    removeEvent(rO, rT, rF, rL);
   });
  }
  if (!f._i) f._i = addEvent._i++;
  o._evts[t][f._i] = f;
 };
 addEvent._i = 1;
 var removeEvent = function(o, t, f, l)
 {
  var d = 'removeEventListener';
  if (o[d] && !l) return o[d](t, f, false);
  if (o._evts && o._evts[t] && f._i) delete o._evts[t][f._i];
 };
}

// Optional cancelEvent() function you can call within your event handlers to
// stop them performing the normal browser action or kill the event entirely.
// Pass an event object, and the second "c" parameter cancels event bubbling.
function cancelEvent(e, c)
{
 e.returnValue = false;
 if (e.preventDefault) e.preventDefault();
 if (c)
 {
  e.cancelBubble = true;
  if (e.stopPropagation) e.stopPropagation();
 }
};

function onDomReady(funcToCall) {
	if (document.addEventListener) {
		document.addEventListener("DOMContentLoaded", funcToCall, false);
	} else {
		document.write("<scr" + "ipt id='__ieinit' defer='true' " + "src='//:'><\/script>");
		var script = document.getElementById("__ieinit");
		script.onreadystatechange = function() {
			if (this.readyState != "complete") return;
			this.parentNode.removeChild(this);
			funcToCall();
		}
		script = null;
	}
}

function opacity(id, opacStart, opacEnd, millisec, onComplete) {
    //speed for each frame
    var speed = Math.round(millisec / 100);
    var timer = 0;

    //determine the direction for the blending, if start and end are the same nothing happens
    if(opacStart > opacEnd) {
        for(i = opacStart; i >= opacEnd; i--) {
            setTimeout("changeOpac(" + i + ",'" + id + "')",(timer * speed));
            timer++;
        }
        setTimeout("document.getElementById('" + id + "').style.display = 'none';",(timer * speed));
		if (onComplete) {
			setTimeout(onComplete,(timer * speed));
		}
    } else if(opacStart < opacEnd) {
		document.getElementById(id).style.display = '';
        for(i = opacStart; i <= opacEnd; i++)
            {
            setTimeout("changeOpac(" + i + ",'" + id + "')",(timer * speed));
            timer++;
        }
		if (onComplete) {
			setTimeout(onComplete,(timer * speed));
		}
    }
}

//change the opacity for different browsers
function changeOpac(opacity, id) {
    var object = document.getElementById(id).style;
    object.opacity = (opacity / 100);
    object.MozOpacity = (opacity / 100);
    object.KhtmlOpacity = (opacity / 100);
    object.filter = "alpha(opacity=" + opacity + ")";
}

// ***********************************************************************************************************************

// *** pre-load AJAX wait gif
var img = new Image();
img.src = "assets/images/wait.gif";
setInterval(function() { var loader = new net.ContentLoader("webservices/keep_alive.asmx", null, null, "POST", "Ping");	}, 5 * 60 * 1000);



