var focusField = null;
//var isIE = (document.all ? true : false);
//var isNS6 = (navigator.userAgent.indexOf("Gecko") != -1 ? true : false);
var NS4 = (document.layers) ? 1 : 0;
var IE4 = (document.all) ? 1 : 0;
var W3C = (document.getElementById) ? 1 : 0;
var MONTH_NAMES = new Array("January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December");
var MSG_PLEASE_FILL = "Please fill in or change the required fields (marked with a red asterix)";

String.prototype.trim = function() { return this.replace(/^\s*|\s*$/g, ""); };

function alertMessage(msg) {
 	alert(msg);
}

function redirect(url) {
	window.location.href = url;
}

/**
 * Copies a value from one element to the other.
 * NOTE: At present, this may only work on textbox elements.
 * @param oFrom the element to copy the value from
 * @param oTo the element to copy the value to
 * @return true if successful, false otherwise
 * @since 1.0.0
 */
function copyValue(oFrom, oTo) {
	if( oFrom == null || oTo == null ) return false;
	oTo.value = oFrom.value;
	return true;
}

function isValidObject(obj, labelName) {
	if( isNull(obj) || isUndefined(obj) ) {
		alert("setting '" + labelName + "' to * cause unable to locate it's related object");
		if( labelName != null ) setInnerHTML(labelName, "*");
		return false;
	} else return true;
}

function checkChecked(checkboxes, id) {
  var i;
	if( !isValidObject(checkboxes, id) ) return false;
  if( isAtLeastOneChecked(checkboxes) ) {
    clearInnerHTML(id);
		return true;
  } else {
	  setInnerHTML(id, "*");
  	return false;
	}
}

function isAtLeastOneChecked(checkboxes) {
	for( i = 0; checkboxes != null && i < checkboxes.length; i++ ) {
		if( checkboxes[i].checked ) return true;
	}
	return false;
}

function checkSelected(formField, labelName) {
	clearInnerHTML(labelName);
	if( !isValidObject(formField, labelName) ) return false;
	if( !isSomethingSelected(formField) ) {
		setInnerHTML(labelName, "*");
		return false;
	}
	return true;
}

function checkSelectedAndSetFocus(formField, labelName) {
	if( checkSelected(formField, labelName) ) {
		return true;
	} else {
		if( focusField == null ) focusField = formField;
		return false;
	}
}

function isSomethingSelected(formField) {
	if( formField.value == "" || formField.value == "0" || formField.value == "-1" ) return false;
	else return true;
}

function checkDateAndSetFocus(formField, labelName, empty) {
	if( !isValidObject(formField, labelName) ) return false;
  var bRet = checkDate(formField.value, labelName, empty, false);
	if( !bRet && focusField == null ) focusField = formField;
	return bRet;
}

function checkFutureDateAndSetFocus(formField, labelName, empty) {
	if( !isValidObject(formField, labelName) ) return false;
  var bRet = checkDate(formField.value, labelName, empty, true);
	if( !bRet && focusField == null ) focusField = formField;
	return bRet;
}

function checkDate(d, id, empty, mustBeInFuture) {
  var ok = true;
	clearInnerHTML(id);
  if( d == "" ) {
		if( empty ) return true;
		else ok = false;
	}
  var strspl = d.split("/");
	if( ok && strspl.length == 3 ) {
		var inDate = new Date(strspl[2], (strspl[1]-1), strspl[0], 23, 59, 59);
		d = inDate.getYear() + 1900;
		if( strspl[2] < 1901 || strspl[2] > 9999 || 
			inDate.getMonth() != (strspl[1]-1) || inDate.getMonth() >= 12 ||
			inDate.getDate() != strspl[0] || inDate.getDate() >= 32 ) ok = false;
		if( ok ) {
			if( !mustBeInFuture ) return true;
			var now = new Date();
			if( inDate.getTime() > now.getTime() ) return true;
			else ok = false;
		}
	} else ok = false;
	if( !ok ) setInnerHTML(id, "*");
  return ok;
}

/**
function checkNumbers(value, id, empty, minV, maxV) {
  clearInnerHTML(id);
	if( empty != null && !empty && value == "" ) {
    setInnerHTML(id, "*");
    return false;
  }
  if( value != "" && (isNaN(value) || 
		(minV != null && value < minV) || (maxV != null && value > maxV)) ) {
			setInnerHTML(id, "*");
			return false;
  }
  return true;
}
*/

function checkNumbers(value, id, empty, minV, maxV) {
	return checkNumber(value, id, empty, minV, maxV);
}

function checkNumber(value, id, empty, minV, maxV) {
  var s = value.replace(",", "");
	clearInnerHTML(id);
	if( empty != null && !empty && s == "" ) {
    setInnerHTML(id, "*");
    return false;
  }
	if( s != "" && (isNaN(s) || !isNumeric(s) ||
		(minV != null && s < minV) || (maxV != null && s > maxV)) ) {
			setInnerHTML(id, "*");
			return false;
  }
  return true;
}

function checkNumbersAndSetFocus(formField, labelName, empty, minV, maxV) {
	return checkNumberAndSetFocus(formField, labelName, empty, minV, maxV);
}

function checkNumberAndSetFocus(formField, labelName, empty, minV, maxV) {
	if( !isValidObject(formField, labelName) ) return false;
  var bRet = checkNumbers(formField.value, labelName, empty, minV, maxV);
	if( !bRet && focusField == null ) focusField = formField;
	return bRet;
}

function checkPhoneNumbersAndSetFocus(formField, labelName, empty) {
	return checkPhoneNumberAndSetFocus(formField, labelName, empty);
}

function checkPhoneNumberAndSetFocus(formField, labelName, empty) {
	if( !isValidObject(formField, labelName) ) return false;
  var bRet = checkNumeric(formField.value, labelName, empty, null, null);
	if( !bRet && focusField == null ) focusField = formField;
	return bRet;
}

function checkValue(value, id) {
  if( value == '' ) {
  	setInnerHTML(id, "*");
    return false;
  }
  clearInnerHTML(id);
  return true;
}

function checkValueAndSetFocus(formField, labelName) {
	if( !isValidObject(formField, labelName) ) return false;
  var bRet = checkValue(formField.value, labelName);
	if( !bRet && focusField == null ) focusField = formField;
	return bRet;
}

function checkEmail(value, id) {
	if( value == null || value.indexOf("@") <= 0 || value.indexOf(".") <= 0 ) {
		setInnerHTML(id, "*");
		return false;
	}
	clearInnerHTML(id);
	return true;
}

function checkEmailAndSetFocus(formField, labelName) {
	if( !isValidObject(formField, labelName) ) return false;
  var bRet = checkEmail(formField.value, labelName);
	if( !bRet && focusField == null ) focusField = formField;
	return bRet;
}

function checkNumeric(value, id, empty, minV, maxV) {
	clearInnerHTML(id);
  if( empty != null && !empty && value == "" ) {
    setInnerHTML(id, "*");
		return false;
  } else if( empty != null && empty && value == "" ) {
		return true;
	}
  var tmp = "", strChar;
  //  test strString consists of valid characters listed above
  for( i = 0; i < value.length ; i++ ) {
      strChar = value.charAt(i);
      if( strChar != " " && strChar != "-" ) tmp += strChar;
  }
	if( tmp == "" ) return false;
  else if( tmp != "" && (isNaN(tmp) ||
    (minV != null && tmp < minV) || (maxV != null && tmp > maxV)) ) {
    	setInnerHTML(id, "*");
			return false;
  }
	return true;
}

function checkAtLeastOneSelectedAndSetFocus(formField, labelName) {
	if( !isValidObject(formField, labelName) ) return false;
  var bRet = checkAtLeastOneSelected(formField, labelName);
	if( !bRet && focusField == null ) focusField = formField;
	return bRet;
}

function checkAtLeastOneSelected(oSelect, id) {
	if( oSelect == null || oSelect.options.length == 0 ) {
		setInnerHTML(id, "*");
		return false;
	}
	for( i = 0; i < oSelect.options.length; i++ ) {
		if( oSelect.options[i].selected ) {
			clearInnerHTML(id);
			return true;
		}
	}
	setInnerHTML(id, "*");
	return false;
}

function getSelectedValue(sElement) {
	return getObjectSelectedValue(getElement(sElement));
}

function getObjectSelectedValue(oElement) {
	for( i = 0; i < oElement.length; i++ ) {
		if( oElement[i].selected ) return oElement[i].value;
	}
	return null;
}

function getCheckedValue(sForm, sElement) {
	return getObjectCheckedValue(getElementArray(sForm, sElement));
}

function getObjectCheckedValue(oElement) {
	for( i = 0; oElement != null && i < oElement.length; i++ ) {
		if( oElement[i].checked ) return oElement[i].value;
	}
	return null;
}

/**
 * Gets the value of the selected radio button in a radio button group.
 * NOTE: A radio button group is a bunch of radio buttons with the same id/name.
 * @param oRadioGroup the radio button group element
 * @return the value of the selected radio button or null if nothing is selected
 * @since 1.0.0
 */
function getRadioGroupSelectedValue(oRadioGroup) {
	getObjectCheckedValue(oRadioGroup);
}

/**
 * Gets the value of the innerHTML property of the given <span> or <div> element.
 * @param oDiv the id/name of the element to get the contents of
 * @return the innerHTML value or null if the object couldn't be located
 * @since 1.0.0
 */
function getInnerHTML(oDiv) {
	var obj = retrieveElement(oDiv);
	if( obj == null ) return null;
	return obj.innerHTML;
}

/**
 * Clears the innerHTML property of the given <span> or <div> element.
 * @param oDiv the id/name of the element to clear the contents of
 * @return true if the operation was successful, false otherwise
 * @see #setInnerHTML(oDiv, sValue)
 * @since 1.0.0
 */
function clearInnerHTML(oDiv) {
	return setInnerHTML(oDiv, "");
}

/**
 * Sets the innerHTML property of the given <span> or <div> element.
 * @param oDiv the id/name of the element to set the contents of
 * @param sValue the new contents of the supplied element
 * @return true if the operation was successful, false otherwise
 * @since 1.0.0
 */
function setInnerHTML(oDiv, sValue) {
	var obj = retrieveElement(oDiv);
	if( obj != null ) {
		obj.innerHTML = sValue;
		return true;
	}
	return false;
}

function selectAllOptions(oSelect) {
	for( i = 0; i < oSelect.options.length; i++ ) oSelect.options[i].selected = true;
}

function clickElement(obj) {
	if( obj == null ) return;
	var o = retrieveElement(obj);
	if( o == null ) return;
	else {
		o.click();
		o.blur();
	}
}

function clickElementArray(sFormName, sElement, iIndex) {
	var o = getFormElement(sFormName, sElement);
	if( o == null ) return;
	if( isUndefined(o.length) ) {
		clickElement(o);
	} else {
		clickElement(o[iIndex]);
	}
}

function disableElementArray(sFormName, sElement) {
	enableDisableElementArray(false, sFormName, sElement);
}

function disableFormElementArray(sFormName, sElement) {
	enableDisableElementArray(false, sFormName, sElement);
}

function enableElementArray(sFormName, sElement) {
	enableDisableElementArray(true, sFormName, sElement);
}

function enableFormElementArray(sFormName, sElement) {
	enableDisableElementArray(true, sFormName, sElement);
}

function enableDisableElementArray(bEnable, sFormName, sElement) {
	var obj = getFormElement(sFormName, sElement);
	if( obj == null ) return;
	if( isUndefined(obj[0]) ) {
		obj.disabled = !bEnable;
	} else {
		for( i = 0; i < obj.length; i++ ) obj[i].disabled = !bEnable;
	}
}

function selectAllChkBoxItems(oChkBoxArray) {
	setAllChkBoxItems(oChkBoxArray, true);
}

function deselectAllChkBoxItems(oChkBoxArray) {
	setAllChkBoxItems(oChkBoxArray, false);
}

function setAllChkBoxItems(oChkBoxArray, bSelect) {
	for( i = 0; i < oChkBoxArray.length; i++ ) oChkBoxArray[i].checked = bSelect;
}

function selectCheckbox(sChkBox) {
	setChecked(sChkBox, true);
}

function deselectCheckbox(sChkBox) {
	setChecked(sChkBox, false);
}

function setChkBoxItems(oChkBox, bSelect) {
	setChecked(oChkBox, bSelect);
}

function setChecked(oChkBox, bSelect) {
	getElement(oChkBox).checked = bSelect;
}

function helpText(id, text) {
	setInnerHTML(id, text);
}

function showHelpSection(oDiv) {
	if( !showdiv(oDiv) ) return false;
	window.status = getInnerHTML(oDiv);
	return true;
}

function hideHelpSection(oDiv) {
	if( !hidediv(oDiv) ) return false;
	window.status = '';
	return true;
}

function getBrowserSupport() {
	if( W3C ) {
		alert("Your browser is W3C compatible");
	} else if( NS4 ) {
		alert("Your browser is Netscape 4 compatable");
	} else {
		alert("Your browser must be Internet Explorer based");
	}
}

/**
 * Returns the element of the given form and element ID. <br />
 * <B>NOTE:</B> This method (as opposed to getElement()) will return 
 * an object array (i.e. a radio group)
 * @param sForm the name/id of the form where the element resides
 * @param sName the name/id of the element to retrieve
 * @return the element described or null if no item exists
 * @see getElement(String)
 * @since 1.0.0
 */
function getElementArray(sForm, sName) {
	if( sName == null ) {
		sName = sForm;
		sForm = "form";
	}
	var obj = document.forms[sForm].elements[sName];
	if( obj == null ) return null;
	if( IE4 ) {
		if( isUndefined(obj.type) ) return obj;
		else return new Array(obj);
	} else if( W3C && isObject(obj) && obj.constructor != NodeList ) {
		return new Array(obj);
	} else return obj;
}

/**
 * Returns the element of the given form and element ID. <br />
 * <B>NOTE:</B> This method (as opposed to getElement()) will return 
 * an object array (i.e. a radio group)
 * @param sForm the name/id of the form where the element resides
 * @param sName the name/id of the element to retrieve
 * @return the element described or null if no item exists
 * @see getElement(String)
 * @since 1.0.0
 */
function getFormElement(sForm, sName) {
	return getElementArray(sForm, sName);
}

function getElement(sName) {
	if( W3C ) {
		return document.getElementById(sName);
	} else if( NS4 ) {
		return document.layers[sName];
	} else { // meant for IE4
		return document.all[sName];
	}
}

/**
 * Returns a reference to the either the passed-in element or the element with the specified ID.
 * @param obj either an object instance or the ID of the element to retrieve
 * @return a reference to the element
 * @see getElement(String)
 * @since 1.0.0
 */
function retrieveElement(obj) {
	var o = obj;
	if( isString(obj) ) {
		o = getElement(obj);
		if( !isReturnedElementValid(obj, o) ) return null;
	}
	return o;
}

/**
 * Determines whether the passed-in element is valid (not null).
 * @param id the form ID of the element in question
 * @param obj the object to validate
 * @return true if the object is valid, false otherwise
 * @since 1.0.0
 */
function isReturnedElementValid(id, obj) {
	if( isNull(obj) ) {
		alert("Failed to locate the specified element [" + id + "]");
		return false;
	}
	return true;
}

/**
 * Shows or hides everything within the passed <div> tag.
 * Changes visibility to the oposite of it's current state.
 * @param sDiv the ID of the div tag to show or hide
 * @since 1.0.0
 */
function showhide(sDiv) {
	setVisible(sDiv, !isVisible(sDiv));
} 

/**
 * Shows everything within the passed <div> or <span> tag.
 * @param sDiv the ID of the div or span tag to show
 * @since 1.0.0
 */
function show(sDiv) {
	setVisible(sDiv, true);
}

/**
 * Shows everything within the passed <div> or <span> tag.
 * @param sDiv the ID of the div or span tag to show
 * @deprecated since 1.0.0 - use #show() instead
 * @see #show()
 * @since 1.0.0
 */
function showdiv(sDiv) {
	setVisible(sDiv, true);
} 

/**
 * Shows everything within the passed <div> or <span> tag.
 * @param sDiv the ID of the div or span tag to show
 * @see #show()
 * @since 1.0.0
 */
function showElement(sDiv) {
	setVisible(sDiv, true);
}

/**
 * Hides everything within the passed <div> or <span> tag.
 * @param sDiv the ID of the div or span tag to hide
 * @since 1.0.0
 */
function hide(sDiv) {
	setVisible(sDiv, false);
}

/**
 * Hides everything within the passed <div> or <span> tag.
 * @param sDiv the ID of the div or span tag to hide
 * @deprecated since 1.0.0 - use #hide() instead
 * @see #hide()
 * @since 1.0.0
 */
function hidediv(sDiv){ 
	setVisible(sDiv, false);
} 

/**
 * Hides everything within the passed <div> tag.
 * @param sDiv the ID of the div or span tag to hide
 * @see #hide()
 * @since 1.0.0
 */
function hideElement(sDiv) {
	setVisible(sDiv, false);
}

function setVisible(sDiv, bVisible) {
	var obj = retrieveElement(sDiv);
	if( obj == null ) return false;
	if( NS4 ) {
		obj.visibility = (bVisible ? "collapse" : "hidden");
	} else {
		obj.style.display = (bVisible ? "block" : "none");
	}
	return true;
}

function isVisible(oDiv) {
	var obj = retrieveElement(oDiv);
	if( isNull(obj) ) return false;
	if( NS4 ) {
		return ( obj.visibility != "hidden" );
	} else { // IE4 & W3C
		return ( obj.style.display != "none" );
	}
	return false;
}

function enableElement(sName) {
	enableDisableElement(sName, true);
}

function enabledElement(sName) {
	enableElement(sName);
}

function disableElement(sName) {
	enableDisableElement(sName, false);
}

function disabledElement(sName) {
	disableElement(sName);
}

function enableDisableElement(sName, bEnable) {
	var obj = retrieveElement(sName);
	if( obj != null ) obj.disabled = !bEnable;
}

function centerWindow(width, height) {
	var actualWidth = screen.width;
	var actualHeight = screen.height;
	window.resizeTo(width, height);
	window.moveTo((actualWidth / 2) - (width / 2), (actualHeight / 2) - (height / 2));
}

/**
 * Opens a new window (with maximum height) to the given URL.
 * @param theURL the URL of the page to open
 * @param winName the name to refer to the new window as
 * @param xtraDetail the Javascript window.open feature list (eg. resizable, scrollbars, etc)
 */
function openWindowMaxHeight(theURL, winName, xtraDetail) {
  var featureList;
  featureList = xtraDetail + ",height=" + (screen.height - 100);
  top.consoleRef = window.open(theURL, winName, featureList);
  top.consoleRef.moveTo(0,0);
  top.consoleRef.focus();
}

function MM_openBrWindow(theURL, winName, features) { //v2.0
  return window.open(theURL, winName, features);
}

function refreshWindowOpener() {
	if( js_version == "1.0" ) {
		// Javascript v1.0
		//  This version of the refresh function will cause a new
		//  entry in the visitor's history.  It is provided for
		//  those browsers that only support JavaScript 1.0.
		window.opener.location.href = unescape(window.opener.location.pathname);
	} else if( js_version == "1.1" ) {
		// Javascript v1.1
		//  This version does NOT cause an entry in the browser's
		//  page view history.  Most browsers will always retrieve
		//  the document from the web-server whether it is already
		//  in the browsers page-cache or not.
		window.opener.location.replace(unescape(window.opener.location.pathname));
	} else if( js_version == "1.2" || js_version == "1.3" || js_version == "1.4" ) {
		// Javascript v1.2
		//  This version of the refresh function will be invoked
		//  for browsers that support JavaScript version 1.2
		//  The argument to the location.reload function determines
		//  if the browser should retrieve the document from the
		//  web-server.  In our example all we need to do is cause
		//  the JavaScript block in the document body to be
		//  re-evaluated.  If we needed to pull the document from
		//  the web-server again (such as where the document contents
		//  change dynamically) we would pass the argument as 'true'.
		window.opener.location.reload( true );
	}
}

/**
 * Adds the given option name & value pair to the given dropdown.
 * @param oSelParent the dropdown element to add the option to
 * @param sText the text part of the option to be added
 * @param sValue the value part of the option to be added
 * @param sSelectedValue the value used to indicate whether this option should be selected
 */
function addSelectEntry(oSelParent, sText, sValue, sSelectedValue) {
	oSelParent.appendChild(createOption(sText, sValue, sSelectedValue));
}

function createOption(sText, sValue, sSelectedValue) {
	var child = document.createElement("option");
	child.innerHTML = sText;
	child.setAttribute("value", sValue);
	if( sSelectedValue != null && sSelectedValue == sValue )
		child.setAttribute("selected", "selected");
	return child;
}

function addBlankSelectEntry(oSelParent, bAutoSelect) {
	var sSelect = (bAutoSelect ? "" : null);
	addSelectEntry(oSelParent, "", "", sSelect);
}

function fillWithFutureDates(oSelect, iDays, bLabels, sSelectedValue) {
	fillWithDates(oSelect, iDays, bLabels, sSelectedValue, null);
}

function fillWithDates(oSelect, iDays, bLabels, sSelectedValue, oStartDate) {
	var mydate = new Date(), str, name, child, day, month;
	if( oStartDate != null ) mydate = oStartDate;
	for( i = 0; i < iDays; i++ ) {
		day = mydate.getDate();
		if( day < 10 ) day = "0" + day;
		month = mydate.getMonth() + 1;
		if( month < 10 ) month = "0" + month;
		str = day + "/" + month + "/" + mydate.getFullYear();
		if( bLabels && oStartDate == null && i == 0 ) name = "Today";
		else if( bLabels && oStartDate == null && i == 1 ) name = "Tomorrow";
		else name = str;
		addSelectEntry(oSelect, name, str, sSelectedValue);
		day++;
		mydate.setDate(day);
	}
}

function fillWithHours(oSelect, sSelectedValue) {
	fillWithNumbers(oSelect, 0, 11, sSelectedValue);
}

function fillWith24Hours(oSelect, sSelectedValue) {
	fillWithNumbers(oSelect, 0, 23, sSelectedValue);
}

function fillWithNumbers(oSelect, iFrom, iTo, sSelectedValue) {
	for( i = iFrom; i <= iTo; i++ ) {
		if( i < 10 ) str = "0" + i;
		else str = "" + i;
		addSelectEntry(oSelect, str, str, sSelectedValue);
	}
}

function fillWithMinutes(oSelect, sSelectedValue) {
	fillWithNumbers(oSelect, 0, 59, sSelectedValue);
}

function fillWithMinuteIntervals(oSelect, iMinuteInterval, sSelectedValue) {
	var items = 60 / iMinuteInterval;
	var itemsUnderTen = 10 / iMinuteInterval;
	for( i = 0; i < items; i++ ) {
		if( i < itemsUnderTen ) str = "0" + (i * iMinuteInterval);
		else str = "" + (i * iMinuteInterval);
		addSelectEntry(oSelect, str, str, sSelectedValue);
	}
}

function fillWithDays(oSelect, sSelectedValue) {
	fillWithNumbers(oSelect, 1, 31, sSelectedValue);
}

function fillWithMonths(oSelect, sSelectedValue) {
	for( i = 1; i <= 12; i++ ) {
		str = MONTH_NAMES[i - 1];
		addSelectEntry(oSelect, str, i, sSelectedValue);
	}
}

function fillWithYears(oSelect, iStartYear, sSelectedValue) {
	fillWithNumbers(oSelect, iStartYear, new Date().getFullYear(), sSelectedValue);
}

function confirmDelete(sRedirect, sText) {
	var ok = confirm("You are about to delete " + sText + ", press OK to proceed");
	if( ok ) document.location = sRedirect;
}

function confirmEdit(sRedirect, sText) {
	var ok = confirm("You are about to edit " + sText + ", press OK to proceed");
	if( ok ) document.location = sRedirect;
}

//  check for valid numeric strings	
function isNumeric(str) {
	if( str.length == 0 ) return false;
	var strChar, strValidChars = "0123456789.-";
	for( i = 0; i < str.length; i++ ) {
		strChar = str.charAt(i);
		if( strValidChars.indexOf(strChar) == -1 ) return false;
	}
	return true;
}

function stripNonDigits(sInput) {
	if( sInput == null ) return null;
	var charCode, output = "";
	var zeroCode = "0".charCodeAt(0);
	var nineCode = "9".charCodeAt(0);
	for( i = 0; i < sInput.length; i++ ) {
		charCode = sInput.charCodeAt(i);
		if( charCode >= zeroCode && charCode <= nineCode ) output += sInput.charAt(i);
	}
	return output;
}

function isAlien(obj) {
   return isObject(obj) && typeof obj.constructor != 'function';
}

function isArray(obj) {
    return isObject(obj) && obj.constructor == Array;
}

function isBoolean(obj) {
    return typeof obj == 'boolean';
}

function isEmpty(obj) {
    var i, v;
    if( isObject(obj) ) {
        for( i in obj ) {
            v = obj[i];
            if( isUndefined(v) && isFunction(v) ) return false;
        }
    }
    return true;
}

function isFunction(obj) {
    return typeof obj == 'function';
}

function isNull(obj) {
    return typeof obj == 'object' && !obj;
}

function isNumber(obj) {
    return typeof obj == 'number' && isFinite(obj);
}

function isObject(obj) {
    return (obj && typeof obj == 'object') || isFunction(obj);
}

function isString(obj) {
    return typeof obj == 'string';
}

function isUndefined(obj) {
    return typeof obj == 'undefined';
} 

function isNotNull(obj) {
	return obj != null && !isUndefined(obj);
}

/**
 * Uses numberformatter.js to format decimal numbers correctly.
 * @since 1.0.0
 */
function formatNumber(sNumber, commas, places) {
	var formatter = new NumberFormat(sNumber);
	formatter.setCurrency(false);
	if( commas == null ) formatter.setCommas(true);
	else formatter.setCommas(commas);
	if( places == null || isNaN(places) ) formatter.setPlaces(2);
	else formatter.setPlaces(places);
	return formatter.toFormatted();
}