String.prototype.trim = function() { return (( ar = /^\s*([\s\S]*\S+)\s*$/.exec(this)) ? ar[1] : "" ); }  // example:  str = str.trim();

try
{
	// add insertAdjacent equivalent "IE only" functions for use in firefox and/or Safari
	if (typeof HTMLElement!="undefined" || !HTMLElement.prototype.insertAdjacentElement)
	{
		HTMLElement.prototype.insertAdjacentElement = function(where, parsed_node)
		{
			switch (where)
			{
				case 'beforeBegin':
					this.parentNode.insertBefore(parsed_node, this)
				break;

				case 'afterBegin':
					this.insertBefore(parsed_node, this.firstChild);
				break;

				case 'beforeEnd':
					this.appendChild(parsed_node);
				break;

				case 'afterEnd':
					if (this.nextSibling)
					{
						this.parentNode.insertBefore(parsed_node, this.nextSibling);
					}
					else
					{
						this.parentNode.appendChild(parsed_node);
					}
				break;
			}
		}

		/**
		 * Allows you to insert an html string either before or after an element in the DOM
		 *
		 * @param string where - Where do you want to insert your stuff (beforeBegin, afterEnd, etc)
		 * @param string html_string - The html string in question
		 *
		 */
		HTMLElement.prototype.insertAdjacentHTML = function(where, html_string)
		{
			var r = this.ownerDocument.createRange();
			r.setStartBefore(this);

			var parsed_HTML = r.createContextualFragment(html_string);
			this.insertAdjacentElement(where, parsed_HTML)
		}


		HTMLElement.prototype.insertAdjacentText = function(where ,txt_str)
		{
			var parsed_text = document.createTextNode(txt_str)
			this.insertAdjacentElement(where, parsed_text)
		}
	}
}
catch(e)
{
}


// "constants" for get()
var CHILD_BY_TAG = 'cTAG_ONE';
var CHILD_BY_CLASS = 'cCLASS_ONE';

var CHILDREN_BY_CLASS = 'dCLASS';
var PARENT_BY_CLASS = 'aCLASS';

var CHILDREN_BY_TAG = 'dTAG';
var PARENT_BY_TAG = 'aTAG';

var CHILDREN_BY_TAG_ONELEV = 'dTAG_ONE';
var CHILDREN_BY_CLASS_ONELEV = 'dCLASS_ONE';

var EVENT_BY_TAG = "eTAG";
var EVENT_BY_CLASS = "eCLASS";
var EVENT = "eEVENT";

// "constants" for highlight()
var MULTI = "multiadd"
var ADD = "singleadd";
var DEL = "singledel";

/**
 * a better version of parseInt
 */
function asInt(value)
{
	return parseInt(value, 10);
}

/**
 * gets the main admin interface window object
 */
function getAdminInterface()
{
	return getInterface('ADMIN_INTERFACE');
}

/**
 * gets the edoss interface window object
 */
function getEdossInterface()
{
	return getInterface('EDOSS_INTERFACE');
}

/**
 * calls a function in the admin interface, with all arguments passed to this
 * function (except for the func name itself) passed to it.
 */
function callAdminFunction(func)
{
	var admin_interface = getAdminInterface();

	if (admin_interface && typeof(admin_interface[func]) == 'function')
	{
		var args = [];

		for (var i = 1; i < arguments.length; i++)
		{
			args.push("arguments[" + i + "]");
		}

		return eval("admin_interface." + func + "(" + args.join(',') + ");");
	}

	return null;
}


/**
 * gets the named interface
 */
function getInterface(interface_name)
{
	var current_window = window;

	while (current_window)
	{
		if (current_window.one45_name == interface_name)
		{
			return current_window;
		}
		else if (current_window == current_window.parent)
		{
			return null;
		}

		current_window = current_window.parent;
	}

	return null;
}

/**
 * Function to add load events to your page once the document has loaded
 *
 * This function was cobbled together from various places:
 * @link http://simonwillison.net/2004/May/26/addLoadEvent/
 * @link http://dean.edwards.name/weblog/2005/09/busted/
 * @link http://www.hedgerwow.com/360/dhtml/ie-dom-ondocumentready.html
 * @link http://www.kryogenix.org/days/2007/09/26/shortloaded
 *
 * @TODO: Test in IE
 * @TODO: Test in Safari
 *
 * @param function func The function you are calling
 */
function addLoadEvent(func)
{
	try
	{
		document.addEventListener("DOMContentLoaded", func, false);
	}
	catch(err)
	{
		(
			function()
			{
				var temp_node = document.createElement('document:ready');

				try
				{
					if (document.readyState != "complete")
					{
						return setTimeout(arguments.callee, 0);
					}

					temp_node.doScroll('left');
					temp = null;
					window.onload = func;
				}
				catch (error)
				{
					setTimeout(arguments.callee, 100);
				}
			}
		)();
	}
}

/**
 * Function to add load events to your page that are fired once the document has loaded
 *
 * @link http://javascript.nwbox.com/ContentLoaded/
 * @link http://simonwillison.net/2004/May/26/addLoadEvent/
 * @link http://dean.edwards.name/weblog/2005/09/busted/
 * @link http://www.hedgerwow.com/360/dhtml/ie-dom-ondocumentready.html
 * @link http://www.kryogenix.org/days/2007/09/26/shortloaded
 *
 * @TODO: This could probably be cleaned up to not use browser sniffing but rather nested try catches
 *
 * @param function fn The function you want to call
 */
function addLoadEvent(fn)
{
	var w = window;
	var d = w.document;
	var u = w.navigator.userAgent.toLowerCase();

	function init(e)
	{
		if (!arguments.callee.done)
		{
			arguments.callee.done = true;
			fn(e);
		}
	}

	// konqueror/safari
	if (/khtml|webkit/.test(u))
	{
		(
			function ()
			{
				if (/complete|loaded/.test(d.readyState))
				{
					init('poll');
				}
				else
				{
					setTimeout(arguments.callee, 10);
				}
			}
		)();
	}
	else if (/msie/.test(u) && !w.opera) // internet explorer all versions
	{
		(
			function ()
			{
				try
				{
					d.documentElement.doScroll('left');
				}
				catch (e)
				{
					setTimeout(arguments.callee, 10);
					return;
				}
				init('poll');
			}
		)();

		d.attachEvent('onreadystatechange',
			function (e)
			{
				if (d.readyState == 'complete')
				{
					d.detachEvent('on'+e.type, arguments.callee);
					init(e.type);
				}
			}
		);
	}
	else
	{
		try
		{
			d.addEventListener('DOMContentLoaded',
				function (e)
				{
					this.removeEventListener(e.type, arguments.callee, false);
					init(e.type);
				}, false
			);
		}
		catch (err)
		{
			var oldonload = w.onload;
			w.onload = function (e)
			{
				if (typeof oldonload == 'function')
				{
					oldonload(e || w.event);
				}
				init((e || w.event).type);
			};
		}
	}
}


/**
 * toggles hidden or showing the given element
 */
function toggle(elem)
{
	if (classname(elem, 'check', 'h'))
	{
		show(elem);
	}
	else
	{
		hide(elem);
	}
}

/**
 * selects all the text inside the given input
 *
 * @param object input The text input to select the text of
 *
 * @todo we could add some further params to specify a range if we find we need that
 *
 * @return void
 */
function selectText(input)
{
	if (typeof(input.setSelectionRange) == 'function')  // ff
	{
		input.setSelectionRange(0, input.textLength);
	}
	else // ie
	{
		var range = input.createTextRange();
		range.select();
	}
}

/**
 *	finds the path to the system root url
 */
function getPathToRoot()
{
	var current_location = window.location.toString();

	// figure out whether we're in admin, public, or the root directory
	var in_admin = (current_location.indexOf('/admin/') > 0);
	var in_public = (current_location.indexOf('/public/') > 0);

	if (in_admin)
	{
		var path = current_location.substr(0, current_location.indexOf('/admin/'));
	}
	else if (in_public)
	{
		var path = current_location.substr(0, current_location.indexOf('/public/'));
	}
	else // we're in the root directory, so trim off the page itself
	{
		// trim everything after the first slash
		var path = current_location.replace(/[^\/]*$/, '');

		// now trim the final slash
		var path = path.replace(/\/$/, '');
	}
	return path;
}

var PATH_TO_ROOT = getPathToRoot();
var SS_PATH = PATH_TO_ROOT + '/ss';
var IM_PATH = PATH_TO_ROOT + '/im';

/**
 *  Displays a nice error if you get a db error through xone
 *
 *  If your page has a debug node, the error will appear in that node. If you do not have a
 *	debug node, then we will display the main iframe (hiding all other iframes) and display
 *	the error in there. If you have neither, we'll just plunk it at the bottom of the body.
 *
 */
function errorCallback(xr)
{
	if (get('debug_node'))
	{
		var node = get('debug_node');
		var cur_contents = node.innerHTML;

		fill('debug_node', cur_contents + xr.xone_result_msg);
	}
	else
	{
		// getMainIframes only exists in fwBase, so if it's present we'll assume we're in the framework
		var in_framework = (typeof(getMainIframes) == 'function');
		var div = create('div');

		// if you are in the framework, use the main window, if not, just use the body
		if (in_framework)
		{
			var all_frames = getMainIframes();
			var main_window = null;

			div.id = "xone_error";

			for (i in all_frames)
			{
				if (all_frames[i].id != "main")
				{
					hide(all_frames[i]);
				}
				else
				{
					main_window = all_frames[i].contentWindow;
					show(all_frames[i]);
				}
			}

			main_window.document.body.appendChild(div);
		}
		else
		{
			document.body.appendChild(div);
		}

		fill(div, xr.xone_result_msg);
	}
}


/**
 *  General purpose function to check to see if user has typed one of a list of keys
 *
 *	Defaults to checking for the return or tab keys
 *
 *  @param object evt - the event object of the keypress
 *	@param array key_codes - array of keycodes you want to check against (optional)
 *  @return mixed - either the event object if one of the keys you're looking for was pressed or false if not
 *
 */
function checkEventKey(evt, key_codes)
{
	/*
		KeyCodes:
			13: return
			9: tab
	*/
	if (key_codes == null)
	{
		var key_codes = new Array();

		key_codes.push(9);
		key_codes.push(13);
	}

	//if key_codes is just a simple number, just make an array out of it
	if (typeof(key_codes) == 'number')
	{
		var key_code = key_codes;
		key_codes = new Array();
		key_codes.push(key_code);
	}

	if (window.event)
	{
		evt = window.event;
	}

	if (in_array(key_codes, evt.keyCode))
	{
		return evt;
	}

	return false;
}


/****************************************/
/*		 MAIN one45.js FUNCTIONS	  */
/****************************************/

/**
 * If you pass deep as true, you get a deep copy of original_object (the whole point)
 */
function clone (original_object, deep)
{
	var object_clone = new Object();

	for (var property in original_object)
	{
	    if (!deep)
	    {
	    	// make property in new obj a ref to the orig
			object_clone[property] = original_object[property];
		}
		else if (typeof this[property] == 'object')
		{
			// recursive call to make a new object for this property
			object_clone[property] = clone(original_object[property], deep);
		}
		else
		{
			// deep copy, but property not an object, is this ok?
			object_clone[property] = original_object[property];
		}
	}

	return object_clone;
}

/**
 * Fires a click event on the elem.
 *
 * @param DOM Node elem (html element)
 */
function click(elem)
{
	var elem = get(elem);

	if(document.createEvent) // mozilla
	{
		var evt = document.createEvent("MouseEvents");

		try
		{
			evt.initMouseEvent('click',		// type
				true, 						// can bubble
				true,						// cancelable
				document.defaultView,		// view
				1,							// detail
				pos(elem), 					// screen x
				pos(elem), 					// screen y
				pos(elem), 					// client x
				pos(elem),					// client y
				false,						// ctrlKey
				false,						// altKey
				false,						// shiftKey
				false,						// metaKey
				1,							// button
				elem);						// relatedTarget
		}
		catch (err) // for safari
		{
			evt.clientX = pos(elem);
			evt.clientY = pos(elem);
			evt.initEvent('click', true, true);
		}

		evt.clicked_node = elem;
		elem.dispatchEvent(evt);
	}
	else // ie
	{
		var evt = document.createEventObject();
		evt.clicked_node = elem;

		// Set an expando property on the event object. This will be used by the
		// event handler to determine what element was clicked on.
		evt.clientX = pos(elem);
		evt.clientY = pos(elem);
		elem.fireEvent('onclick', evt);
		evt.cancelBubble = true;
	}
}

/**
 * Very simple function to get the tagname of an element.
 *
 * @param DOM Node node
 * @reutrn string
 */
function tagname(node)
{
	if (node && node.tagName)
	{
		return node.tagName.toLowerCase();
	}
	return '';
}


/**
	Add an event listener to an html element.

	event_type is the type of event the listener is waiting for(keypress, click, etc...) NB: DONT INCLUDE THE "ON" PART
	func_name is the name of the function to call when the event of the type happens
	elems is an ARRAY of elements to apply the listener to
	alt_ie_event_type is an alternate event type to run if you're in IE because sometimes IE sucks
*/
function addListener(event_type, func_name, elems, alt_ie_event_type)
{
	// add the listener to each elem in your array
	for (var i in elems)
	{
		try		// first try the mozilla way
		{
			elems[i].addEventListener(event_type, func_name, true);
		}
		catch(e)	// then fallback to the ie way
		{
			if (alt_ie_event_type)
			{
				event_type = alt_ie_event_type;
			}
			elems[i].attachEvent('on' + event_type, function (evt) { func_name(evt); });
		}
	}
}

function removeListener(event_type, func_name, elems, alt_ie_event_type)
{
	// add the listener to each elem in your array
	for (var i in elems)
	{
		try		// first try the mozilla way
		{
			elems[i].removeEventListener(event_type, func_name, true);
		}
		catch(e)	// then fallback to the ie way
		{
			if (alt_ie_event_type)
			{
				event_type = alt_ie_event_type;
			}
			elems[i].detachEvent('on' + event_type, function (evt) { func_name(evt); });
		}
	}
}

function get(elem)
{
	if (arguments.length == 1)
	{
		return (isElem(elem)) ? elem : document.getElementById(elem);
	}
	else
	{
		for (var i = 0, args = new Array(); i < arguments.length; i++)
		{
			args.push(arguments[i]);
		}

		return superget(args);
	}
}

function classname(node, op, c1, c2)
{
	if (node = get(node))
	{
		if (op == 'clear')
		{
			node.className = "";
			return;
		}
		if (op == 'split')
		{
			return (node.className.trim() != "") ? node.className.split(/\s+/) : new Array();
		}

		if (op == 'check')
		{
			if (node.className.trim() != '')
			{
				var classnames = node.className.split(/\s+/);

				for (var i = arguments.length - 1; i >= 2; i--)
				{
					if (in_array(classnames, arguments[i]))
					{
						return 1;
					}
				}
			}
			return 0;

		}

		var cn = node.className;
		var index = cn.search('\\b' + c1 + '\\b');
		var exists = (index < 0) ? 0 : 1;
		var middle = "";

		switch (op)
		{
			case 'add':
				middle = c1;
			break;

			case 'swap':
				middle = (exists) ? c2 : "";
			break;
		}

		var length = c1.length;
		index = (exists) ? index : cn.length;
		var pre = cn.substr(0, index).trim();
		var post = cn.substr(index + length).trim();


		node.className = (pre + " " + middle + " " + post).trim();

		if (op == 'switch')
		{
			classname(node, 'add', c2);
		}
		else if (op == 'swap' && !exists)
		{
			classname(node, 'switch', c2, c1);
		}
		return node;
	}
	return null;
}

function del()
{
	return cycle(arguments, 'del');
}

function show()
{
	return cycle(arguments, 'show');
}

function hide()
{
	return cycle(arguments, 'hide');
}

/**
 * this is a an override of hide() specifically for iframes
 *
 * the difference is setting width and height to 0 instead of display:none for
 * some browser quirk that has since been forgotten!
 */
function hideIframe()
{
	return cycle(arguments, 'hideIframe');
}

/**
 * this is an override of show() specifically for iframes
 *
 * the differene is the flipside of that metioned in hideIframe()
 */
function showIframe()
{
	return cycle(arguments, 'showIframe');
}

/**
 * this is an override of hide() to leave element in document flow
 *
 * the difference is to use visibility:hidden/visible instead of display:none
 */
function hideContent(elem)
{
	return cycle(arguments, 'hideContent');
}

/**
 * this is an override of show() to leave element in document flow
 *
 * the differene is the flipside of that metioned in hideContent()
 */
function showContent(elem)
{
	return cycle(arguments, 'showContent');
}

// returns a value from a classname
function getTagValueFromClass(elem,tag)
{
	//get tag=value string
	var tagValString = new String(elem.className.match(RegExp(tag+'=\\S+')));
	//now strip the tag= part
	return tagValString.replace(tag+'=','');
}


function table_x(td_node)
{
	var td = get(td_node, PARENT_BY_TAG, 'td');
	var tr = td.parentNode;

	for (var i = 0; tr.childNodes[i] != td; i++)
		;

	return i;
}

function table_y(tr_node)
{
	var tr = get(tr_node, PARENT_BY_TAG, 'tr');
	var tbody = tr.parentNode;

	for (var i = 0; tbody.childNodes[i] != tr; i++)
		;

	return i;
}

function highlight(node, hl_class, op)
{
	var op = (!op) ? ADD : op;
	var node = get(node);
	var hl_class = (arguments.length == 1) ? "o" : hl_class;

	if (arguments.length < 3)
	{
		switch (node.tagName.toLowerCase())
		{
			case 'ul':
			case 'ol':
			case 'table':
			case 'tbody':
				op = MULTI;
			break;
		}
	}
	switch (op.substr(0, op.length - 3))
	{
		case "single":
			var classname_op = op.substr(op.length - 3);
			classname(node, classname_op, hl_class);
		return node;

		case 'multi':
			for (var i = 0, n = node; n && i < n.childNodes.length; i++)
			{
				op = (i % 2 == 0) ? 'add' : 'del';
				classname(n.childNodes[i], op, hl_class);
			}
		break;
	}
	return node;
}

function fill(obj, html)
{
	switch (arguments.length)
	{
		case 1:
			for (i in obj)
			{
				get(i).innerHTML = obj[i];
			}
		break;

		case 2:
			var obj = get(obj);
			obj.innerHTML = html;
		return obj;
	}
}


function replace(obj, html)
{
	var node = get(obj);
	var container = node.parentNode;
	var div = create('div', { className: 'h' });

	node.parentNode.appendChild(div);

	fill(div, html);

	var first_elem = true;

	while (div.lastChild)
	{
		if (first_elem)
		{
			container.cur_elem = div.lastChild;
			container.replaceChild(div.lastChild, node);
			first_elem = false;
		}
		else
		{
			container.insertBefore(div.lastChild, node);
			container.cur_elem = container.cur_elem.previousSibling;
		}
	}

	// cleanup
	div.parentNode.removeChild(div);
}


function squeeze(elem, html, node)
{
	var node = get(node);
	var html = (is_array(html)) ? html : new Array(html);
	var elem = get(elem);

	for (var i = 0; i < html.length; i++)
	{
		var node_f = (isElem(html[i])) ? 1 : 0;

		if (node_f)
		{
			elem.insertBefore(html[i], node);
		}
		else
		{
			var dummy = create('div');
			fill(dummy, html[i]);

			while (dummy.firstChild)
			{
				elem.insertBefore(dummy.firstChild, node);
			}
		}
	}
	return elem;
}

function create(tagname, attribs, content, num)
{
	var attribs = (!attribs) ? new Array() : attribs;
	var num = (arguments.length < 4) ? 1 : num;

	for (var i = 0, ret_a = new Array(); i < num; i++)
	{
		ret_a[i] = (isElem(tagname)) ? elem.cloneNode(true) : document.createElement(tagname);

		for (attribute in attribs)
		{
			att = (attribute == 'className' && !window.ActiveXObject) ? 'class' : attribute;
			ret_a[i].setAttribute(att, attribs[attribute]);
		}
		if (content)
		{
			fill(ret_a[i], content);
		}
	}
	return (num == 1) ? ret_a.pop() : ret_a;
}

function pos(elem, hidden)
{
	var el = get(elem);

	if (hidden)
	{
		show(elem);
	}

	var x = el.offsetLeft;
	var y = el.offsetTop;
	var height = el.offsetHeight;
	var width = el.offsetWidth;

	if (hidden)
	{
		hide(elem);
	}

	var tempElem = el.offsetParent;

	while (tempElem != null)
	{
		x += tempElem.offsetLeft - tempElem.scrollLeft;
		y += tempElem.offsetTop - tempElem.scrollTop;
		tempElem = tempElem.offsetParent;
	}

	return {left: x, top: y, height: height, width: width};
}

function move(elem, x, y)
{
	var elem = get(elem);

	elem.style.left = x + "px";
	elem.style.top = y + "px";
}


function repositionWindow(node)
{
	var position = pos(node);
	window.scrollTo(0, position.top);
}


function stopProp(evt)
{
	if (!evt) // for IE's benefit
	{
		var evt = window.event;
	}
	evt.cancelBubble = true;

	if (evt.stopPropagation)
	{
		evt.stopPropagation();
	}
}

var dumpage = new Array();

/**
 * dumps dumpee to a div on top of whatever page you are loading.
 * Note that in Firefox, console.log() is often better to use
 * than dump(). 
 *
 * @todo make styles a class and add to one45.css
 *
 * @return the div with the dumped data
 */
function dump(dumpee, header, attrib_keys, clear)
{
	var is_ie = window.ActiveXObject;

	var div = get('dump_div');
	var indent = '';

	if (div == null || clear)
	{
		div = create('div', {id: 'dump_div'});
		document.body.appendChild(div);
		var exit = create('div', {align: 'right'}, "close");
		exit.style.textDecoration = 'underline';
		exit.style.cursor = 'pointer';
		exit.style.font = 'bold small-caps 14px sans-serif';
		exit.style.color = 'red';

		exit.onclick = function() { hide(div); }

		div.appendChild(exit);

		div.style.position = 'absolute';
		div.style.top = '100px';
		div.style.left = '100px';

		var width  = (typeof(window.innerWidth) == 'number')  ?
										window.innerWidth  :
										document.documentElement.clientWidth;

		div.style.width  = width - 200 + 'px';
		div.style.border = '5px solid blue';
		div.style.zIndex = '9999999';
		div.style.backgroundColor = 'khaki';
		div.style.overflow = 'auto';
		div.style.padding = '20px';
	}

	if (header)
	{
		var h1 = create('h1', {style: 'color:red;font-size:large;'}, header);
		div.appendChild(h1);
	}

	pre = create('pre');
	pre.style.whiteSpace = 'nowrap';
	div.appendChild(pre);

	if (is_array(attrib_keys))
	{
		// override global (declared just below)
		dump_attribute_keys = attrib_keys;
	}
	dump_helper(dumpee, pre, indent);

	div.appendChild(create("hr"));
	show(div);
	return div;
}

/**
 * attributes that get dumped for HTMLElements (anything with obj.tagName)
 */
var dump_attribute_keys = ['id', 'name', 'value', 'checked', 'className', 'tagName', 'innerHTML'];
// other possibilities
// onclick, onmouseover, action, method, what else?
// TODO: extend dump() to allow passing an array of attribs you care about to override
var DUMP_INDENT_INCREMENT = '&nbsp;&nbsp;&nbsp;&nbsp;';

function dump_helper(dumpee, target, indent)
{
	if ((dumpee == null) || (typeof(dumpee) != 'object' && dumpee == ''))
	{
		dumpee = 'NULL';
	}
	var type = typeof(dumpee);

	switch (type)
	{
		case 'object':

			// IE doesn't "see" the classname for HTMLElements, so the replace
			// does nothing
			var name = (is_array(dumpee)) ? "Array" :
							dumpee.toString().replace(/\[object (\w+)\]/, "$1");

			target.innerHTML += name + '<br />' + indent + '(<br />';
			var keys;
			var value;

			if (dumpee.tagName)  // it's an HTMLElement
			{
				keys = dump_attribute_keys;
			}
			else
			{
				keys = dumpee;
			}

			for (i in keys)
			{
				if (dumpee.tagName)
				{  // HTMLElement; use values in keys array as key
					i = keys[i];
				}

				value = dumpee[i];
				target.innerHTML += indent + DUMP_INDENT_INCREMENT + '[' + i + '] => ';
				dump_helper(value, target, indent + DUMP_INDENT_INCREMENT);
				target.innerHTML += '<br />';
			}

			target.innerHTML += indent + ")";
		break;

		case 'function':
			target.innerHTML += 'function()<br />';
		break;

		case 'number':
			target.innerHTML += dumpee;
		break;

		case 'boolean':
			target.innerHTML += (dumpee) ? 'true' : 'false';
		break;

		case 'string':
		default:
			dumpee = dumpee.replace(/</g, "&lt;");
			dumpee = dumpee.replace(/>/g, "&gt;");
			target.innerHTML += dumpee;
	}
}

function redirect(location, title, args)
{
	var new_window = window.open(location, title, args);
}

function olddump(text)
{
	var div = document.createElement('div');

	if (is_array(text))
	{
		for (var i = 0; i < text.length; i++)
		{
			var temp_div = document.createElement('div');
			var stars = makeStars();

			temp_div.appendChild(document.createTextNode(text[i]));

			div.appendChild(temp_div);
			div.appendChild(stars);
		}
	}
	else
	{
		var stars = makeStars();

		div.appendChild(document.createTextNode(text));
		div.appendChild(stars);
	}

	document.body.appendChild(div);
	div.id = "dump";
}

/****************************************/
/*		 END one45.js FUNCTIONS	   */
/****************************************/


/****************************************/
/*		 HELPFUL ARRAY FUNCTIONS	  */
/****************************************/
function array_search(val, arr)
{
	var found = -1;

	for (var i = 0; i < arr.length; i++)
	{
		if (arr[i] == val)
		{
			found = i;
			break;
		}
	}
	return found;
}

/**
 * Search a sorted Array object.
 *
 * Note that this expects an Array object ([1,2,3]), not a generic object
 * used as an associative array {0:1,1:2,2:3}.
 *
 * @param arr Sorted Array object
 * @param target Target value
 * @return Index of the target value in the array, if found, else -1.
 * @author Petter Haggholm <petter@one45.com>
 */
function sortedArraySearch(arr, target)
{
	var min = 0, max = arr.length-1;
	var value, index;

	while (min <= max)
	{
		// R-shifting rather than dividing by 2 because Javascript
		// does floating-point division...
		index = (min+max) >> 1;
		value = arr[index];

		if (value > target)
		{
			max = index-1;
		}
		else if (value < target)
		{
			min = index+1;
		}
		else // cur == val
		{
			return index;
		}
	}
	return -1;
}


/**
 * Remove an element from a sorted Array object.
 *
 * This only removes the item once; if there are multiple occurrences, you
 * will need to call the function multiple times.
 *
 * @param arr
 * @param target
 * @return true if the item was found and removed, else false.
 * @author Petter Haggholm <petter@one45.com>
 */
function sortedArrayRemove(arr, target)
{
	var i = sortedArraySearch(arr, target);
	if (i != -1)
	{
		arr.splice(i, 1);
		return true;
	}
	else
	{
		return false;
	}
}

function array_walk(walk_a, item_name, walk_code)
{
	walk_code = walk_code.replace(item_name, 'walk_a[i]');

	for (var i = 0; i < walk_a.length; i++)
	{
		eval(walk_code);
	}
}

function in_array(arr, val)
{
	var found = 0;

	for (var i = 0; i < arr.length; i++)
	{
		if (arr[i] == val)
		{
			found = 1;
			break;
		}
	}

	return found;
} 

function is_array(obj)
{
	try
	{
		if(typeof(obj) != "object" || obj == null)
		{
			return false;
		}
		else
		{
			// check for absence of obj.splice is a hack that may not work across
			// browsers. needed to do this (or something like it) for safari.
			if (obj.constructor.toString().indexOf("Array") == -1 && !(obj.splice()))
			{
				return false;
			}
			else
			{
				return true;
			}
		}
	}
	catch(e)
	{
		return false;
	}


}


// counts the number of objects in an associative array or object
function count(obj)
{
	$cnt = 0;

	for (i in obj)
	{
		$cnt++;
	}

	return $cnt;
}


/**
 * Same as PHP array_keys - returns an array of keys
 * of the passed array.
 *
 * @param Array arr
 * @return Array - an array keys
 */
function array_keys(arr)
{
	var keys = [];

	for (i in arr)
	{
		keys.push(i);
	}

	return keys;
}


// replace the inner HTML of a form element
function replaceInnerHtml(elem_to_fill, new_html)
{
	var elem_to_fill = get(elem_to_fill);
	var parent = elem_to_fill.parentNode
	var next_sibling = elem_to_fill.nextSibling;
	if (next_sibling)
	{
		del(elem_to_fill);
		squeeze(parent, new_html, next_sibling);
	}
	else
	{
		del(elem_to_fill);
		squeeze(parent, new_html);
	}
}

/****************************************/
/*		 END ARRAY FUNCTIONS		  */
/****************************************/


function clearFormTextValues(form)
{
	for (var i = 0; i < form.elements.length; i++)
	{
		if (form.elements[i].nodeType == 1 && form.elements[i].name && form.elements[i].type == 'text')
		{
			if (!classname(form.elements[i], "check", "chg"))
			{
				form.elements[i].value = "";
			}
		}
	}
}


// helper functions (ignore these)
function superget(args)
{
	var opt = args[1];
	var one_lev = 0;

	switch (opt)
	{
		case 'eEVENT':
		case 'eTAG':
		case 'eCLASS':
			var e = args.shift();
			var baseEl = (e.srcElement) ? e.srcElement : e.target;

			args.shift();
		return ((opt != 'eEVENT' && checkTagOrClass(baseEl, args, opt.charAt(1).toLowerCase()) || opt == 'eEVENT')) ? baseEl : null;

		case 'dTAG_ONE':
		case 'dCLASS_ONE':
			one_lev = 1;

		case 'dCLASS':
		case 'aCLASS':
		case 'dTAG':
		case 'aTAG':
			var node = args.shift();
			var get_type = opt.charAt(1).toLowerCase();

			args.shift();
		return (opt.charAt(0) == 'd') ? getDescendants(node, args, get_type, one_lev) : getAncestor(node, args, get_type);

		case 'cCLASS_ONE':
		case 'cTAG_ONE':
			var node = args.shift();
			var get_type = opt.charAt(1).toLowerCase();
			args.shift();
		return getDescendants(node, args, get_type, 0).pop();

		default:
			for (var i = 0, ret_a = new Array(); i < args.length; i++)
			{
				ret_a.push(get(args[i]));
			}
		return ret_a;
	}
}

function checkTagOrClass(n, crit_a, get_type)
{
	var crit_a = (is_array(crit_a)) ? crit_a : {0: crit_a};
	var add = false;

	for (i in crit_a)
	{
		add = false;

		switch (get_type)
		{
			case 'c':
				var add = classname(n, 'check', crit_a[i]);
			break;

			case 't':
			default:
				var add = (n.tagName.toLowerCase() == crit_a[i].toLowerCase()) ? true : false;
			break;
		}
		if (add)
		{
			return add;
		}
	}
}

function getAncestor(node, args, get_type)
{
	var node = get(node);
	var new_args = new Array();

	for (var i in args)
	{
		new_args.push(args[i]);
	}

	try
	{
		while (node && !checkTagOrClass(node, new_args, get_type))
		{
			try
			{
				node = node.parentNode;
			}
			catch (e)
			{
				node = node;
			}
		}

		return node;
	}
	catch (e)
	{
		return null;
	}
}

function getDescendants(node, args, get_type, one_lev)
{
	var ret_a = new Array();
	var node = get(node);

	for (var i = 0; node && i < node.childNodes.length; i++)
	{
		var n = node.childNodes[i];
		var add = 0;

		if (n.nodeType == 1 && checkTagOrClass(n, args, get_type))
		{
			ret_a.push(n);
		}
		if (n.hasChildNodes() && !one_lev)
		{
			var child_a = getDescendants(n, args, get_type);

			if (child_a.length)
			{
				ret_a = ret_a.concat(child_a);
			}
		}
	}
	return (ret_a.length) ? ret_a : new Array();
}

function isElem(elem)
{
	return (elem && elem.tagName) ? true : false;
}

function cycle(args, op)
{
	for (var i = 0; i < args.length; i++)
	{
		if (args[i])
		{
			switch (op)
			{
				case 'show':
				case 'hide':
					classname(args[i], (op == 'show') ? 'del' : 'add', 'h');
				break;

				case 'hideContent':
				case 'showContent':

					var elem = get(args[i]);

					if (isElem(elem))
					{
						elem.style.visibility = (op == 'hideContent') ? 'hidden' : 'visible';
					}

				break;

				case 'del':
					var el = get(args[i]);

					if (el)
					{
						el.parentNode.removeChild(el);
					}
				break;

				case 'hideIframe':
				case 'showIframe':
					var frame = get(args[i]);

					if (frame)
					{
						if (op == 'hideIframe')
						{
							frame.style.width  = 0;
							frame.style.height = 0;
						}
						else
						{
							frame.style.width  = frame.real_width;
							frame.style.height = frame.real_height;
						}
					}
				break;
			}
		}
	}
	if (i == 1)
	{
		return get(args[0]);
	}
}

/**
 * Function for checking validity of date spans
 * - checks that both dates are valid dates and that from_date <= to_date
 *
 * @param from_date - The start date we are checking against
 * @param to_date - The end date we are checking against
 *
 * @return string - Error message or empty string
 *
 */
function checkDateSpan(from_date, to_date)
{
	//first, make sure the dates are valid
	var from_value = Date.parse(from_date);
	var to_value = Date.parse(to_date);
	var msg = '';

	if (isNaN(from_value))
	{
		msg = 'Invalid dates: There is no specified start date.';
	}
	else if (isNaN(to_value))
	{
		msg = 'Invalid dates: There is no specified end date.';
	}
	else if (from_value > to_value)
	{
		msg = 'Invalid dates: Start date must not occur after end date.';
	}

	return msg;
}


/**
 * Defines the javascript event(s) for the help tag (help.php)
 * - when the help link is activated, a new window/tab is opened with the given location
 *
 * @return void;
 */
function openHelpLink(location)
{
	var form_id = 'help_link_form';
	var form = get(form_id);

	if (!form)
	{
		form = create('form');
		form.id = form_id;

		hide(form);
		document.body.appendChild(form);
		form.target = 'one45_help';
	}

	form.action = location;
	form.submit();
}

/**
 * Parses a string with tag=value tag2=value2 and extracts the value corressponding to the tag.
 * @param DOMNode elem
 * @param string - name of the value we want from the classname
 *
 * @return string
 */
function getTagValueFromClass(elem, tag)
{
    var tagValString = new String(elem.className.match(RegExp(tag+'=\\S+')));
    //now strip the tag= part
    return tagValString.replace(tag+'=','');
}

/**
 * @return int the height of the current frame, in pixels
 */
function getWindowHeight()
{
	return document.documentElement.clientHeight;
}

/**
 * @return int the width of the current frame, in pixels
 */
function getWindowWidth()
{
	return document.documentElement.clientWidth;
}

function is_ie()
{
	return (window.ActiveXObject) ? true : false;
}


/**
 * Invoke window.location.reload(); useful for simple xone callbacks.
 */
function reloadPage()
{
	if (is_ie())
	{
		window.location.reload();
	}
	else
	{
		window.location.href = window.location.href;
	}
}

/**
 * Returns the stylesheet embedded in a document
 */
function getStyleSheetRules()
{
	var rules = null;

	// for FireFox
	if (document.styleSheets[0].cssRules)
	{
		rules = document.styleSheets[0].cssRules
	}
	// for IE
	else if (document.styleSheets[0].rules)
	{
		rules = document.styleSheets[0].rules	
	}
	
	return rules;	
}

/**
 * Returns the number of days difference between two dates
 * @param string start_date in M d, Y format
 * @param string end_date in M d, Y format
 * @return int
 */
function getDaysDiff(start_date, end_date)
{
	var start_date = new Date(start_date);
	var end_date = new Date(end_date);

	var number_of_millisec_in_a_sec = 1000;
	var number_of_sec_in_an_hour = 60;
	var number_of_hour_in_a_day = 24;
	var number_of_millisec_in_a_day = 1000 * 60 * 60 * 24;
		
	var diff = end_date - start_date; //difference in milliseconds
	return new String(diff/number_of_millisec_in_a_day); //calculate days and convert to string
}

/**
 * for javascript translation
 */
function currentLocale()
{
	if (typeof(CURRENT_LOCALE) != 'undefined')
	{
		return CURRENT_LOCALE;
	}
	else
	{
		return "en_CA";
	}
}

/**
 * for javascript translation
 */
function overrideTranslation()
{
	if (typeof(OVERRIDE_TRANSLATION) != 'undefined')
	{
		return OVERRIDE_TRANSLATION;
	}
	else
	{
		return false;
	}
}