function getElementsByClass(searchClass,node,tag)
{
	var classElements = new Array();
	
	// 25 July .... check for string and if so use getEl string
	
	if( node && typeof(node) == 'string' ) // if node is '' (empty string) truth value is false 
	{
			node = getEl(node); // getEl returns null if node does not exist
	}
	
	if ( node == null || node == '' )
	{
		node = document;
	}
	
	if ( typeof(tag) == 'undefined' )
	{
		tag = '*';
	}
	
	var els = node.getElementsByTagName(tag);
	var elsLen = els.length;
	var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)");
	
	for (i = 0, j = 0; i < elsLen; i++) 
	{
		if ( pattern.test(els[i].className) ) 
		{
			classElements[j] = els[i];
			j++;
		}
	}
	return classElements;
}

/* toggle an element's display */
function toggle(obj) 
{
	var el = document.getElementById(obj);
	
	if( !el )
	{
		return;
	}
	
	if ( el.style.display != 'none' ) 
	{
		el.style.display = 'none';
	}
	else 
	{
		el.style.display = '';
	}
}

/* insert an element after a particular node */
function insertAfter(parent, node, referenceNode) 
{
	parent.insertBefore(node, referenceNode.nextSibling);
}

function is_array(a)
{
// Added 11:50 25th April 2007
// from: http://www.planetpdf.com/developer/article.asp?ContentID=testing_for_object_types_in_ja
	if( !a )
	{	
		return null;
	}
	// return ( a.constructor.toString().match(/array/i));  <--- dropped due to Safari and Konq returning function for constructor
	return !!( a && a.constructor == Array ); // see  http://www.optimalworks.net/blog/2007/web-development/javascript/array-detection
}

/* Array prototype, matches value in array: returns bool */
Array.prototype.in_array = function(val) 
{
	var i;
	
	for(i=0,j=this.length; i < j; i++) 
	{
		if(this[i] === val)
		{
			return true;
		}
	}
	
	return false;
};

Array.prototype.reduce=function(templateFunction) 
{
  var l=this.length;
  var s='';
  var tmp = [];
  for (var i=0; i<l; i++)
  {
   	s += templateFunction(this[i]);
	
  }
  return s;
};

// from  http://www.hunlock.com/blogs/Mastering_Javascript_Arrays
Array.prototype.shuffle = function ()
{ 
        for(var rnd, tmp, i=this.length; i; rnd=parseInt(Math.random()*i), tmp=this[--i], this[i]=this[rnd], this[rnd]=tmp);
};

function deal(n) 
{
	var j, k, q = [];
	
	for (j = 0; j < n; j++) 
	{
		k = random(j + 1);
		q[j] = q[k];
		q[k] = j;
	}
	
	return q;
}

function getEl(el)
{
// return appropriate element - no more hard JS or CSS work Navigator 4 and IE4
           
	   if(document.getElementById && document.getElementById(el))
           {
		    	return document.getElementById(el);
           }
           else
	   {
	   	// 25 July 2006 changed return value from false to null
			return null;
	   }
}

function createEl(type,el_id,el_class)
{
// return appropriate element - no more hard JS or CSS work Navigator 4 and IE4

	 var element;
	 
         if( !document.createElement )
	 {
	    return null;
	 }
	 
	 if( !type )
	 {
	 	return null;
	 }
	 
	element = document.createElement(type)
	 
	 if( el_id )
	 {
	   	element.id = el_id;
	 }
	 
	 if( el_class )
	 {
	 	 element.className = el_class;
	 }
	 
	 return element;
}

function browser_obj()
{
	var ua = navigator.userAgent.toLowerCase();

	this.opera = ua.indexOf('opera')!=-1;
	this.konqueror = ua.indexOf('konqueror')!= -1;
	this.ie = !this.opera && !this.konqueror && ua.indexOf('msie') !=-1;
	this.ie5 = this.ie && ua.indexOf('msie 5.0') !=-1;
	this.ie55 = this.ie && ua.indexOf('msie 5.5') !=-1;
	this.ie6 = this.ie && ua.indexOf('msie 6.') !=-1;
	this.ie7 = this.ie && ua.indexOf('msie 7.') !=-1;
	this.opera7 = ua.indexOf('opera/7')!=-1;
	this.opera8 = ua.indexOf('opera/8')!=-1;
	this.gecko = ua.indexOf('gecko')!=-1;
	this.name = navigator.appName;
	this.agent = ua;
	return this;
}

browser = new browser_obj();

function new_image(img_src)
{
	var x = new Image();
	x.src = img_src;
	return x;
}  

function alter_links()
{
	if( !document.links.length ) return;
	if(!document.links[0].setAttribute ) return;
	
	for (i=0; i<document.links.length; i++)  
   	{
		curr_link = document.links[i];
		
		if (curr_link.getAttribute('class') == 'newWindow' || curr_link.className == 'newWindow') 
   		{
			changeAllLinksWithClassToTargetBlanks(curr_link) 
		}
		
		if (curr_link.getAttribute('class') == 'crypto' || curr_link.className == 'crypto') 
   		{
			decrypt_links(document.links[i]) 
		}
		
		
	}
	
}
function changeAllLinksWithClassToTargetBlanks(link) 
{
	// from http://development.incutio.com/simon/targetBlankExperiment.html
	
 		  	link.setAttribute('target', '_blank');
		   	link.setAttribute('title', 'opens in new window');
			
}

function decrypt_links(link)
{
	
		if( !(link_href = link.title) )
		{
			return;
		}
		
		regexp = /^(.+)$/; 
		
		matches = link_href.match(regexp);

		if( ! matches || ! matches.length > 1 ) 
		{
			return;
		}
		
		link_href = encode(matches[1]);
		link.href = link_href;
		link.firstChild.nodeValue = link_href.replace(encode(':LDA38m'),'');
		link.title = 'Email Flowforce';
}


function get_evt_targ(e)
{
	
	var el = null;
	
	evt = e || window.event;
	
	if( evt )
	{
		el = evt.target || evt.srcElement;
	}
	
	return el;
}
 
function get_evt_targ_id(e)
{
		var el = get_evt_targ(e);
				
		if( el && el.id )
		{
			return el.id
		}
		
		return null;	
}

function get_mouse_coords(evt)
{
		
	var evt = v(evt);
		
	if( !evt ) 
	{
		x = null;
		y = null;
	}
	else
	{
		if (evt.pageX || evt.pageY) 	
		{
			x = evt.pageX;
			y = evt.pageY;	
		}
		else if (evt.clientX || evt.clientY)
		{
			x = evt.clientX + Math.max(document.documentElement.scrollLeft,document.body.scrollLeft);
			y = evt.clientY + Math.max(document.documentElement.scrollTop,document.body.scrollTop);
		}
		else
		{
			x = null;
			y = null;
		}
	}
	
	return { x : x, y : y };
}

function getStyleById(id,prop,propNS)
{
	var el = document.getElementById(id);

	if(!el) 
	{
		return null;
	}
	
	var s;

	s =  eval("el.style." + prop);

	if((s != "") && (s != null)) 
	{
		return  s;
	}

	if(el.currentStyle) 
	{
		s = eval("el.currentStyle." + prop);
		
		if((s != "") && (s !== null)) 
		{
			return s;
		}
	}
	
	if(document.defaultView && document.defaultView.getComputedStyle)
	{

	s = (document.defaultView.getComputedStyle(el, '') ) ? document.defaultView.getComputedStyle(el,'').getPropertyValue(propNS) : "";
	
		if((s != "") && (s != null)) 
		{
			return s;
		}
	}
	
	return null;

}

/*****************
The purge function takes a reference to a DOM element as an argument. 
It loops through the element's attributes. If it finds any functions, 
it nulls them out. This breaks the cycle, allowing memory to be reclaimed. 
It will also look at all of the element's descendent elements, and clear 
out all of their cycles as well. The purge function is harmless on Mozilla 
and Opera. It is essential on IE. The purge function should be called before 
removing any element, either by the removeChild method, or by setting the 
innerHTML property.

http://www.crockford.com/javascript/memory/leak.html

****************/
function purge(d) {
    var a = d.attributes, i, l, n;
    if (a) {
        l = a.length;
        for (i = 0; i < l; i += 1) {
            n = a[i].name;
            if (typeof d[n] === 'function') {
                d[n] = null;
            }
        }
    }
    a = d.childNodes;
    if (a) {
        l = a.length;
        for (i = 0; i < l; i += 1) {
            purge(d.childNodes[i]);
        }
    }
}
function create_char_list()
{
	var str = '';
	char_list = [];
	var chars = " -.0123456789:ABCDEFGHIJKLMNOPQRSTUVWXYZ_@abcdefghijklmnopqrstuvwxyz"
	
	for(var i=0;i<chars.length;i++)
	{
		char_list[char_list.length] = chars.charCodeAt(i);
	}
	return char_list;
}

function encode(str_to_encrypt)
{
	if( !str_to_encrypt ) 
	{
		return;
	}
	var forward = create_char_list();
	var reversed = forward.join(','); // break reference to chars so reverse() method does not effect both original and copy of chars
	reversed = reversed.split(',');
	reversed.reverse();
	var ret_list = [];
	ret_str = '';
	
	for(var i=0; i<str_to_encrypt.length; i++)
	{
		var curr_char_code = str_to_encrypt.charCodeAt(i);
		var found = 0;
		
		for(j=0; j<forward.length; j++)
		{
			if( forward[j] == curr_char_code )
			{
				//ret_list[ret_list.length] =  String.fromCharCode(reversed[j]);
				ret_str +=  String.fromCharCode(reversed[j]);
				found = 1;
				break;
			}
		}
		
		if( !found )
		{
			//ret_list[ret_list.length] = str_to_encrypt.charAt(i);
			ret_str += str_to_encrypt.charAt(i);
		}	
	}
	//return ret_list;
	return ret_str;	
}

function change_opacity(el,level)
{
	
	if( typeof(el) == 'string' )
	{
		el = getEl(el);
	}

	if( el == null || typeof(el) != 'object' ) // null is of type object
	{
		return;
	}

	if( typeof(el.style.opacity) != 'undefined' )
	{
		el.style.opacity = level/10;
		
	}
	else if( typeof(el.style.MozOpacity) != 'undefined' )
	{
		el.style.MozOpacity = level/10;
	}
	else if( typeof(el.style.filter) != 'undefined')
	{
		el.style.filter = 'alpha(opacity="' + (level * 10 ) + '")';
	}
}

function debug(func,var_name,var_val,do_alert)
{
	ret_val = 'In ' + func + '() variable "' + var_name + '" has value ';
	
	if( typeof(var_val) == 'string' && var_val.length > 20 )
	{
		ret_val += "\n" + var_val;
	}
	else
	{
		ret_val += var_val;
	}
	
	if( do_alert )
	{
		alert(ret_val);
	}
	else
	{
		return ret_val;
	}
}
function stop_bubble(evt)
{
//	var el = get_evt_targ(evt);

	evt = v(evt);
	
	if (!evt)
	{
		return;
	}
	
	evt.cancelBubble = true;
	evt.returnValue = false;
	
	if( evt.preventDefault ) 
	{
		evt.preventDefault();
	}
	
	if( evt.stopPropagation )
	{
		evt.stopPropagation(); 
	}
}

function first_to_upper(str)
{	
	var first_char = str.substring(0,1);
        var rest = str.substring(1);
        return first_char.toUpperCase() + rest;
}

function disable_text_selection(el)
{
	
	if( typeof(el) == 'string' )
	{
		el = getEl(el);
	}
	
	if( typeof(el) != 'object' )
	{
		return;
	}

	if( typeof(el.onselectstart) != "undefined" )
	{
		el.onselectstart = function()
		{
			return false
		}
	}
	else if( typeof(el.style.MozUserSelect) != "undefined" )
	{
			el.style.MozUserSelect = 'none';
	} 
	else if( typeof(el.unselectable) != "undefined" )
	{
		el.unselectable = 'on';	
	}
	else
	{
		
	}
}
/*
As from Nov 11th 2007 trim functions now based on those found at 
http://www.hunlock.com/blogs/Ten_Javascript_Tools_Everyone_Should_Have

Added token replace as well as \s as above url
*/

String.prototype.trim = function(token) 
{
	if( typeof(token) == 'undefined' )
	{
		//s = '\\s'; // Sun 27th May 2007. Changed default val from ' ' to '\\s' so new lines are replaced in addition to spaces
		return this.replace(/^\s+|\s+$/g,"");
	}
	else
	{
		var regexp = new RegExp('^' + token + '+|' + token + '+$', 'g');
		return this.replace(regexp,"");
	}
}

String.prototype.ltrim = function(token) 
{

	if( typeof(token) == 'undefined' )
	{
		//s = '\\s'; // Sun 27th May 2007. Changed default val from ' ' to '\\s' so new lines are replaced in addition to spaces
		return this.replace(/^\s+/,"");
	}
	else
	{
		var regexp = new RegExp('^' + token + '+');
		return this.replace(regexp,"");
	}
}

String.prototype.rtrim = function(token)
{
   	if( typeof(token) == 'undefined' )
	{
		//s = '\\s'; // Sun 27th May 2007. Changed default val from ' ' to '\\s' so new lines are replaced in addition to spaces
		return this.replace(/\s+$/,"");
	}
	else
	{
		var regexp = new RegExp(token + '+$');
		return this.replace(regexp,"");
	}
}

// random funcs from http://www.merlyn.demon.co.uk/js-randm.htm
function random(x) 
{
    return Math.floor(x * (Math.random() % 1));
}

function random_num(min,max)
{
 	return min + random(max - min + 1);
}

function include_js_file(script_src)
{
	reg_exp = /\/([^\/]+)\..+$/; // match file basename without extension
	var script_id = script_src.match(reg_exp)[1];
	var head = document.getElementsByTagName('head')[0];
	
	if( (script = getEl(script_id)) )
	{
		if( navigator.userAgent.toLowerCase().indexOf('msie') != -1 )
		{
			purge(script); // see Crockford note in common.css
		}
		
		head.removeChild(script);
	}
	
	script = createEl('script',script_id ,'');
	script.type="text/javascript";
	script.defer = true;
	script.src = script_src;
	head.appendChild(script);
	
}

if( typeof(window.encodeURIComponent) == 'undefined' && window.escape ) // for IE 5.0 which doesn't support encodeURIComponent()
{
	window.encodeURIComponent = function(str)
	{
		return escape(str);
	}
}

function v(ev) // returns event object. added Friday Nov 16 2007
{
	var e = null;
	try {e = ev || event;} catch(err){}	
	return e;
}
