/**
 * Core Javascript Class Used by Extensible Site Framework (XSF)
 * @copyright 2002 Centricity Systems, All Rights Reserved
 * @author S. Larsen <slarsen@centricitysystems.com>
 * @version 1.0
 */
/**
 * ENVIRONMENT VARIABLES
 */
/**
 * @var web_protocol defines the default protocol
 */
web_protocol = window.location.protocol;
/**
 * @var web_host defines the default host
 */
web_host = window.location.host;
/**
 * @var web_file_path defines the default path and file
 */
web_file_path = window.location.pathname;
/**
 * @var web_query defines the default querystring
 */
web_query = window.location.search;
/**
 * @var web_hash defines the default hash
 */
web_hash = window.location.hash;
/* ------------------------------------------------------------- */
/**
 * FORM BIND OBJECT
 */
function form_bind(form,cntl,required,relevant,calculate,datatype,help,error,scope) {
	this.form = form;
	this.cntl = cntl;
	this.required = Boolean(required);
	this.relevant = relevant;
	this.calculate = calculate;
	this.datatype = datatype;
	this.help = help;
	this.error = error;
	this.global = (scope==""||scope=="local"?false:true);
	str = "";
	str += "form: "+this.form+"\n";
	str += "cntl: "+this.cntl+"\n";
	str += "required: "+this.required+"\n";
	str += "relevant: "+this.relevant+"\n";
	str += "calculate: "+this.calculate+"\n";
	str += "datatype: "+this.datatype+"\n";
	str += "help: "+this.help+"\n";
	str += "error: "+this.error+"\n";
	str += "global: "+this.global;
	//alert(str);
	return this;	
}
/**
 * processes all global functions on blur
 */
function process_global_controls(ths) {
	for(i=0; i<sizeof(ths.form.elements); i++) {
		n = ths.form.name+"_"+ths.form.elements[i].name;
		if ( bindObj[n].global ) {
			eval(bindObj[n].calculate);
		}
	}
}
/**
 * gets value of an object
 */
function valueof(ths) {
	return (valueof.arguments.length==2?ths.form.elements[valueof.arguments[1]].value:ths.value);
}

function calculate(ths, calc) {
	ths.value = eval(calc);
}

function sum(ths,str) {
	if ( str == "" ) { return 0; }
	a = str.split(",");
	v = 0;
	for(i=0;i<sizeof(a);i++) {
		num = parseFloat(ths.form.elements[a[i]].value);
		if ( !isNaN(num) ) { v += num; }
	}
	return v;
}

function enable(ths) {
	try {		
		o = (enable.arguments.length==2?ths.form.elements[enable.arguments[1]]:ths);
		t = o.type;
	} catch(e) { return; }
	if ( typeof(t) == "undefined" ) { return; }
	switch (t) {
		case "button" :
		case "submit" :
		case "select-one":
		case "select-multiple":
		case "reset"	:
		case "text"		: o.readonly = false; break;
	}
}

function disable(ths) {
	try {
		o = (disable.arguments.length==2?ths.form.elements[disable.arguments[1]]:ths);
		t = o.type;
	} catch(e) { return; }
	if ( typeof(t) == "undefined" ) { return; }
	switch (t) {
		case "button" :
		case "submit" :
		case "select-one":
		case "select-multiple":
		case "reset"	:
		case "text"		: o.disabled = true; break;
	}
}

/**
 * @return string Returns the web root value
 */
function get_web_root() {
	return web_protocol + "//" + web_host +"/";
}
/**
 * @return string Returns the web query
 */
function get_web_query() {
	return web_query;
}
/**
 * @return string Returns the web hash
 */
function get_web_hash() {
	return web_hash;
}
/**
 * Returns the full web file path, including host, protocol and file name. If param1 is set to false
 * then returns the file path without root host or protocol.
 * @param boolean param1 <i>optional</i> Specifies if to return host and protocol. Default is true.
 * @return string Returns the full web file path, including host and protocol
 */
function get_web_file_path() {
	if ( get_web_file_path.arguments.length == 0 ) { param1 = true; }
	else { param1 = (get_web_file_path.arguments[0]?true:false); }
	if ( param1 ) { return web_protocol + "//" + web_host + web_file_path; }
	return web_file_path;
}
/**
 * Returns the web path only, including host and protocol but no filename.
 * If param1 is set to false (default is true), then returns the path without host and protocol.
 * @param boolean param1 <i>optional</i> Specifies if to return host and protocol. Default is true.
 * @return string Returns the web path only, including host and protocol but no filename.
 */
function get_web_path() {
	if ( get_web_path.arguments.length == 0 ) { param1 = true; }
	else { param1 = (get_web_path.arguments[0]?true:false); }
	s = '';
	if ( window.location.pathname.length > 0 ) {
		w = window.location.pathname;
		if ( w.substr(0,1) == "/" ) { w = w.substr(1); }
		wf_arr = w.split("/");
		if ( wf_arr.length > 0 && wf_arr[wf_arr.length-1].indexOf(".") != -1 ) { fname = wf_arr.pop(); }
		s = wf_arr.join("/");
	}
	s = (param1?get_web_root():"") + s + (s.length==0?'':"/");
	return s;
}
/**
 * @return string Returns the web file only (no path)
 */
function get_web_file() {
	return basename();
}
/**
 * @param string path The path to return the file from
 * @param boolean strip_ext <i>optional</i> Set to TRUE to strip off any extension. Default is FALSE. 
 * @return string Returns the file only (no path)
 */
function basename() {
	strip = false;
	if ( basename.arguments.length>=1 ) { path = basename.arguments[0]; }
	else { path = window.location.pathname;	}
	if ( basename.arguments.length==2 ) { strip = Boolean(basename.arguments[1]); }
	if ( path == "" ) { return ""; }
	arr = path.split("/");
	file = (arr.length==0?"":arr[arr.length-1]);
	f_ = file.split(".");
	if ( f_.length <= 1 ) { return ""; }
	return (strip?f_[0]:file);
}
/**
 * @param string path The path to return the file from
 * @return string Returns the directory only (no file)
 */
function dir() {
	if ( dir.arguments.length>=1 ) { path = dir.arguments[0]; }
	else { path = window.location.pathname;	}
	if ( path == "" ) { return path; }
	arr = path.split("/");
	file = (arr.length==0?"":arr.pop());
	f_ = file.split(".");
	if ( f_.length <= 1 ) { return path; }
	return (arr.length==0?"":arr.join("/"));
}
/**
 * Helper function to get the default image directory
 * @return string Returns the web image directory path
 */
function get_image_dir() {
	return get_web_path() + "xbbin/images/";
}
/**
 * Pops up a window using the lnk (uri)
 * @param string url The source to display
 * @param boolean param1 <i>optional</i> True (default), if the window should be centered when displayed
 * @param mixed param2 <i>optional</i> The width for the window
 * @param mixed param3 <i>optional</i> The height for the window
 * @param boolean param4 <i>optional</i> Include a close buttom (Default is True)
 * @param boolean param5 <i>optional</i> allow window to be resized by user (Default is True)
 * @param boolean param6 <i>optional</i> show toolbar (Default is True)
 * @param boolean param7 <i>optional</i> show menubar (Default is True)
 * @param boolean param8 <i>optional</i> show location (Default is True)
 * @param boolean param9 <i>optional</i> show scrollbars (Default is True)
 * @param boolean param10 <i>optional</i> show status (Default is True)
 */
function popwin(url) {
	if ( url.substr(0,1) == '?' ) { url = get_web_file_path()+url; }
	h = screen.height-160;
	w = screen.width-20;
	cls = false;
	center = true;
	tb = ",toolbar=yes";
	mb = ",menubar=yes";
	sb = ",scrollbars=yes";
	lc = ",location=yes";
	st = ",status=yes";
	rz = ",resizable=yes";
	win_left = ",left=0,screenX=0";
	win_top = ",top=0,screenY=0";
	switch ( popwin.arguments.length ) {
		case 11: 
				if ( popwin.arguments[10] != null ) { st = ",status="+(popwin.arguments[10]?"yes":"no"); }
		case 10: 
				if ( popwin.arguments[9] != null ) { sb = ",scrollbars="+(popwin.arguments[9]?"yes":"no"); }
		case 9 : 
				if ( popwin.arguments[8] != null ) { lc = ",location="+(popwin.arguments[8]?"yes":"no"); }
		case 8 : 
				if ( popwin.arguments[7] != null ) { mb = ",menubar="+(popwin.arguments[7]?"yes":"no"); }
		case 7 : 
				if ( popwin.arguments[6] != null ) { tb = ",toolbar="+(popwin.arguments[6]?"yes":"no"); }
		case 6 : 
				if ( popwin.arguments[5] != null ) { rz = ",resizable="+(popwin.arguments[5]?"yes":"no"); }
		case 5 : 
				if ( popwin.arguments[4] != null ) { cls = popwin.arguments[4]; }
		case 4 :
				if ( popwin.arguments[3] != null ) { h = popwin.arguments[3]; }
		case 3 :
				if ( popwin.arguments[2] != null ) { w = popwin.arguments[2]; }
		case 2 :
				if ( popwin.arguments[1] != null ) { center = (popwin.arguments[1]?true:false); }
	}
	width = "width=" +w;
	height = ",height=" + (cls?h+60:h);
	if ( center ) {
		l = set_window_center_left(w);
		t = set_window_center_top(h);
		win_left = ",left="+l+",screenX="+l;
		win_top = ",top="+t+",screenY="+t;
	}
	// build source wrapping
	win_props = "dependent=yes"+(width+height+win_left+win_top==""?"":",")+width+height+win_left+win_top;
	win_props += tb+mb+sb+rz+lc+st;
	window.open(url,"_popwin",win_props);
}
/**
 * Special 'Click to Enlarge' javascript picture.
 * @param string img_src The source of the image
 * @param integer width The width of the window
 * @param integer height The height of the window
 * @param boolean cls <i>optional</i> TRUE (default) if a close button should be present, FALSE for none
 * @param boolean rsz <i>optional</i> TRUE (default) if window can be resized.
 * @param boolean scrl <i>optional</i> TRUE (default) if scroll bars should be present.
 */
function enlarge(title,img_src,width,height) {
	cls = (enlarge.arguments.length==5?(enlarge.arguments[4]==false?false:true):true);
	rsz = (enlarge.arguments.length==6?(enlarge.arguments[5]==false?false:true):true);
	scrl = (enlarge.arguments.length==7?(enlarge.arguments[6]==false?false:true):true);
	img = "<img src=\""+img_src+"\" width=\""+width+"\" height=\""+height+"\">";
	pop_window(title,img,true,width,height,cls,rsz,scrl);
}
/**
 * Pops up a window with the src contained within
 * @param string title The title of the window being displayed
 * @param string src The source to display
 * @param boolean param1 <i>optional</i> True (default), if the window should be centered when displayed
 * @param mixed param2 <i>optional</i> The width for the window
 * @param mixed param3 <i>optional</i> The height for the window
 * @param boolean param4 <i>optional</i> Include a close buttom (Default is True)
 * @param boolean param5 <i>optional</i> Allow resize (Default is True)
 * @param boolean param6 <i>optional</i> Allow scroll (Default is True)
 * @param boolean param7 <i>optional</i> Body background color (Default is white:#ffffff)
 */
function pop_window(title,src) {
	h = screen.height;
	w = screen.width;
	cls = true;
	scrll = "yes";
	resize = "yes";
	bgclr = "bgcolor=\"#ffffff\"";
	lt = "<";
	gt = ">";
	gtlt = gt+lt;
	center = true;
	win_left = ",left=0,screenX=0";
	win_top = ",top=0,screenY=0";
	switch ( pop_window.arguments.length ) {
		case 9 : bgclr = "bgcolor=\""+(pop_window.arguments[8]?pop_window.arguments[8]:"#ffffff")+"\"";
		case 8 : scrll = (pop_window.arguments[7]?"yes":"no");
		case 7 : resize = (pop_window.arguments[6]?"yes":"no");
		case 6 : cls = (pop_window.arguments[5]?true:false);
		case 5 : h = pop_window.arguments[4];
		case 4 : w = pop_window.arguments[3];
		case 3 : center = (pop_window.arguments[2]?true:false);
	}
	use_scroll = (scrll=="yes"?true:false);
	scrll = "scrollbars="+scrll+",";
	resize = "resizable="+resize;
	if ( center ) {
		l = set_window_center_left(w);
		t = set_window_center_top(h);
		win_left = ",left="+l+",screenX="+l;
		win_top = ",top="+t+",screenY="+t;
	}
	// build source wrapping
	head = "";
	foot = "";
	htmlClose = false;
	bodyClose = false;
	switch ( true ) {
		case (src.substring(0,6)!=lt+"html"+gt) : head += lt+"html"+gt; htmlClose = true;
		case (src.substring(0,6)!=lt+"head"+gt) : head += lt+"title"+gt+title+lt+"/title"+gt;
		case (src.substring(0,5)!=lt+"body") :
			head += lt+"body marginheight=\"0\" marginwidth=\"0\" leftmargin=\"0\"";
			head += " rightmargin=\"0\" topmargin=\"0\" "+bgclr+gt; bodyClose = true;
	}
	if ( cls && bodyClose ) {
		foot += lt+"form"+gt;
		foot += lt+"p"+gt+lt+"div align=\"center\""+gt;
		foot += lt+"hr size=\"1\" width=\"100%\"/"+gt;
		foot += lt+"input type=\"button\" name=\"close\" value=\"Close Window\"";
		foot += " onclick=\"window.close()\" style=\""+get_button_style()+"\"/"+gtlt+"/div"+gtlt+"/p"+gt;
		foot += lt+"/form"+gt;
	}
	foot += (bodyClose?lt+"/body"+gt:"")+(htmlClose?lt+"/html"+gt:"");
	width = "width=" +w;
	height = ",height=" + (cls&&bodyClose?parseInt(h)+(use_scroll?100:60):h);
	win_props = "dependent=yes,"+scrll+resize;
	win_props += (width+height+win_left+win_top==""?"":",")+width+height+win_left+win_top;
	src = head+src+foot;
	if ( typeof(win) == "undefined" || win.closed ) {
		win = window.open("","_popwin",win_props);
		win.document.write(src);
	}
	win.focus();
}
/**
 * Helper function that sets the window center left location
 * @param mixed width The width of the screen
 * @return string Returns the centered left or 0 (zero) if center left is greater than or equal
 * to screen width.
 */
function set_window_center_left(width) {
	if ( width >= (screen.width-20) ) { return 0; }
	return (screen.width - width) / 2;
}
/**
 * Helper function that sets the window center top location
 * @param mixed height The height of the screen
 * @return string Returns the center top or 0 (zero) if center top is greater than or equal
 * to screen height.
 */
function set_window_center_top(height) {
	if ( height >= (screen.height-160) ) { return 0; }
	return (screen.height - height) / 2;
}
/**
 * This function returns a string with all occurences of search in subject replaced
 * with the given replace value.
 * @param string needle The string to search for
 * @param string replace The string to replace with
 * @param string haystack The string to search and replace in
 * @return string Returns the string with all found occurences replaced.
 */
function str_replace(needle, replace, haystack) {
	for(var i=0; i<haystack.length; i++) {
		if(haystack.substring(i, i+needle.length) == needle) {
			tempstack = haystack.substring(0, i) + replace;
			haystack = tempstack + haystack.substring(i+needle.length, haystack.length);
		}
	}
	return haystack;
}
/**
 * This function returns the ordinal value (ascii value) of the string passed to it.
 * If a string longer than one character is passed, the first character's ascii value
 * is returned.
 * @param string str The character to translate to an ordinal value
 * @return integer Returns the ordinal value of the string or NULL if the value can not
 * be determined.
 * @see chr()
 */
function ord(str) {
	if ( str.length == 0 ) { return 0; }
	ch = escape(str);
	if ( ch.substring(0,1) == "%" ) {
		ch = ch.substring(1);
		return parseInt(ch,16);
	}
	chrr = str.substring(0,1);
	for (var i=1;i<127;i++) {
		if ( unescape('%'+i.toString(16)) == chrr ) { return i; }
	}
	for (var i=160;i<=255;i++) {
		if ( unescape('%'+i.toString(16)) == chrr ) { return i; }
	}
	return 0;
}
/**
 * Test for credit card number. Optional values allow for spaces or dashes.
 * @param string ccNum The credit card number to test
 * @param boolean allowSpaces <i>optional</i> Allow [TRUE] (default), or disallow [FALSE] spaces
 * in verification.
 * @param boolean allowDashes <i>optional</i> Allow [TRUE], or disallow [FALSE] (default) dashes
 * in verification.
 */ 
function is_cc_num() {
	allowSpaces = true;
	allowDashes = false;
	ccNum = "";
	switch ( is_cc_num.arguments.length ) {
		case 3 : allowDashes = is_cc_num.arguments[2];
		case 2 : allowSapces = is_cc_num.arguments[1];
		case 1 : ccNum = is_cc_num.arguments[0]; break;
		default : return false;
	}
	for(i=0;i<ccNum.length;i++) {
		ascii = ord(ccNum.substr(i,1));
		if ( is_num(ascii) || (allowSpaces && ascii==32) || (allowDashes && ascii==45) ) { continue; }
		return false;
	}
	return true;
}
/**
 * Helper function that takes an ordinal (ascii) value and returns TRUE if it is an alpha character.
 * @param int o Ordinal (ascii) value to test
 * @return boolean Returns TRUE if value falls between 65 and 90, 98 and 122, otherwise FALSE.
 */
function is_alpha(o) {
	if ( o<65 || (o>90 && o<97) || o>122 ) { return false; }
	return true;
}
/**
 * Helper function that takes an ordinal (ascii) value and returns TRUE if the character is a number.
 * @param int o Ordinal (ascii) value to test
 * @return boolean Returns TRUE if value falls between 48 and 57, otherwise FALSE.
 */
function is_num(o) {
	if ( o<48 || o>57 ) { return false; }
	return true;
}
/**
 * Helper function that takes an ordinal (ascii) value and returns TRUE if it is an alpha uppercase
 * character.
 * @param int o Ordinal (ascii) value to test
 * @return boolean Returns TRUE if value falls between 65 and 90, otherwise FALSE.
 */
function is_upper(o) {
	if ( o>=65 && o<=90 ) { return true; }
	return false;
}
/**
 * Helper function that takes an ordinal (ascii) value and returns TRUE if it is an alpha lowercase
 * character.
 * @param int o Ordinal (ascii) value to test
 * @return boolean Returns TRUE if value falls between 97 and 122, otherwise FALSE.
 */
function is_lower(o) {
	if ( o>=97 && o<=122 ) { return true; }
	return false;
}
/**
 * This function returns the string value of the ascii number passed to it.
 * If the value is out of range, null is returned.
 * @param integer val The ascii value to convert to it's string equivalent
 * @return string Returns the string value equivalent of the passed ordinal value or NULL
 * if the value passed is out of range.
 * @see ord()
 */
function chr(val) {
	nums = new Array("\0","\0","\0","\0","\0","\0","\0","\0","\0","\t","\n","\0","\0","\r");
	if ( typeof val != "number" ) { return null; }
	ch = escape(val.toString(16));
	rv = unescape("%"+ch);
	if ( rv.length == 0 ) { return ""; }
	if ( rv.substring(0,1) == "%" ) {
		n = parseInt(rv.substring(1),16);
		if ( n > nums.length-1 ) { return null; }
		else { return nums[n]; } 
	}
	return unescape("%"+ch);
}
/**
 * This function returns a string with whitespace stripped from the beginning and end
 * of str. trim() will strip these characters:
 *   " "	(ASCII 32 (0x20)), an ordinary space.
 *   "\t"	(ASCII 9 (0x09)), a tab.
 *   "\n"	(ASCII 10 (0x0A)), a new lin (line feed).
 *   "\r"	(ASCII 13 (0x0D)), a carriage return.
 *   "\0"	(ASCII 0 (0x00)), the NUL-byte.
 * @param string str The string to trim.
 * @return string Returns str with whitespace removed from both ends.
 */
function trim(str) {
	ds = "  ";
	dt = "\t\t";
	if (typeof str != "string") { return str; }
	rtn = str;
	// remove beginning
	ch = ord(rtn.substr(0, 1));
	while (rtn.length>0 && (ch == 32 || ch == 9 || ch == 0 || ch == 10 || ch == 13 ) ) {
  	rtn = rtn.substr(1, rtn.length);
  	ch = ord(rtn.substr(0, 1));
  }
	// remove ending
  ch = ord(rtn.substr(rtn.length-1, rtn.length));
	while (rtn.length>0 && (ch == 32 || ch == 9 || ch == 0 || ch == 10 || ch == 13 ) ) {
		rtn = rtn.substr(0, rtn.length-1);
   	ch = ord(rtn.substr(rtn.length-1, rtn.length));
  }
  return rtn;
}
/**
 * Alias to object.length, returns the size of the value/object passed
 * @param mixed obj The object to determine size of
 * @return integer Returns the size (length) of the object
 */
function sizeof(obj) {
	try {
		return obj.length;
	}
	catch(e) { return 0; }
}
/**
 * Tests if value is an empty string, null value, or zero length string. If the value is zero (0)
 * this function will return false.
 * @param mixed val The value to test
 * @return boolean Returns true if the value is a zero length string, undefined or null, false if
 * anything else.
 */
function empty(val) {
	if ( typeof(val) == "undefined" ) { return true; }
	if ( typeof(val) == "number" && val == 0 ) { return false; }
	if ( val == null ) { return true; }
	if ( val.length==0 ) { return true; } else { return false; }
	if ( val == "" ) { return true; }
	return false;
}
/**
 * Tests a list (haystack) for any occurrence of (needle) and returns true if found or false if not.
 * @param string needle The value to search in the list for.
 * @param list haystack The list to search.
 * @param boolean is_case Whether the search is case sensitive or not (default is false)
 * @return boolean Returns true if found, false if not
 * @see list_index()
 */
function in_list(needle,haystack,is_case) {
	is_case = (is_case==null?false:is_case);
	for( i=0; i<haystack.length; i++ ) {
		if ( is_case ) {
			if ( needle == haystack[i].value ) { return true; }
		} else {
			if ( needle.toLowerCase() == haystack[i].value.toLowerCase() ) { return true; }
		}
	}
	return false;
}
/**
 * Tests a list (haystack) for any occurrence of (needle) and returns the index if found or -1 if not.
 * @param string needle The value to search in the list for.
 * @param list haystack The list to search.
 * @param boolean is_case Whether the search is case sensitive or not (default is false)
 * @return integer Returns the index if found, or -1 if not
 * @see in_list()
 */
function list_index(needle,haystack,is_case) {
	is_case = (is_case==null?false:is_case);
	for( i=0; i<haystack.length; i++ ) {
		if ( is_case ) {
			if ( needle == haystack[i].value ) { return i; }
		} else {
			if ( needle.toLowerCase() == haystack[i].value.toLowerCase() ) { return i; }
		}
	}
	return -1;
}
/**
 * Helper function to remove the slash from the end of a string. Helpful when working with
 * urls and file paths.
 * @param string str The string to remove the slash from.
 * @return string Returns the string with slash removed from end if it existed.
 * @see trim_slashes(), trim_front_slash()
 */
function trim_end_slash(str) {
	if ( str.length == 0 ) { return str; }
	ch = str.substring(str.length-1);
	if ( ch == "/" || ch == "\\" ) {
		str = str.substring(0,str.length-1);
	}
	return str;
}
/**
 * Helper function to remove the slash from the beginning of a string. Helpful when working with
 * urls and file paths.
 * @param string str The string to remove the slash from.
 * @return string Returns the string with slash removed from beginning if it existed.
 * @see trim_slashes(), trim_end_slash()
 */
function trim_front_slash(str) {
	if ( str.length == 0 ) { return str; }
	ch = str.substring(0,1);
	if ( ch == "/" || ch == "\\" ) {
		str = str.substring(1);
	}
	return str;
}
/**
 * Helper function to remove the slash from both the beginning and end of a string.
 * Helpful when working with urls and file paths.
 * @param string str The string to remove the slash from.
 * @return string Returns the string with slash removed from beginning and end if it existed.
 * @see trim_front_slash(), trim_end_slash()
 */
function trim_slashes(str) {
	str = trim_front_slash(str);
	return trim_end_slash(str);
}
/**
 * Used by {@link pop_window()} to set style of button in popup window.
 * @return string Returns a style format (e.g. {font-family:arial;...} )
 */
function get_button_style() {
	 return "{font-size:11px;}";
}
/**
 * Used by {@link pop_window()} to set style of paragraph in popup window.
 * @return string Returns a style format (e.g. {font-family:arial;...} )
 */
function get_para_style() {
	 return "{font-family:verdana,arial,helvetica;font-size:12px;}";
}
/**
 * Sets the desired image to show. Used primarily by mouseover/mouseout/etc events
 * @param object _this The calling object (typically an <a> tag)
 * @param string name The name of the image to set
 * @param string img The image to replace with
 */
function show(name,img) {
	if ( img == '' ) { return; }
	// check if image has been preloaded
	if ( typeof(document.images[name]) == "undefined" ) { return; }
	// check images path setting
	if ( dir(img) == "" ) {
		// apply path to image using current source path
		img = get_image_dir()+img;
	}
	document.images[name].src = img;
}
/**
 * Sets the image base names from a set of prefined image _on settings
 */
function set_pics_base() {
	if ( typeof(pics_on) == "undefined" ) { return; }
	for (field in pics_on) {
		s = basename(pics_on[field],true);
		pics_base[field] = s.substring(0,s.lastIndexOf("_"));
	}
}
/**
 * Preloads any images set up in two arrays (pics_on and pics_off). These arrays must be predefined
 * as global vars before calling this.
 * @param mixed action If parameter is passed then a cycling will automatically begin
 * @param string dir <i>optional</i> Pass a set directory, otherwise the default xbbin directory for
 * images is used.
 */
function preload_images() 
{	// loads the images for quicker viewing.
	idir = get_image_dir();
	if (preload_images.arguments.length == 2) {
		idir = preload_images.arguments[1];
		if ( idir.lastIndexOf("/") != idir.length-1 ) { idir = idir + "/";}
	}
	set_pics_base();
	onImages = new Array();
  for (field in pics_on) {
		onImages[field] = new Image();
		onImages[field].src = idir + pics_on[field];
	}
  for (field in pics_off) {
		onImages[field] = new Image();
		onImages[field].src = idir + pics_off[field];
	}
	if ( preload_images.arguments.length == 0 ) { return; }
	cycle_images();
}
/**
 * Cycles through a set of images
 */
function cycle_images() {
	if (document.images) {
		var img = "";
		var name = pics_base[(atPic == -1 ? 0 : atPic)];
		obj = eval("document." + name);
		if (obj.complete) {
			atPic++;
			for (field in pics_base) {
				if ( atPic == pics_base.length || atPic < 0 ) { atPic = 0; }
	
				obj = eval("document." + pics_base[field]);
				if ( field == atPic ) { 
					img = idir + pics_on[field];
				} else {
					img = idir + pics_off[field];
				}
				obj.src = img;
			}
	  }
		setTimeout("cycle_images()", 1 * 1000)
	}
}
/**
 * Parses a file path and returns the path with file stripped off. This function
 * returns an end "/" unless the path is empty, then it returns empty.
 * @param string path The path to parse out
 * @return string Returns the path portion of a filepath (without file)
 */
function parse_file_path(path) {
	if ( path.length == 0 ) { return path; }
	a = path.split("/");
	f = a[a.length-1].split(".");
	s = "";
	if ( f.length == 1 ) { return a[a.length-1] + "/"; }
	for(i=0; i<a.length; i++) {
		if ( i == a.length-1 ) {
			f = a[i].split(".");
			if ( f.length > 1 ) { continue; }
		}
		s += (s==""?"":"/") + a[i];
	}
	return s+(s==""?"":"/");
}
/**
 * Object class to store properties of the forms help message
 * @param string control The control name
 * @param string message The message to display.
 * @return object Returns the object
 */
function setFormHelp() {
	this.control = setFormHelp[0];
	this.message = setFormHelp[1];
	return this;
}
/**
 * Returns the current calling url with or without the current query string
 * @param boolean incl_query <i>optional</i> Default is set to TRUE. If set to FALSE,
 * will return the url including any current query string. If empty or set to TRUE,
 * then the url is returned with the query string stripped if it exists.
 * @return string Returns the current url with or without the any existing query string.
 */
function this_url() {
	rtn_query = true;
	proto = location.protocol + "//";
	host = location.hostname;
	path = location.pathname;
	query = location.search;
	if ( this_url.arguments.length > 0 ) { rtn_query = Boolean(this_url.arguments[0]); }
	return location.protocol+"//"+location.hostname+location.pathname+(rtn_query?location.search:"");
}
/**
 * Returns the current url's query string if it exists without the query marker ('?').
 * @return string Returns the current url's query string or "" if no query string.
 */
function this_query() {
	if ( location.search != "" ) { return location.search.substring(1); }
	return "";
}
/**
 * Returns the value of a query string name defined by parameter 'name'. <b>Note:</b> The
 * parameter 'name' is case insensitive by default. This is to say that a name of TestThis will match
 * a query element named testthis as well as TESTTHIS. If you want case sensitivity, set 'casesensitive'
 * parameter to TRUE. 
 * @param string name The name of the query element to return it's value
 * @param boolean casesensitive <i>optional</i> Identifies if the query name search should be
 * case insensitive (default setting), or case sensitive. If set to TRUE the query name search will
 * only return exact match of case.
 * @return string Returns the value of 'name' or empty string if the 'name' is not
 * present in the query string.
 */
function query_value() {
	if ( query_value.arguments.length == 0 ) { return ""; }
	cs = false;
	if ( query_value.arguments.length > 1 ) { cs = Boolean(query_value.arguments[1]); }
	name = (cs?query_value.arguments[0]:query_value.arguments[0].toLowerCase());
	query = location.search;
	if ( query != "" ) { query = query.substring(1); } else { return ""; }
	q = query.split("&");
	for (x=0; x<q.length; x++) {
		nv = q[x].split("=");
		n = (cs?nv[0]:nv[0].toLowerCase());
		if ( n == name ) { return nv[1]; }
	}
	return "";
}
/**
 * Removes the query string name/value pair identified by 'name'. <b>Note:</b> The
 * parameter 'name' is case insensitive by default. This is to say that a name of TestThis will match
 * a query element named testthis as well as TESTTHIS. If you want case sensitivity, set 'casesensitive'
 * parameter to TRUE. Results are returned as a new query string including the query marker ('?').
 * @param string name The name of the query element to remove from the query string
 * @param boolean casesensitive <i>optional</i> Identifies if the query name search should be
 * case insensitive (default setting), or case sensitive. If set to TRUE the query name search will
 * only return exact match of case.
 * @return string Returns a new query string minus the name/value pair identified by 'name'. An empty
 * string is returned if after removal, no name/value pairs remain. Returns untouched query string
 * if no match for 'name' is found.
 */
function strip_query_pair() {
	if ( strip_query_pair.arguments.length == 0 ) { return ""; }
	cs = false;
	if ( strip_query_pair.arguments.length > 1 ) { cs = Boolean(strip_query_pair.arguments[1]); }
	name = (cs?strip_query_pair.arguments[0]:strip_query_pair.arguments[0].toLowerCase());
	query = location.search;
	if ( query != "" ) { query = query.substring(1); } else { return ""; }
	q = query.split("&");
	qs = "?";
	for (x=0; x<q.length; x++) {
		nv = q[x].split("=");
		n = (cs?nv[0]:nv[0].toLowerCase());
		if ( n != name ) { qs += (qs=="?"?"":"&") + n + "=" + nv[1]; }
	}
	return (qs=="?"?"":qs);
}
/**
 * adds commas in number at appropriate values. Assumes the number has no decimal or other non-
 * integer values
 * @param mixed num The number to add commas to
 * @return string Returns the string representation of number with commas added
 */
function commafy(num) {
	s = '';
	c = 0;
	d = 3;
	n = num.toString();
	if ( n.length <= d ) { return n; }
	for(i=n.length;i>=0;i--) { s = (c++==d?',':'')+n.charAt(i)+s; }
	return s;
}
/**
 * Sets a number to a precise decimal level
 * @param mixed val The number to be converted
 * @param integer r The precision (number of decimals)
 */
function precision(val,r) {
	v = strToNum(val);
	sv = v.toString();
	a = sv.split('.');
	n = commafy(parseInt(a[0]));
	s = n+'.';
	if ( a.length == 1 ) {
		s += str_repeat("0",r);
	} else if ( a[1].length > r ) {
		// first round the digits precision + 1
		f = Math.round(parseInt(a[1].substr(0,r+1)));
		// turn into decimal string
		fs = f.toString();
		// capture precision length
		fs += str_repeat("0",(r-fs.length));
		// reduce to precision if longer
		s += fs.substr(0,r);
	} else {
		s += a[1]+str_repeat("0",(r-a[1].length));
	}
	return s;
}
/**
 * Converts a string value to a number
 * @param string val The value to convert
 * @return float Returns the value as a number. If value could not be converted to a number, then
 * 0 (zero) is returned.
 */
function strToNum(val) {
	rgx = /[^0-9\.]/ig;
	if ( val == 'NaN' || val == '' || typeof(val) == "undefined" ) { return 0; }
	s = val+'';
	n = s.replace(rgx,'');
	if ( n == '' | n == '.') { n = 0; }
	return n;
}
/**
 * Unscrambles a previously scrambled data string (scramble performed in PHP xBuilderSMS
 * @param string str The string to unscramble.
 * @return string Returns the unscrambled string
 */
function unscramble(str) {
	b = '@abcdefg_hijklMNOPQRSTUVWXYZAB.CDEFGHIJKL-mnopqrstuvwxyz0123456789';
	a = 'nopqrstuvwxyzabc-defghijklmNOPQRSTUVWXY_ZABCDEFGHIJKLM9876543210.@';
	l = a.length; sl = str.length;
	i = 0; j = 0;
	s = '';
	for(i=0;i<sl;i++) {
		c = str.charAt(i);
		for(j=0;j<l;j++) { if ( a.charAt(j) == c ) { c = b.charAt(j); break; } }
		s += c;
	}
	return s;
}
/**
 * Special xBuilderSMS mailto descrambler. Upon unscrambling, launches the mailto link.
 * @param string data Scrambled mailto string
 */
function jsm(data) {
	u = unscramble(data);
	location.href='mailto:'+escape(u.substr(7));
}
/**
 * Repeats param::str the number of param::count times.
 * @param string str The string value to repeat
 * @param integer count The number of times to repeat
 * @return string Returns the repeated string
 */
function str_repeat(str,count) {
	if ( count < 0 || str == "" ) { return ""; }
	cnt = 1;
	rtnStr = "";
	while ( cnt <= count ) {
		rtnStr += str;
    cnt++
	}
	return rtnStr;
}