
/* ============================================================================
This is a core library for javsacript 
Please follow the the object oriented script framework to add utility function
=============================================================================== */

// global environment variables
var ENV = new function()
{	
	// Whether in debugging mode
	this.bDebugging = true;
	
	this.Warning = function( msg )
	{
		// in debug mode, show the warning
		if ( this.bDebugging ) alert( ' [base.JS]:' + msg );		
		return ( this.bDebugging ? false : true );
	}
}

// a powerful function to Parameterize arguments
// e.g. document.getElementById('element_id') same to $('element_id')
// e.g. input variables can also be array
 
function $() {
  var elements = new Array();
  for (var i = 0; i < arguments.length; i++) {
    var element = arguments[i];
    if (typeof element == 'string')
      element = document.getElementById(element);
    if (arguments.length == 1)
      return element;
    elements.push(element);
  }
  return elements;
}

// short cut format of DebugUtils.jdebug()
function jd(prompt, value) { DebugUtils.jdebug(prompt, value); }
function jdo(prompt, obj) { DebugUtils.jdebugObject(prompt, obj); }		// for debug object


/*
============================================
Event related functions
============================================
*/

// event types
var EventTypes = {	
	focus:			"focus", 
	blur:			"blur", 
	click:			"click", 
	dblclick:		"dblclick", 
	keypress:		"keypress", 
	keydown:		"keydown", 
	keyup:			"keyup", 
	onmousedown:	"onmousedown", 
	onmousemove:	"onmousemove", 
	onmouseout:		"onmouseout", 
	onmouseover:	"onmouseover", 
	onmouseup:		"onmouseup", 
	onresize:		"onresize"
}

// to record the event listener added
var EventCache = function(){
	var listEvents = [];
	return {
		listEvents : listEvents,
		add : function(node, sEventName, fHandler){
			listEvents.push(arguments);		// add the event into the array
		},
		
		// when window unload, flush it
		flush : function(){			
			var i, item;
			for(i = listEvents.length - 1; i >= 0; i = i - 1){
				item = listEvents[i];
				if(item[0].removeEventListener){
					item[0].removeEventListener(item[1], item[2], item[3]);			// removeEventListener( "eventType", listenerFunc, useCapture )
				};
				if(item[1].substring(0, 2) != "on"){
					item[1] = "on" + item[1];
				};
				if(item[0].detachEvent){
					item[0].detachEvent(item[1], item[2]);
				};
				item[0][item[1]] = null;
			};
		}
	};
}();

function getFunctionName(handler)
{
	var str = String(handler);
	
	str = str.replace("function", "")	//remove the head
	str = str.replace(/\((.|\n)*$/,"")	//remove the tail
	str = str.replace(/^\s*|\s*$/g,"");	//perfom the trimmming
	
	return str
}

// dummy functions that can be used as an event handler -- which has to be a function
function returnFalse()
{
	return false;
}

function returnTrue()
{
	return true;
}

var EventUtils = new function(){
	this.generalEventList = {}

	this.registerGeneralEvent = function(eventType, handler, priority)
	{	
		var handlers = this.generalEventList[eventType];
		
		if(!handlers)
			handlers = this.generalEventList[eventType] = new Array();
			
		if(priority == undefined)
			priority = 100;

		this.generalEventList[eventType].push(new Array(handler, priority, getFunctionName(handler)));
	}
	
	this.fixEvent = function(event) {
		// add W3C standard event methods
		event.preventDefault = EventUtils.fixEvent.preventDefault;
		event.stopPropagation = EventUtils.fixEvent.stopPropagation;
		return event;
	};
	
	this.fixEvent.preventDefault = function() {
		this.returnValue = false;
	};
	
	this.fixEvent.stopPropagation = function() {
		this.cancelBubble = true;
	};
	
	this.stopEvent = function(e){
		if (typeof e.stopPropagation != "undefined") 
			e.stopPropagation(); 
		else 
			e.cancelBubble = true; 
	}
	
	//if handler is undefined, it means this the event will be attached to the general event handlers
	//if priority is undefined, it means the default priority of 100 will be used
	
	this.addEvent = function(element, type, handler, priority) {
		// assign each event handler a unique ID
		//if (!handler.$$guid) handler.$$guid = this.addEvent.guid++;
		// create a hash table of event types for the element
		if (!element.events) element.events = {};
		
		// create a hash table of event handlers for each element/event pair
		var handlers = element.events[type];
		var functionName ="";
		
		if (!handlers) {
			handlers = element.events[type] = new Array();
			var inlineHandler = element["on" + type];
			// store the existing event handler (if there is one)
			if(inlineHandler) {
				//the inline handler is a slightly higher priority than the default one
				handlers.push(new Array(inlineHandler, 101, getFunctionName(inlineHandler) ));	//use the same structure as general event handler
				functionName = "#inline:" + inlineHandler + "#";
				element.events_debug += "on" + type + ":" + functionName  + "; "
			}						
		}
		
		// store the event handler in the hash table
		// the general event hadler is a special case, it will be called every time, 
		// and the general event handler has its own events
		// so need not and should not store
		if( handler )
		{
			if(!priority)
				priority = 100;
				
			handlers.push(new Array(handler, priority, getFunctionName(handler) ));
		}
			
		// assign a global event handler to do all the work
		element["on" + type] = this.handleEvent;
		
		// the events_debug property is purely for debug purpose
		if(!element.events_debug)
			element.events_debug = "";
			
		
		
		if(handler)
			functionName = getFunctionName(handler);
		else
			functionName = "#GeneralEventHandler()#";
			
		element.events_debug += "on" + type + ":" + functionName  + "; ";
	};

	this.removeEvent = function(element, type, handler) {
		var handlers;
		
		if(this.events && this.events["on"+ type])
			handler = this.events["on"+ type];
			
		if(handlers)
		{
			for(var i=0; i<handlers.length; i++)
			{
				if(handlers[i][2] == getFunctionName(handlers))
					delete handlers[i];
			}		
		}
	};

	//we make a special case for the general event
	//basically almost every element the user possibly triggers contains the general event handler, so the checking is not
	//neccessary
	this.isGeneralEventHandler = function(handler)
	{
		return getFunctionName(handler) =="generalEventHandler";
	}

	this.mergeEventList = function(list1, list2)
	{
		var newList = new Array();
		
		for(var i in list1)
			newList.push(list1[i]);
		
		for(var i in list2)
			newList.push(list2[i]);

		return newList;
	}
	
	// compare priority
	this.sortEvent = function(a,b)
	{	
		var aPri, bPri;		
		if ( a.sort && a.length > 1 ) aPri = a[1]; else aPri = 100;
		if ( b.sort && b.length > 1 ) bPri = b[1]; else bPri = 100;
		return bPri - aPri;	//sort by the priority, descending order		
	}	
	
	//since the event is triggered as a method of element, so the "this" here means the element, instead of EventUtils
	this.handleEvent = function(event) {
		var returnValue;
		
		// grab the event object (IE uses a global event object)
		event = event || EventUtils.fixEvent(window.event);
		
		// get a reference to the hash table of event handlers
		// merge with the general event list
		var handlers = EventUtils.mergeEventList(this.events[event.type], EventUtils.generalEventList[event.type]);
		
		//sort the events by priority		
		handlers.sort(EventUtils.sortEvent);
		
		//ENV.bDebugging = false
		
		for (var i in handlers) {
		
			this.$$handleEvent = handlers[i][0];	
			
			if(ENV.bDebugging)	//development phase
			{
				if ( this.$$handleEvent ) 
				{
					if ( this.$$handleEvent(event) === false) return false;
				}	
			}
			else	//production phase
			{
				try{
					if(this.$$handleEvent(event) === false)
						return false;
				}
				catch(error){}	//catch the error and hide it, to avoid interrupting other javascript
			}
		}
		
		return returnValue;
	};


	//----------------------------------------------------------------------------
	//misc utils.
	
	// get the src element from the event
	this.getSrcElement = function( e ){
		return e.srcElement ? e.srcElement : e.target;
	}
	
	// return the key code of the event
	this.getKeyCode = function(e){
		var code;
		if (!e) var e = window.event;
		if (e.keyCode) code = e.keyCode;  
		else if (e.which) code = e.which;
		return code;
	}
	
	// Return the character code of the event
	this.getCharCode = function( e ){		
		return String.fromCharCode( this.getKeyCode( e ) );			
	}
}

//general event handling
//executeRange < 0, perform those with priority > default priority only
//executeRange > 0, perform those with priority < default priority only
//execute range ==0, or undefined, execute all
function generalEventHandler__depreciated(e, executeRange)
{
	function indexOfFirstDefault(eventList)
	{
		for(i=0; i<eventList.length; i++)
		{
			if(eventList[i][2] >= 100)
				return i;
		}
	}

	var i, currentEvent, returnValue;
	var startIndex, endIndex;
	
	if(!executeRange)
	{
		startIndex = 0;
		endIndex = registerGeneralEvent.generalEventList.length;
	}
	else if(executeRange < 0)
	{
		startIndex = 0;
		endIndex = indexOfFirstDefault(registerGeneralEvent.generalEventList);
	}
	else
	{
		startIndex = indexOfFirstDefault(registerGeneralEvent.generalEventList);
		endIndex = registerGeneralEvent.generalEventList.length;
	}
	
	for(i=startIndex; i<endIndex ; i++)
	{
		currentEvent = registerGeneralEvent.generalEventList[i];
		if ( currentEvent && currentEvent[0] == e.type )
		{
			try
			{
				if(currentEvent[1](e) === false)	//trigger the handler
					returnValue = false;
			}
			catch(error)
			{
				//alert("error:" + error.description + "\nwhile executing:\n"+currentEvent[1])
			}
		}
	}
	
	return returnValue;
}






// add and event & listener func to an element
// example : EventUtils.addEvent( dbfrm.txt1, EventTypes.dblclick, funcName )
var EventUtils__depreciated = new function(){
	
	//function addEvent( obj, eventType, fn ) {
	this.addEvent= function( obj, eventType, fn ) {
	
		// The input is not an obj, cannot attach event to it
		if ( !obj ) {			
			ENV.Warning('EventUtils : Cannot attach event to non-exist object : ' + obj );
			return;
		}

		if (obj.addEventListener) {
			obj.addEventListener( eventType, fn, false );		// addEventListener( "eventType", listenerFunc, useCapture )
			EventCache.add(obj, eventType, fn);
		}
		else if (obj.attachEvent) {
			obj["e"+eventType+fn] = fn;
			obj[eventType+fn] = function() { obj["e"+eventType+fn]( window.event ); }
			obj.attachEvent( "on"+eventType, obj[eventType+fn] );
			EventCache.add(obj, eventType, fn);
		}
		else {
			obj["on"+eventType] = obj["e"+eventType+fn];
		}
	}

	// get the src element from the event
	this.getSrcElement = function( e ){
		return e.srcElement ? e.srcElement : e.target;
	}
	
	// return the key code of the event
	this.getKeyCode = function(e){
		var code;
		if (!e) var e = window.event;
		if (e.keyCode) code = e.keyCode;  
		else if (e.which) code = e.which;
		return code;
	}
	
	// Return the character code of the event
	this.getCharCode = function( e ){		
		return String.fromCharCode( this.getKeyCode( e ) )				
	}
	
}


// ================================================
// Cursor positioning utils ( IE only )
// ================================================
var CursorUtils = new function(){

	this.positionCursor = function(input, position)
	{
		var range = input.createTextRange();
		range.collapse(true);
		range.moveStart('character', position);
		range.select();
	}

	this.positionCursorAtStart = function(input)
	{
		var range = input.createTextRange();
		range.collapse(true);
		range.select();
	}

	this.positionCursorAtEnd = function(input)
	{
		var range = input.createTextRange();
		range.collapse(false);
		range.select();
	}

	this.highlightToEnd = function(input, selectionStart)
	{
		highlight(input, selectionStart, input.value.length);
	}

	this.highlight = function(input, selectionStart, length) 
	{
		var range = input.createTextRange();
		range.collapse(true);
		range.moveStart('character', selectionStart);
		range.moveEnd('character', length);
		range.select();
	} 

}

// ==============================================================================
// Form related functions
// ==============================================================================
var FormUtils = new function(){	

	this.bFocusInForm = true;
	this.formsNotToBeFocused = ""; //should be regular expression
	// Focus the first element of the form
	// e.g. FormUtils.focusFirstElement( document.search_form );
	this.focusFirstElement = function( form ){
		
		if ( form && form.elements )
		{
			for ( var i = 0; i< form.elements.length; i++ )
			{
				var done = false
				var element = form.elements[i];
				
				if ( ( ( element.type == 'select-one' ) || ( element.type == 'text' ) || ( element.type == 'textarea' ) || ( element.type == 'select' )) )  {
					// if error, that mean can foucs the fisrt element, then keep on
					try {
						if (element.focus) element.focus();					
						done = true
					}
					catch (e) {
						done = false		//alert( 'fail to focus' )					
					}	
					if ( done ) return;				
				}
			}
		}	
	}
	
	// test whether field is focus-able
	this.IsFocusableField = function( field )
	{
		//the focusable types are defined here
		var ty;
		
		// use a try-catch in case there is no type information
		try {		
			ty = field.type; 
		} catch(e) {}

		return ty && ((ty == "text") ||
						(ty == "textarea") || 
						(ty == "checkbox") ||
						(ty == "radio") ||
						(ty == "select-one") ||
						(ty == "select-multiple"));
	}	
	
	// Get next focusable element in the form	
	this.GetNextFocusableElement = function(queryElement)
	{
		return FormUtils.GetNextFocusableElementEx(queryElement, queryElement.form.elements);
	}
	
	// Get next focusable element in the form	
	this.GetNextFocusableElementEx = function(queryElement, formElements)
	{
		var totalElements = FormUtils.CountFormElements(formElements);
		var i = FormUtils.IndexOf(queryElement, formElements, totalElements);

		for(; i < totalElements; i++)
		{
			var element = formElements[i];			
			if (FormUtils.IsFocusableField(element) ) return element;
		}
		

		// return null instead, otherwise can't know really can't find one
		return null;	
	}
	
	// this counts how many elements there are in the form
	//  in case the form contains a field called "length", then 
	//    we can't use formElements.length which will return the form field rather than the length
	//    we can't use for(var a in formElements) { formElements[a] } 
	//        because "a" will contain a reference to "length" (length of the form), 
	//        but formElements[a] will point to the "length" field, i.e. the order of the elements may be off
	//        which is important for us in some cases.
	this.CountFormElements = function(formElements)
	{
		var i = 0;		
		for (var obj in formElements) i++; 		
		return i;
	}
	
	// find the index of an element inside a form element collection
	// the returned index is the one AFTER the queryElement
	this.IndexOf = function(queryElement, formElements, nElements)
	{
		if (queryElement == null) 
		{
			return 0; 
		}

		for (var i = 0; i < nElements; i++)
		{
			var e = formElements[i];
			
			if (queryElement == e)
			{
				// in case queryElement is part of a group, e.g. radio or checkbox
				// then the next focusable element should be after the group
				var j = i + 1;
				
				for (; j < nElements; j++) 
				{
					if (FormUtils.IsFocusableField(formElements[j]) && e.name != formElements[j].name)
						return j; 
				}
				return j;
			}
		}
		
		return i;
	}
	
	
	// place the focus in the first editable element of the form elements
	this.PlaceFocusInForm = function(formElements)
	{	
		var field = FormUtils.GetNextFocusableElementEx(null, formElements);
		
		// if the focus is on a dropdown, scroll wheel will scroll the dropdown, 
		//  which may be confusing for some users
		// so don't focus on any element in such case
		if( field 
			&& (field.ty != "select-one")
			&& (field.ty != "select-multiple"))
		{
			try { field.focus();} catch (e) {}
		}
	}

	this.FocusInFirstForm = function(){
		FormUtils.formsNotToBeFocused = "";
		FormUtils.FocusInForm();
	}
	
	// place the focus on the first editable form elements
	this.FocusInForm = function()
	{		
		// if we have a dbform, then place the focus there
		if (document.dbfrm) {
			FormUtils.PlaceFocusInForm(document.dbfrm.elements);
			return true;
		}
		else if (document.forms.length > 0) 
		{	
			if(FormUtils.formsNotToBeFocused != ""){				
				for(var i=0; i<document.forms.length; i++){
					var regex = new RegExp(FormUtils.formsNotToBeFocused);
					if(!regex.test(document.forms[i].name)){
						FormUtils.PlaceFocusInForm(document.forms[i].elements);
						break;
					}
				}
			}else{
				FormUtils.PlaceFocusInForm(document.forms[0].elements);
			}
			return true;
		}
		return false;
	}
	
	// Focus next element
	this.FocusNextElement = function( element )
	{
		var lastE = element
		
		if ( FormUtils.IsFocusableField(lastE) ) 
		{	
			var done = false				
			while ( (!done) && lastE )
			{								
				try {
					lastE = FormUtils.GetNextFocusableElement(lastE);
					lastE.focus();
					done = true
				} catch (e) {						
					// cannot foucus next element, find next
					done = false
				};
			}	
		}
	}
	
	// Send post data within physical form element
	// queryData in the form param1=value1&param2=value2
	this.submitPostData = function( queryData, action, target )
	{
		//DebugUtils.jdebug( queryData )		' See the post data
		DOMUtils.addFormIfNotExist("submitHelperForm", 'post', action, target)	//create the form		
		$('submitHelperForm').innerHTML = '';		// Clear the elements
		
		// Dynamically create the elements inside the form
		var arr = queryData.split('&');
		for (var i = 0; i < arr.length; i++) {
			var temp = arr[i].split('=');		
			DOMUtils.addInputIfNotExist(temp[0], "submitHelperForm", "hidden")			
			$(temp[0]).setAttribute('value', temp[1]);			
		}
		
		$('submitHelperForm').submit();	// submit the data
		
		return false;
	}
	
}

var FieldUtils = {
	
	// is the element is visible
	visible : function(element) {
		element = $(element)		
		return element.style.display != 'none';
	},

	clear: function() {
		for (var i = 0; i < arguments.length; i++)
			$(arguments[i]).value = '';
	},

  focus: function(element) {
	for (var i = 0; i < arguments.length; i++)
    var element = $(arguments[i])
    if ( element ) { 		
		if ( element.style.display != 'none' ) {
			element.focus();			
		}
	}
  },

  present: function() {
    for (var i = 0; i < arguments.length; i++)
      if ($(arguments[i]).value == '') return false;
    return true;
  },

  select: function(element) {
    $(element).select();
  },

  activate: function(element) {
    element = $(element);
    element.focus();
    if (element.select)
      element.select();
  } 

}

// ============================================================================
// Window and Frame Utils
// ============================================================================
var WindowUtils = new function(){
	
	// open a pop up window
	// pos: random, center
	
	// scrollbars=yes,location=yes,directories=yes,status=yes,menubar=yes,toolbar=yes,resizable=yes
	
	this.popUp = function( url , winName , w, h, pos, cond ) 
	{
		var win, settings
		win=null;
		
		if(pos=="random"){
			myleft=(screen.width)?Math.floor(Math.random()*(screen.width-w)):100;
			mytop=(screen.height)?Math.floor(Math.random()*((screen.height-h)-75)):100;
		}		
		else if(pos=="center")
		{
			myleft=(screen.width)?(screen.width-w)/2:100;
			mytop=(screen.height)?(screen.height-h)/2:100;
		}
		else if((pos!='center' && pos!="random") || pos==null)
		{
			myleft=0;
			mytop=20
		}		
		if ( cond.length == 0 ) cond = 'scrollbars=yes,location=yes,directories=yes,status=yes,menubar=yes,toolbar=yes,resizable=yes'		
		settings="width=" + w + ",height=" + h + ",top=" + mytop + ",left=" + myleft + cond ;
		win=window.open( url ,winName , settings);
		if (win) win.focus();
	}	
	
	// Auto Maximize Window
	this.maxWindow = function(){
		top.window.moveTo(0,0);
		if (document.all) 
		{ 
			top.window.resizeTo(screen.availWidth,screen.availHeight);
		}
		else if (document.layers||document.getElementById) {
			if (top.window.outerHeight<screen.availHeight||top.window.outerWidth<screen.availWidth)
			{
				top.window.outerHeight = screen.availHeight;
				top.window.outerWidth = screen.availWidth;
			}
		}
	}
	
	this.findMaxSize = function() {
		if( typeof( window.pageXOffset ) == 'number' ) { var x = window.pageXOffset, y = window.pageYOffset;
		} else if( document.documentElement && ( document.documentElement.scrollLeft || document.documentElement.scrollTop ) ) {
			var x = document.documentElement.scrollLeft, y = document.documentElement.scrollTop;
		} else if( document.body && ( document.body.scrollLeft || document.body.scrollTop ) ) {
			var x = document.body.scrollLeft, y = document.body.scrollTop;
		} else { var x = 0, y = 0; }
		if( window.innerWidth ) { var w = window.innerWidth, h = window.innerHeight;
		} else if( document.documentElement && document.documentElement.clientWidth ) {
			var w = document.documentElement.clientWidth, h = document.documentElement.clientHeight;
		} else if( document.body && document.body.clientWidth ) {
			var w = document.body.clientWidth, h = document.body.clientHeight;
		} else { var w = 400, h = 400; } if( window.opera || ( navigator.product == 'Gecko' && navigator.taintEnabled ) ) { w -= 16; }
		if( !window.ActiveXObject && !navigator.taintEnabled ) { h -= 4; }		
		return [x,y,w,h ]
	}
			
}

// ================================================================================
// Layer Utils
// ================================================================================

// utils function that deal with layer
var LayerUtils = new function(){

	this.moveAtCenter = function( element  ){
		var x, y, width, height		
		width  = parseFloat( element.style.width ||0 ) ;
		height = parseFloat( element.style.height ||0 );				
		x= (screen.width)?(screen.width-width)/2:100;
		y= (screen.height)?(screen.height-height)/5:20;
		x = x + document.body.scrollLeft;
		y = y + document.body.scrollTop ;		
		element.style.left    = x + 'px';;
		element.style.top   = y + 'px';;
		element.style.width  = width + 'px';;
		element.style.height = height + 'px';;		
	}
		
	this.showAtCenter = function( element  ){
		this.moveAtCenter(element);
		this.show(element);
	}
	
	// is the element is visible
	this.visible = function(element) {
		return element.style.display != 'none';
	}
	
	// e.g. toggle( 'a_id', 'b_id' )
	this.toggle = function() {
		for (var i = 0; i < arguments.length; i++) 
		{
			var element = $(arguments[i]);
			if ( this.visible(element) ){
				this.hide(element);
			}else{
				this.show(element);
			}
		}
	}

	this.hide = function() {
		for (var i = 0; i < arguments.length; i++) {
			var element = $(arguments[i]);			
			element.style.visibility	="hidden"
			element.style.display		="none"
		}
	}

	this.show = function() {
		for (var i = 0; i < arguments.length; i++) {
			var element = $(arguments[i]);			
			element.style.visibility	="visible"
			//element.style.display		="inline"
			element.style.display		=""
		}
	}
		
	this.showAtCursor = function( divObj, xoffset, yoffset, e )
	{
		var offsetxpoint=xoffset //Customize x offset of tooltip
		var offsetypoint=yoffset //Customize y offset of tooltip
						
		//if (enabletip)
		{
			var curX=((document.getElementById && !document.all))?e.pageX : event.x+this.ietruebody().scrollLeft;
			var curY=((document.getElementById && !document.all))?e.pageY : event.y+this.ietruebody().scrollTop;

			//position the horizontal position of the menu where the mouse is positioned
			divObj.style.left=curX+offsetxpoint+"px"			
			divObj.style.top=curY+offsetypoint+"px"
			divObj.style.visibility	="visible"
			divObj.style.display	="inline"
		}
	}
	
	// private helper function
	this.ietruebody = function()
	{
		return (document.compatMode && document.compatMode!="BackCompat")? document.documentElement : document.body
	}
}

// ============================================================================
// DOM Utils
// ============================================================================
var DOMUtils = new function(){
	//recursively loop through a node, and collect 
	//the all the child elements are returned in an array
	this.getAllElements = function(node)
	{
		function getAllElementsIntoArray(node, array, maxDepth)
		{
			if(!node)
				return

			if(array.length > 50)	//avoid infinite looping
				return 
			if(maxDepth < 0)
				return 
			
			try{
				if(node.name || node.id)	//only push those with ID or name
				{
					array.push(node)
				}

				if(node.children && node.children.length > 0)
				{
					for ( var i in node.children )
					{
						getAllElementsIntoArray(node.children[i], array, maxDepth-1)
					}
				}
			}
			catch (e)
			{
				jd("error when get elements into array @ 78", e.description)
			}
		}
	
		array = new Array()
		
		//trigger the recursion here
		getAllElementsIntoArray(node, array, 3)
		
		return array
	}
	
	//dynamiccally create a div, if the div does not already exist
	this.addDivIfNotExist = function(divID, elementName, bTail)
	{
		var div = document.getElementById(divID)

		if(!div)
		{
			div = document.createElement("DIV")
			div.id = divID
			
			var hook
			
			if(elementName && $(elementName))
				hook = $(elementName)
			else
				hook = document.body	//by default, hook to the body
				
			if(bTail)	//append as the last child of element
				hook.appendChild(div)
			else						//insert as the first child of elment
				hook.insertBefore(div, hook.firstChild)
		}
	}

	//dynamically create an input element and put it into the target form
	this.addInputIfNotExist = function(name, formName, type)
	{
		if($(name) && $(name).tagName == "INPUT")
		{
			//do nothing
		}
		else
		{
			if($(formName))
			{
				var divName = formName + "_dynamicInputDiv"

				if(!type)	//by default it's hidden
					type = "hidden"

				//we have to create a div first, instead of directly inject the new input into the form
				//otherwise, the DOM of form will be damaged, and javascript cannot be triggered
				//we need to append to the tail, otherwise it would change the appearance				
				this.addDivIfNotExist(divName, formName, true)

				//this is the only way to have a input with name
				$(divName).innerHTML += "<input type=" + type + " name='" + name + "' id='" + name + "'>" 
			}
			else
			{
				alert("Fatal error: try to add hidden input, form object not found")
			}
		}	
	}
	
	this.addFormIfNotExist = function(formName, method, action, target)
	{
		if(!$(formName)){
			var divName = formName + "_dynamicFormDiv"
			this.addDivIfNotExist(divName, document.body, true)

			$(divName).innerHTML += "<form method=post name=" + formName + " id=" + formName + "></form>"	
		}

		if(action)	$(formName).action = action
		if(target)	$(formName).target = target
		if(method)	$(formName).method = method
	}
}

// ============================================================================
// String Utils
// ============================================================================
var StringUtils = new function()
{
	
	// Turn new line into <br>
	this.nl2br = function(str)
	{
		str = str.replace(/\n/g, "<br>")
		return str;
	}
	
	this.escapeHTML = function(str)
	{
		var div = document.createElement('div');
		var text = document.createTextNode(str);
		div.appendChild(text);
		return div.innerHTML;
	}
	
	this.trim = function(str)
	{
		return str.replace(/^\s*|\s*$/g,"");
	}
	
	// function to compose a order string for query	
	this.updateOrderByField = function ( order_string_fd_id, fd )
	{	
		var obj = $(order_string_fd_id)
	    
		if ( !obj ) return false;
	    
		fd = '"' + fd + '"'
	    
		var to_add
	    
		//DebugUtils.jdebug( 'Defore' + obj.value );
	    
		// is it already in the order condition ?
		if ( obj.value.indexOf( fd ) >= 0 ){
			// the fd order already specific, opposite the order, put it lower priority
			if ( obj.value.indexOf( fd + ' asc') >= 0 )
			{
				obj.value = obj.value.replace(  ', ' + fd+' asc', '' );
				obj.value = obj.value.replace(  fd+' asc,', '' );
				obj.value = obj.value.replace(  fd+' asc', '' );
				to_add = fd + ' desc';
			}
			else if ( obj.value.indexOf( fd + ' desc') >= 0 )
			{
				obj.value = obj.value.replace(  ', ' + fd + ' desc', '' );
				obj.value = obj.value.replace(  fd+' desc,', '' );
				obj.value = obj.value.replace(  fd+' desc', '' );
				to_add = fd + ' asc';
			}
		}else{   
			to_add = fd + ' asc'
		}
	    
		// append the order
		if ( Trim(obj.value).length > 0 ){
			obj.value = obj.value + ', ' + to_add;
		}else{
			obj.value = to_add;
		}
		//DebugUtils.jdebug( '------> ' + obj.value);
	}
	
	// Check password
	this.CheckPassword = function(username, password)
	{
		var p = document.getElementById(password);
		var u = document.getElementById(username);
		
		if ( !u ) return this.TestPassword( null , p.value );
		
		if ((p) && (u))	
		{
			return this.TestPassword(u.value, p.value);
		}
		return true;
	}
	
	// Security level of password
	this.TestPassword = function(username, password)
	{
		var pass = true;
		var msg = '';
		
		if ( username ) {
			if (password.indexOf(username) >= 0)
			{
				pass = false;
				msg += 'Your password cannot contain the username. \r\n';
			}
		}

		// length
		if (password.length < 8)
		{
			pass = false;
			msg += 'Your password is too short. \r\n';
		}
		
		// NUMBERS
		if (!password.match(/\d+/))	// [verified] at least one number
		{
			pass = false;
			msg += 'Your password should contain number(s). \r\n';
		}
		
		// Letter
		if (!password.match(/[A-Za-z]/))  // [verified] at least one letter
		{
			pass = false;
			msg += 'Your password should contain letter(s). \r\n';
		}
		
		if (!pass)
		{
			alert('Your password is too weak. \r\n' + msg);
		}
		
		return pass;
	}		
}

var CreditCardUtils = new function()
{	
	this.isValidCardNumber = function(strNum) 
	{
		var nCheck = 0;
		var nDigit = 0;
		var bEven = false;
		   
		for (n = strNum.length - 1; n >= 0; n--) 
		{
			var cDigit = strNum.charAt (n);
			if (CreditCardUtils.isDigit (cDigit))
			{
				var nDigit = parseInt(cDigit, 10);
				if (bEven)
				{
					if ((nDigit *= 2) > 9)
					nDigit -= 9;
				}
				nCheck += nDigit;
				bEven = ! bEven;
			}
			else if (cDigit != ' ' && cDigit != '.' && cDigit != '-')
			{
				return false;
			}
		}
		return (nCheck % 10) == 0;
	}


	this.isDigit = function(c)
	{
		var strAllowed = "1234567890";
		return (strAllowed.indexOf (c) != -1);
	}
	/* type = Visa, Master Card, Amex */
	this.isCardTypeCorrect = function(strNum, type)
	{
		var nLen = 0;
		for (n = 0; n < strNum.length; n++)
		{
			if (CreditCardUtils.isDigit (strNum.substring (n,n+1)))
				++nLen;
		}   
		if (type == 'Visa')
			return ((strNum.substring(0,1) == '4') && (nLen == 13 || nLen == 16));
		else if (type == 'Amex')
			return ((strNum.substring(0,2) == '34' || strNum.substring(0,2) == '37') && (nLen == 15));
		else if (type == 'Master')
			return ((strNum.substring(0,2) == '51' || strNum.substring(0,2) == '52'
					|| strNum.substring(0,2) == '53' || strNum.substring(0,2) == '54'
					|| strNum.substring(0,2) == '55') && (nLen == 16));
		else
			return false;		   
	}

}


var PositionUtils = new function(){
	//find display position of an element
	this.getPosition = function(el){
		var cell_el = el;
		var cell_left_pos = cell_el.offsetLeft ;
		var cell_top_pos = cell_el.offsetTop ; 
		var parent_el = cell_el.offsetParent ;

		while (parent_el != null){
			// if parent a table cell, include cell border width
			if(parent_el.tagName == "TD")
			{ 
				cell_left_pos += parent_el.clientLeft;
				cell_top_pos += parent_el.clientTop;
			}
			cell_left_pos += parent_el.offsetLeft;		// add left offset of parent
			cell_top_pos += parent_el.offsetTop;		// add top offset of parent

			if(parent_el.scrollTop && parent_el.tagName != "BODY") cell_top_pos -= parent_el.scrollTop;			
			if(parent_el.scrollLeft && parent_el.tagName != "BODY") cell_left_pos -= parent_el.scrollLeft
						
			parent_el = parent_el.offsetParent; // move up the elements until no more offset parents exist
		}

		return [cell_top_pos, cell_left_pos]
	}

  	this.realOffset = function(element) {
		var valueT = 0, valueL = 0;
		do {
		  valueT += element.scrollTop  || 0;
		  valueL += element.scrollLeft || 0;
		  element = element.parentNode;
		} while (element);
		return [valueL, valueT];
	}

	this.cumulativeOffset = function(element) {
		var valueT = 0, valueL = 0;

		do {
		  valueT += element.offsetTop  || 0;
		  valueL += element.offsetLeft || 0;
		  element = element.offsetParent;
		} while (element);

		return [valueL, valueT];
	}

	this.positionedOffset =  function(element) {
		var valueT = 0, valueL = 0;
		do {
		  valueT += element.offsetTop  || 0;
		  valueL += element.offsetLeft || 0;
		  element = element.offsetParent;
		  if (element) {
			p = Element.getStyle(element, 'position');
			if (p == 'relative' || p == 'absolute') break;
		  }
		} while (element);
		return [valueL, valueT];
	}

	this.offsetParent =  function(element) {
		if (element.offsetParent) return element.offsetParent;
		if (element == document.body) return element;

		while ((element = element.parentNode) && element != document.body)
		  if (Element.getStyle(element, 'position') != 'static')
			return element;

		return document.body;
	}
}

/* Class to process XML message */

MTGXML = new function()
{

	this.getFirstNode = function( rootNode, tag )
	{
		var arr = new Array();		
		for ( var i=0; i<rootNode.childNodes.length; i++)
		{	
			var n = rootNode.childNodes[i];			
			if ( n.tagName == tag ) return n;
		}
		return null;
	}
	
	this.getFirstNodeData = function( rootNode, tag )
	{
		var n = this.getFirstNode( rootNode, tag );		
		if ( n ) return this.nodeValue( n );
		return '';		
	}
	
	this.getNodes = function( rootNode, tag )
	{	
		var arr = new Array();		
		for ( var i=0; i<rootNode.childNodes.length; i++)
		{	
			var n = rootNode.childNodes[i];						
			if ( n.tagName == tag ) arr.push( n );
		}		
		return arr;
	}
	
	// Get value of a node data, cross browser
	this.nodeValue = function ( n ) 
	{	if ( n.firstChild ){
			return n.firstChild.data;			
		}else return n.nodeValue;
	}

	/**
	* Create a new Document object. If no arguments are specified,
	* the document will be empty. If a root tag is specified, the document
	* will contain that single root tag. If the root tag has a namespace
	* prefix, the second argument must specify the URL that identifies the
	* namespace.
	*/
	this.newDocument = function(rootTagName, namespaceURL) {
		if (!rootTagName) rootTagName = "";
		if (!namespaceURL) namespaceURL = "";
		if (document.implementation && document.implementation.createDocument) {
			// This is the W3C standard way to do it
			return document.implementation.createDocument(namespaceURL, rootTagName, null);
		}
		else { // This is the IE way to do it
			// Create an empty document as an ActiveX object
			// If there is no root element, this is all we have to do
			var doc = new ActiveXObject("MSXML2.DOMDocument");
			// If there is a root tag, initialize the document
			if (rootTagName) {
			// Look for a namespace prefix
			var prefix = "";
			var tagname = rootTagName;
			var p = rootTagName.indexOf(':');
			if (p != -1) {
				prefix = rootTagName.substring(0, p);
				tagname = rootTagName.substring(p+1);
			}
			// If we have a namespace, we must have a namespace prefix
			// If we don't have a namespace, we discard any prefix
			if (namespaceURL) {
				if (!prefix) prefix = "a0"; // What Firefox uses
			}
			else prefix = "";
			// Create the root element (with optional namespace) as a
			// string of text
			var text = "<" + (prefix?(prefix+":"):"") +  tagname +
				(namespaceURL
				?(" xmlns:" + prefix + '="' + namespaceURL +'"')
				:"") +
				"/>";
			// And parse that text into the empty document
			doc.loadXML(text);
			}
			return doc;
		}
	};

	/**
	* Synchronously load the XML document at the specified URL and
	* return it as a Document object
	*/
	this.load = function(url) {	
		// Create a new document with the previously defined function
		var xmldoc = this.newDocument();
		xmldoc.async = false;  // We want to load synchronously
		xmldoc.load(url);      // Load and parse
		return xmldoc;         // Return the document
	};

	/**
	* Asynchronously load and parse an XML document from the specified URL.
	* When the document is ready, pass it to the specified callback function.
	* This function returns immediately with no return value.
	*/
	this.loadAsync = function(url, callback) {
		var xmldoc = this.newDocument();
		// If we created the XML document using createDocument, use
		// onload to determine when it is loaded
		if (document.implementation && document.implementation.createDocument) {
			xmldoc.onload = function() { callback(xmldoc); };
		}
		// Otherwise, use onreadystatechange as with XMLHttpRequest
		else {
			xmldoc.onreadystatechange = function() {
				if (xmldoc.readyState == 4) callback(xmldoc);
			};
		}
		// Now go start the download and parsing
		xmldoc.load(url);
	};


	/**
	* Parse the XML document contained in the string argument and return
	* a Document object that represents it.
	*/
	this.parse = function(text) {
		if (typeof DOMParser != "undefined") {
			// Mozilla, Firefox, and related browsers
			return (new DOMParser()).parseFromString(text, "application/xml");
		}
		else if (typeof ActiveXObject != "undefined") {
			// Internet Explorer.
			var doc = this.newDocument();  // Create an empty document
			doc.loadXML(text);            // Parse text into it
			return doc;                   // Return it
		}
		else {
			// As a last resort, try loading the document from a data: URL
			// This is supposed to work in Safari. Thanks to Manos Batsis and
			// his Sarissa library (sarissa.sourceforge.net) for this technique.
			var url = "data:text/xml;charset=utf-8," + encodeURIComponent(text);
			var request = new XMLHttpRequest();
			request.open("GET", url, false);
			request.send(null);
			return request.responseXML;
		}
	};


	/**
	* there is an advantage to including that data directly within the HTML page: the 
	* data is already available, and the web application does not have to establish 
	* another network connection to download the data. 

	* Return a Document object that holds the contents of the <xml> tag
	* with the specified id. If the <xml> tag has a src attribute, an XML
	* document is loaded from that URL and returned instead.
	*
	* Since data islands are often looked up more than once, this function caches
	* the documents it returns.
	*/
	this.getDataIsland = function(id) {
		var doc;
		// Check the cache first
		doc = this.getDataIsland.cache[id];
		if (doc) return doc;
		// Look up the specified element
		doc = document.getElementById(id);
		// If there is a "src" attribute, fetch the Document from that URL
		var url = doc.getAttribute('src');
		if (url) {
			doc = this.load(url);
		}
		// Otherwise, if there was no src attribute, the content of the <xml>
		// tag is the document we want to return. In Internet Explorer, doc is
		// already the document object we want. In other browsers, doc refers to
		// an HTML element, and we've got to copy the content of that element
		// into a new document object
		else if (!doc.documentElement) {// If this is not already a document...
			// First, find the document element within the <xml> tag. This is
			// the first child of the <xml> tag that is an element, rather
			// than text, comment, or processing instruction
			var docelt = doc.firstChild;
			while(docelt != null) {
				if (docelt.nodeType == 1 /*Node.ELEMENT_NODE*/) break;
				docelt = docelt.nextSibling;
			}
			// Create an empty document
			doc = this.newDocument();
			// If the <xml> node had some content, import it into the new document
			if (docelt) doc.appendChild(doc.importNode(docelt, true));
		}
		// Now cache and return the document
		this.getDataIsland.cache[id] = doc;
		return doc;
	};

	this.getDataIsland.cache = {}; // Initialize the cache
}


// ============================================================================
// String Utils
// ============================================================================
//print the debug message to an iframe, instead of using alert
var DebugUtils = new function()
{	
	this.jdebug = function(prompt, value)
	{
		//in production mode, do not show the debug message
		if(!ENV.bDebugging)
			return
			
		var divId= "JDebugDiv"

		DOMUtils.addDivIfNotExist(divId)	//dynamically create a div
		
		var hook = document.getElementById(divId)
		var debugTable = document.getElementById("debugTable")
		
		if(debugTable == undefined)
		{
			//actually it would be better to generate the table using "document.createElement()"
			hook.innerHTML+="<table id=debugTable width=100% border=1 bordercolor=blue cellspacing=0></table>"
			
			debugTable = document.getElementById("debugTable")
		}

		var newRow=debugTable.insertRow(debugTable.rows.length)
		var cell0 = newRow.insertCell(0);
		var cell1 = newRow.insertCell(1);
		var cell2 = newRow.insertCell(2);
		cell0.width = "10%"
		cell1.width = "20%"
		cell2.width = "30%"
		
		cell0.innerHTML = "JDEBUG"

		try{
			cell1.innerHTML = prompt
			
			if(typeof value== "object")
				cell2.innerHTML = displayObject(value)
			else
				cell2.innerHTML = StringUtils.escapeHTML(value)
		}
		catch(e)
		{
			cell2.innerHTML = "<font color = red>Error in jdebug:" + e.message + "</font>"
		}		
	}
	
	this.jdebugObject = function( prompt, obj )
	{
		var s = '';
		for (property in obj) {		
			s = s + ' [' + property + ']';
		}
		this.jdebug( prompt, s );
	}

	function displayObjectAttribute(index, object)
	{
		var display = ""
		if(object != undefined)
		{
			if(object.tagName)
			{
				display += " [ " + index + " ] " 
				display += "Current Tag Name: <font color=green>" + object.tagName + "</font><br>"
			
				if(object.id)
					display += " id => <font color=red>" + object.id + "</font>"
				if(object.name)
					display += " name => <font color=green>" + object.name + "</font>"
				if(object.value)
					display += " value => " + escapeHTML(object.value)
					
				display += "<hr>"
			}
			else if(typeof object != "object")
			{
				display += escapeHTML(object)
			}
			
			if(display)
				display += "<br>"
		}
		
		return display
	}

	function displayObject(object)
	{
		var i
		var display=""

		display = "<font color=blue>" + displayObjectAttribute("o", object) + "</font>"
		
		if(object && object.sort)	//it is likely to be an array
		{
			for(var i in object)
			{
				var e = object[i]
				display +=  "__ " + i + "=>" + displayObject(e)
			}
			display += "<hr>"
		}
		
		if(!object)
		{
			display += " undefined object<br>"
		}
		
		return display
	}
	
}

// ==============================================================
// Variable utils to register - Global flag register mechanism
// ==============================================================
//this object is for registration of global registers
// e.g. var arr = new Array(); Global.put( 'abc', arr ); Global.get( 'abc' );
var globalRegisterObject = new Object()

var Global = new function()
{	
	this.put = function( property, value, owner )	
	{ 
		if ( !owner ) owner = null;
		eval("globalRegisterObject."+property+"__value = value");
		eval("globalRegisterObject."+property+"__owner = owner");
	}
	this.get = function( property )	
	{ return eval("globalRegisterObject."+property+"__value") }	
	
	this.getOwner = function( property )
	{ return eval("globalRegisterObject."+property+"__owner") }
	
	this.isExist = function( property )	
	{ return eval("globalRegisterObject."+property+"__value != undefined") }
	
}


// ================================================
// execute a url in hidden frame
// ================================================
function RunURL(url)
{
	RunURLEx("", url)
}

function RunURLEx(prefix, url)
{
	RunURLEx2(prefix, url, null)
}

function informParentRunURLResult(e, handler)
{
	var srcElement = EventUtils.getSrcElement(e)
	
	var handler = $(srcElement.id + "_handler")
	
	if(handler)
	{
		handler = handler.value
		if(handler == "UNLOAD")
		{
			eval("window.frames."+srcElement.id + "=null")	//kill the frame, save memory and free the page out
		}
		else
		{
			var result = null
			
			if(eval("window.frames."+srcElement.id + ".getFrameResult"))
			{
				eval("result = window.frames."+srcElement.id + ".getFrameResult()")
				eval("innerHTML = window.frames."+srcElement.id + ".document.body.innerHTML")
			}
		
			handler = handler.replace("<result>", "result")
			handler = handler.replace("<innerHTML>", "innerHTML")
			eval(handler)
		}
	}
}

//very loose one for now
function getHostFromURL(url)
{
	var pos = url.indexOf("?")	
	if(pos < 0)
		return url
	else
		return url.substring(0, pos)
}

function RunURLEx2(prefix, url, handler)
{
	//increase the frameHeight to debug the hidden frames
	var frameHeight = 0
	var frameWidth = 500
	
	var onloadHandler = ""
	var frameHTML
	//var oldFrameExist = true
	
	var frame_name = prefix + "cmd_frame" // note that prefix could be blank, and frame name can't start with "_"
	var frame_div_name = prefix + "frame_div"
	var frame_handler_name = frame_name + "_handler"

	//if there is no usch frame, it would raise an error, instead of give an undefined value
	//do not use window.frames["XXX"]. as it would fail to work in firefox
	var oldFrame = eval("window.frames."+frame_name)
	
	if(handler) onloadHandler = "onload = \"informParentRunURLResult(event)\""
	
	if(oldFrame){	//if the frame already exists, do not add the frame
	}
	else{
		addCmdFrameDivIfNotExist()

		frameHTML = "<div id=" + frame_div_name + " name=" + frame_div_name + "> " +
						"<input type=hidden id=" + frame_handler_name + " name=" + frame_handler_name  + " value=\"" + handler + "\">" + 
						"<iframe id=" + frame_name + " name=" + frame_name + " width=" + frameWidth + " height=" + frameHeight +	
							" " + onloadHandler + "></iframe>" +
					"</div>"
								
					
		document.getElementById("cmd_frame_div").innerHTML += frameHTML
	}

	var frame = eval("window.frames."+frame_name)
	
	//use location.replace instead of setting location.href, this function would not add any frame
	//to the window history, hence would not affect the browser "BACK" button (and should solve the "CANCEL" button problem)
	frame.location.replace(url)
}

//should use outerhtml instead?
//this seems to be the only way to remove a frame, a little bit memory leakage, about ~10 KB each time
function UnloadIFrameByPrefix(prefix)
{	
	var frame_name = prefix + "cmd_frame" // note that prefix could be blank, and frame name can't start with "_"
	var div = $(prefix+"frame_div")
	
	if(div) div.outerHTML = ""
}

function addCmdFrameDivIfNotExist()
{
	var hook = document.getElementById("cmd_frame_div")

	if(hook == undefined)
	{
		div = document.createElement("DIV")
		div.id = "cmd_frame_div"

		document.body.insertBefore(div, document.body.firstChild)
		hook = document.getElementById("cmd_frame_div")
	}
}

// ================================================
// marks whether the page has been changed or not
// mainly used in OnBeforeUnload()
// ================================================
function markLastModified()
{
	Global.put("lastModified",new Date(), "markLastModified")
}



// ================================================
// debug
// ================================================
function Debug(label, msg)
{
	alert(label + ": " + msg);
}

/* ==========  Event Related ============== */
//register the event handler to all forms
function SetupGeneralEventHandler()
{
	//register the raw events
	EventUtils.addEvent(document.body, "keydown")
	EventUtils.addEvent(document.body, "keypress")
	EventUtils.addEvent(document.body, "click")

	//register the semantic events
	var formLen = FormUtils.CountFormElements(document.forms)
	
	for(var p=0; p<formLen; p++)
	{
		if(document.forms[p])
		{
			var currentForm = document.forms[p]
			var len = FormUtils.CountFormElements(currentForm)
			for(var i=0; i<len; i++)
			{
				try
				{
					var el = currentForm[i]
					if(el && FormUtils.IsFocusableField(el))
						EventUtils.addEvent(el, "change")
				}
				catch(e){}
			}
		}
	}
	
	
	EventUtils.registerGeneralEvent("change", markLastModified)
}


// Javascritp function to be called when page on load
// i.e. default script to be called
function DefaultPageOnLoad()
{
	if(FormUtils.bFocusInForm){
		// Focus to the form element			
		FormUtils.FocusInForm();
	}
}

var dbfrm;
// A chain pattern that user can create the function
// like command in dbform
//1.PageOnLoadPre
//2.PageOnLoad
//3.PageOnLoadPost
function BasicPageOnLoad()
{	
	//set up those environemtn variables based on ASP
	if ( window.SetupASPEnv != undefined ) SetupASPEnv();
	
	//set up the general event handler
	SetupGeneralEventHandler();

	// call pre function if any
	if ( window.PageOnLoadPre != undefined ) PageOnLoadPre()
	
	// call function if any, otherwise use default
	if ( window.PageOnLoad != undefined )
		PageOnLoad()
	else
		DefaultPageOnLoad()

	// call post function if any	
	if ( window.PageOnLoadPost != undefined ) PageOnLoadPost()
	
	// Make it compatible with FireFox
	dbfrm = document.getElementById('dbfrm');
}


// Called the onload function
// header page onload will trigger basic page onload

//this basic page onload will only be called, when header basic is included
if ( window.SetupASPEnv != undefined )
	EventUtils.addEvent(window, 'load', BasicPageOnLoad);



// ============================== Basic Utility ====================================

function Choose( bool, a, b ){	if ( bool ) return a;else return b; }
function IfTrue( bool, a ){	return Choose( bool, a, "" );}
function IfFalse( bool, a ){return Choose( bool, "", a );}
function IfEmpty( s, val ){	if ( IsEmptyString(s) ) return val;	return s;}
function IsEmpty(s){ return IsEmptyString(s); }
function IsEmptyString(s){ if (( s == null ) || ( Trim(s).length == 0 ) ) return true; else return false; }
function TrimLeft(s) { var whitespaces = " \t\n\r"; for(n = 0; n < s.length; n++) { if (whitespaces.indexOf(s.charAt(n)) == -1) return (n > 0) ? s.substring(n, s.length) : s; }; return("");}
function TrimRight(s){	var whitespaces = " \t\n\r"; for(n = s.length - 1; n  > -1; n--) { if (whitespaces.indexOf(s.charAt(n)) == -1) return (n < (s.length - 1)) ? s.substring(0, n+1) : s; };return("");}
function Trim(s) {return ((s == null) ? "" : TrimRight(TrimLeft(s))); }
function IsInt( num ){return new RegExp("^-?\\d*$").test( num ) ;}
function IsDecimal( num, decimalPlace ){return new RegExp("^-?\\d*\\.\\d{0," + decimalPlace + "}$").test( num );}
