/**************************************************************************************************/
// Code Cavalier JavaScript Library 2 - Prototypes & Objects
// Copyright 2009. Brodie Sebresos. Please redistribute freely.
// Refer to website for periodic updates.
// http://codecavalier.com/dhtml/cc_lib/cc2.js
// Version: 2.0.14 (2011-05-23)
//
// The cc2.js library is a collection of various free scripts that have been gleaned from across
// the Internet, and modified to work within a global cc object. This approach encapsulates most
// of the library within its own name space, thus increasing portability. It is also composed of
// several JavaScript native object prototypes which are considered ubiquitous enough to avoid
// causing compatibility problems when used in conjunction with other libraries. cc2.js provides
// much of the best and most commonly used JavaScript functionality in an integrated, concise,
// unobtrusive, and cross-platform compatible package.
//
// A large portion of the code is original work by Brodie Sebresos, being influenced by many other
// of the great minds in web browser innovation. In instances where code has been taken directly
// from other programmers, credit and reference links have been provided. If any portion of this
// code is improperly copied or credited, please report cases to: webmaster@codecavalier.com
/**************************************************************************************************/
//WISH LIST:
//  FEATURE: Automatic box element drop shadows from class="dropShadow" attribute
//   SOURCE: http://www.tastypopsicle.com/dropshadow/
//   SOURCE: http://www.erik-rasmussen.com/blog/2006/12/04/the-shadower-realistic-drop-shadows-in-javascript/
//  FEATURE: Automatic tool tips from toolTip="" attribute
//  FEATURE: Port ajax support from cc_lib
/**************************************************************************************************/
//ERRATA:
// 2011-05-23: Ability to make Ajax calls with username/password?????
/**************************************************************************************************/




/**************************************************************************************************/
// Extensions to the basic JavaScript language by prototyping native objects. These are considered
// so ubiquitous that even if they are already defined in other libraries, they should have the
// same functionality, so redefining them here is safe.
/**************************************************************************************************/
//FUNCTION: window.$() - courtesy of Dustin Diaz, The Prototype Dollar Function, http://www.dustindiaz.com/top-ten-javascript/
if (typeof window.$ !== 'function') window.$ = 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;
}
//PROTOTYPE: Object.beget(o) - makes a cloned object that inherits the properties of the parent object (aka: prototypal inheritance) - Crockford, Douglas (2008). JavaScript: The Good Parts, 1st Edition. O'Reilly Media, Inc. p. ??. ISBN-13 978-0-596-51774-8. Safari Books Online. Retrieved on Feb 6, 2009. http://my.safaribooksonline.com/9780596517748/prototype
if (typeof Object.beget !== 'function') Object.beget = function(o) {
	var F = function() {};
	F.prototype = o;
	return new F();
}
//PROTOTYPE: removeAllChildren() - clears all children of a DOM node
// Note: some browsers don't support prototypes for certain objects, and browsers don't agree upon the class names for all objects.
//       Thus, not all objects can be prototyped.  I.E.: the following removeAllChildren prototype works in Firefox, but not IE; also
//       the class name for HTML Collection objects is not the same across all browsers.  The result is that you just can't prototype
//       everything--sometimes you must use a global function.  If you are having trouble using this prototype, try using cc.clear().
if (typeof Element.prototype.removeAllChildren !== 'function') Element.prototype.removeAllChildren = function() {
	while(this.childNodes.length)
		this.removeChild(this.childNodes[0]);
	return this;
}
//PROTOTYPE: Number.integer() - returns the integer portion of positive or negative real numbers - Crockford, Douglas (2008). JavaScript: The Good Parts, 1st Edition. O'Reilly Media, Inc. p. ??. ISBN-13 978-0-596-51774-8. Safari Books Online. Retrieved on Feb 6, 2009. http://my.safaribooksonline.com/9780596517748/augmenting_types
if (typeof Number.prototype.integer !== 'function') Number.prototype.integer = function() {
	return Math[(this < 0 ? 'ceil' : 'floor')](this);
}
//PROTOTYPE: Number.pad0(newlength) - Zero padding
if (typeof Number.prototype.pad0 !== 'function') Number.prototype.pad0 = function(newlength) {
	return String(this).pad0(newlength);
}
//PROTOTYPE: String.pad0(newlength) - Zero padding
if (typeof String.prototype.pad0 !== 'function') String.prototype.pad0 = function(newlength) {
	if(isFinite(this))
	{//this is a number
		var pad = '';
		var len = newlength-String(this).length;
		for (var i=0;i<len;i++)
			pad += '0';
		return pad+this;
	}
	else
		return this;
}
//PROTOTYPES: 3 Javascript functions that trim whitespace from the ends of strings using simple, elegant regular expressions. The functions are granted to the public domain. © Shailesh N. Humbad - http://www.somacon.com/p355.php
if (typeof String.prototype.trim !== 'function') String.prototype.trim = function() {
	return this.replace(/^\s+|\s+$/g,"");
}
if (typeof String.prototype.ltrim !== 'function') String.prototype.ltrim = function() {
	return this.replace(/^\s+/,"");
}
if (typeof String.prototype.rtrim !== 'function') String.prototype.rtrim = function() {
	return this.replace(/\s+$/,"");
}

//==== Prototypes inspired by Sven Tofte: www.svendtofte.com/code/usefull_prototypes/prototypes.js
//PROTOTYPES: Number.max(a,b), Number.min(a,b) - returns the greater/lesser of the two inputs
if (typeof Number.prototype.max !== 'function') Number.prototype.max = function(a,b) {
	return a<b?b:a;
}
if (typeof Number.prototype.min !== 'function') Number.prototype.min = function(a,b) {
	return a>b?b:a;
}
//METHOD: Math.mod(val,mod) - standard mathematical mod function
if (typeof Math.mod !== 'function') Math.mod = function(val,mod) {
	if (val < 0) {
		while(val<0) val += mod;
		return val;
	} else {
		return val%mod;
	}
}
//METHODS: window.getInnerWidth(), window.getInnerHeight() - cross-platform, return dimensions of the browser window in pixels
if (typeof window.getInnerWidth !== 'function') window.getInnerWidth = function() {
	if (window.innerWidth) {
		return window.innerWidth;
	} else if (document.body.clientWidth) {
		return document.body.clientWidth;
	} else if (document.documentElement.clientWidth) {
		return document.documentElement.clientWidth;
	}
}
if (typeof window.getInnerHeight !== 'function') window.getInnerHeight = function() {
	if (window.innerHeight) {
		return window.innerHeight;
	} else if (document.body.clientHeight) {
		return document.body.clientHeight;
	} else if (document.documentElement.clientHeight) {
		return document.documentElement.clientHeight;
	}
}
//PROTOTYPE: String.endsWith(str) - returns true if the end of the object string is equal to the passed string
if (typeof String.prototype.endsWith !== 'function') String.prototype.endsWith = function(str) {
	return (this.length-str.length)==this.lastIndexOf(str);
}
//PROTOTYPE: String.reverse() - returns a string that is the object string turned around
if (typeof String.prototype.reverse !== 'function') String.prototype.reverse = function() {
	var s = "";
	var i = this.length;
	while (i>0) {
		s += this.substring(i-1,i);
		i--;
	}
	return s;
}
//PROTOTYPE: String.toInt() -
if (typeof String.prototype.toInt !== 'function') String.prototype.toInt = function() {
	var a = new Array();
	for (var i = 0; i < this.length; i++) {
		a[i] = this.charCodeAt(i);
	}
	return a;
}
//PROTOTYPE: Array.intArrayToString() -
if (typeof Array.prototype.intArrayToString !== 'function') Array.prototype.intArrayToString = function() {
	var a = new String();
	for (var i = 0; i < this.length; i++) {
		if(typeof this[i] != "number") {
			throw new Error("Array must be all numbers");
		} else if (this[i] < 0) {
			throw new Error("Numbers must be 0 and up");
		}
		a += String.fromCharCode(this[i]);
	}
	return a;
}
//PROTOTYPE: Array.compareArrays(arr) -
if (typeof Array.prototype.compareArrays !== 'function') Array.prototype.compareArrays = function(arr) {
	if (this.length != arr.length) return false;
	for (var i = 0; i < arr.length; i++) {
		if (this[i].compareArrays) { //likely nested array
			if (!this[i].compareArrays(arr[i])) return false;
			else continue;
		}
		if (this[i] != arr[i]) return false;
	}
	return true;
}
//PROTOTYPE: Array.map(fnc) -
if (typeof Array.prototype.map !== 'function') Array.prototype.map = function(fnc) {
	var a = new Array(this.length);
	for (var i = 0; i < this.length; i++) {
		a[i] = fnc(this[i]);
	}
	return a;
}
//PROTOTYPE: Array.foldr(fnc,start) -
if (typeof Array.prototype.foldr !== 'function') Array.prototype.foldr = function(fnc,start) {
	var a = start;
	for (var i = this.length-1; i > -1; i--) {
		a = fnc(this[i],a);
	}
	return a;
}
//PROTOTYPE: Array.foldl(fnc,start) -
if (typeof Array.prototype.foldl !== 'function') Array.prototype.foldl = function(fnc,start) {
	var a = start;
	for (var i = 0; i < this.length; i++) {
		a = fnc(this[i],a);
	}
	return a;
}
//PROTOTYPE: Array.exists(x) -
if (typeof Array.prototype.exists !== 'function') Array.prototype.exists = function(x) {
	for (var i = 0; i < this.length; i++) {
		if (this[i] == x) return true;
	}
	return false;
}
//PROTOTYPE: Array.filter(fnc) -
if (typeof Array.prototype.filter !== 'function') Array.prototype.filter = function(fnc) {
	var a = new Array();
	for (var i = 0; i < this.length; i++) {
		if (fnc(this[i])) {
			a.push(this[i]);
		}
	}
	return a;
}
//PROTOTYPE: Array.random() -
if (typeof Array.prototype.random !== 'function') Array.prototype.random = function() {
	return this[Math.floor((Math.random()*this.length))];
}
//==== End. Sven Tofte prototypes ====================================================
/** End. Extensions by prototype ********************************************************/






/****************************************************************************************/
// CodeCavalier library:  The cc library is contained within the global cc object in
// order to provide a distinct naming space, and allow for library extensions.
/****************************************************************************************/
//OBJECT: cc - CodeCavalier library container object
if(window.cc === undefined) window.cc = {};
//PROPERTIES:
if(cc.name === undefined) cc.name        = 'CodeCavalier JavaScript Library 2 - Version: 2.0.10 (2009-10-27)';
if(cc.name === undefined) cc.version     = '2.0.10';
if(cc.name === undefined) cc.cssIncluded = false; //note: this flag specifies if a CSS has been loaded via cc.includeCSS, it gives no further detail when including multiple CSS files
if(cc.name === undefined) cc.jsIncluded  = false; //note: this flag specifies if a JS has been loaded via cc.includeJS, it gives no further detail when including multiple JS files

/****************************************************************************************/
// Header methods: file inclusion, page load events, style sheet manipulation, etc.

//METHOD: cc.includeCSS(css_file) - dynamically includes the specified CSS file (URL) - courtesy of Stoyan Stefanov, http://www.phpied.com/javascript-include-ready-onload/
cc.includeCSS = function(css_file) {
	var html_doc = document.getElementsByTagName('head')[0];
	css = document.createElement('link');
	css.setAttribute('rel', 'stylesheet');
	css.setAttribute('type', 'text/css');
	css.setAttribute('href', css_file);
	html_doc.appendChild(css);
	css.onreadystatechange = function() {
		if(css.readyState == 'complete') cc.cssIncluded = true;
	}
	css.onload = function() {
		cc.cssIncluded = true;
	}
}
//METHOD: cc.includeJS(file) - dynamically includes the specified JS file (URL) - courtesy of Stoyan Stefanov
cc.includeJS = function(file) {
	var html_doc = document.getElementsByTagName('head')[0];
	js = document.createElement('script');
	js.setAttribute('type', 'text/javascript');
	js.setAttribute('src', file);
	html_doc.appendChild(js);
	js.onreadystatechange = function() {
		if (js.readyState == 'complete') cc.jsIncluded = true;
	}
	js.onload = function() {
		cc.jsIncluded = true;
	}
}
//METHOD: cc.addLoadEvent(func) - appends the specified function(via reference) to the window.onload event - courtesy of Simon Willison, http://simonwillison.net/2004/May/26/addLoadEvent/
cc.addLoadEvent = function(func) {
	var oldonload = window.onload;
	if (typeof window.onload !== 'function') {
		window.onload = func;
	}
	else {
		window.onload = function() {
			if (oldonload) {
				oldonload();
			}
			func();
		}
	}
}
//METHOD: cc.fixPngs() - Fixes PNGs with alpha transparency in IE 5 & 6, in IMG tags and block backgrounds
//        This function provides similar functionality to Drew McLellan's SuperSleight - http://24ways.org/2007/supersleight-transparent-png-in-ie6
//  Note: for block elements with background images, the background-position property is overridden by the old-fashioned AlphaImageLoader() function in IE, which only supports scaling the image to the size of the element, or resizing the element to the size of the image - http://msdn.microsoft.com/en-us/library/ms532920(VS.85).aspx
cc.fixPngs = function() {
	var ver = navigator.appVersion.split('MSIE');
	ver = parseFloat(ver[1]);
	if (ver >= 5.5 && ver < 7 && document.body.filters)
	{//IE version is 5.5-6.x and filters object exists in DOM
		var pattern = new RegExp("([a-zA-Z0-9])+.png",'i');
		//Scan all block element backgrounds
		var scanElm = document.getElementsByTagName('*');
		for (var i = 0; i < scanElm.length; i++) {
			if(scanElm[i].style && scanElm[i].style.backgroundImage && pattern.test(scanElm[i].style.backgroundImage) )
			{//this element has an explicit .png background
				//alert('BACKGROUND-'+i+':'+scanElm[i].nodeName+':'+scanElm[i].className+':'+scanElm[i].style.backgroundImage+'\n'+(pattern.test(scanElm[i].style.backgroundImage) ? "IS a PNG" : "Nope")+'\n'+scanElm[i].style.filter+'\n'+scanElm[i].style.backgroundImage.replace("url(",'').replace(")",''));
				scanElm[i].style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+scanElm[i].style.backgroundImage.replace("url(",'').replace(")",'')+"',sizingMethod='crop')";
				scanElm[i].style.backgroundImage = 'none';
			}
		}
		//Scan backgrounds in all style sheets
		//var o = '';
		for(var i = 0; i < document.styleSheets.length; i++) {
			//o = o+'STYLE-'+i+'\n';
			for(var r = 0; r < document.styleSheets[i].rules.length; r++) {
				if(document.styleSheets[i].rules[r].style.backgroundImage && pattern.test(document.styleSheets[i].rules[r].style.backgroundImage) ) {
					//o = o+'  Rule-'+r+':'+document.styleSheets[i].rules[r].selectorText+'\n'+'    backgroundImage:'+document.styleSheets[i].rules[r].style.backgroundImage+'\n';
					document.styleSheets[i].rules[r].style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+document.styleSheets[i].rules[r].style.backgroundImage.replace("url(",'').replace(")",'')+"',sizingMethod='crop')";
					document.styleSheets[i].rules[r].style.backgroundImage = 'none';
				}
			}
		}
		//alert(o);
		//Scan all IMG tags
		for(var i = 0; i < document.images.length; i++)
		{//Loop through all images
			var img = document.images[i];
			var iSrc = img.src;
			if (iSrc.substring(iSrc.length-3, iSrc.length).toUpperCase() == 'PNG')
			{//this is a .png image
				var newOuterHTML = '<span '
				                 + (img.id ? "id='"+img.id+"' " : '')
				                 + (img.name ? "name='"+img.name+"' " : '')
				                 + (img.className ? "class='"+img.className+"' " : '')
				                 + (img.title ? "title='"+img.title+"' " : (img.alt ? "title='"+img.alt+"' " : ''))
				                 + ' style="display:inline-block;'
				                 + 'width:'+img.width+'px;'
				                 + 'height:'+img.height+'px;'
				                 + (img.align.toUpperCase()=='LEFT' ? 'float:left;' : '')
				                 + (img.align.toUpperCase()=='RIGHT' ? 'float:right;' : '')
				                 + (img.parentElement.href ? 'cursor:hand;' : '')
				                 + "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+img.src+"',sizingMethod='scale');"
				                 + '"></span>';
				img.outerHTML = newOuterHTML;
				i = i-1;//decrement the image count because we've removed one img element from the DOM
			}
		}
	}
}

/****************************************************************************************/
//MEMBER OBJECT: BrowserDetect by Peter-Paul Koch - http://www.quirksmode.org/js/detect.html
//               last update: 2009-07-08 (This code needs to be updated periodically)
//  Browser name: cc.BrowserDetect.browser
//  Browser version: cc.BrowserDetect.version
//  OS name: cc.BrowserDetect.OS
cc.BrowserDetect = {
	init: function() {
		this.browser = this.searchString(this.dataBrowser) || "An unknown browser";
		this.version = this.searchVersion(navigator.userAgent)
			|| this.searchVersion(navigator.appVersion)
			|| "an unknown version";
		this.OS = this.searchString(this.dataOS) || "an unknown OS";
	},
	searchString: function(data) {
		for (var i=0;i<data.length;i++)	{
			var dataString = data[i].string;
			var dataProp = data[i].prop;
			this.versionSearchString = data[i].versionSearch || data[i].identity;
			if (dataString) {
				if (dataString.indexOf(data[i].subString) != -1)
					return data[i].identity;
			}
			else if (dataProp)
				return data[i].identity;
		}
	},
	searchVersion: function(dataString) {
		var index = dataString.indexOf(this.versionSearchString);
		if (index == -1) return;
		return parseFloat(dataString.substring(index+this.versionSearchString.length+1));
	},
	dataBrowser: [
		{
			string: navigator.userAgent,
			subString: "Chrome",
			identity: "Chrome"
		},
		{ 	string: navigator.userAgent,
			subString: "OmniWeb",
			versionSearch: "OmniWeb/",
			identity: "OmniWeb"
		},
		{
			string: navigator.vendor,
			subString: "Apple",
			identity: "Safari",
			versionSearch: "Version"
		},
		{
			prop: window.opera,
			identity: "Opera"
		},
		{
			string: navigator.vendor,
			subString: "iCab",
			identity: "iCab"
		},
		{
			string: navigator.vendor,
			subString: "KDE",
			identity: "Konqueror"
		},
		{
			string: navigator.userAgent,
			subString: "Firefox",
			identity: "Firefox"
		},
		{
			string: navigator.vendor,
			subString: "Camino",
			identity: "Camino"
		},
		{		// for newer Netscapes (6+)
			string: navigator.userAgent,
			subString: "Netscape",
			identity: "Netscape"
		},
		{
			string: navigator.userAgent,
			subString: "MSIE",
			identity: "Explorer",
			versionSearch: "MSIE"
		},
		{
			string: navigator.userAgent,
			subString: "Gecko",
			identity: "Mozilla",
			versionSearch: "rv"
		},
		{ 		// for older Netscapes (4-)
			string: navigator.userAgent,
			subString: "Mozilla",
			identity: "Netscape",
			versionSearch: "Mozilla"
		}
	],
	dataOS : [
		{
			string: navigator.platform,
			subString: "Win",
			identity: "Windows"
		},
		{
			string: navigator.platform,
			subString: "Mac",
			identity: "Mac"
		},
		{
			   string: navigator.userAgent,
			   subString: "iPhone",
			   identity: "iPhone/iPod"
	    },
		{
			string: navigator.platform,
			subString: "Linux",
			identity: "Linux"
		}
	]
};

/****************************************************************************************/
// Cookie methods: for cookie manipulation

//PROPERTY: Stores the original value of document.cookie before any other script changes (given that cc2.js is included at the top)
cc.originalDocumentCookieValue = document.cookie;

//METHOD: cc.setCookie(cookieName,val,days,path) - sets a cookie in the browser for the current domain
// usage: setCookie('cookie_name','cookie value',{number of days before expiration},{optional path});
//      : set days = 0 for a browser session cookie
//      : set days = -1 to delete a cookie (or use the handy function below)
cc.setCookie = function(cookieName,val,days,path) {
	//alert('setCookie('+cookieName+','+val+','+days+')');
	var expires = '';
	if(days) {//a time limit, in days, has been provided
		var d = new Date();
		d.setTime(d.getTime()+(days*24*60*60*1000));
		expires = '; expires='+d.toGMTString();
	}
	if(path) {//a specific path has been provided
		path = encodeURIComponent(path);
	}
	else {//no path was provided
		path = '/';
	}
	document.cookie = cookieName+'='+encodeURIComponent(val)+expires+'; path='+path;
}
//METHOD: cc.getCookie(cookieName) - gets the value of the cookie with the specified name
cc.getCookie = function(cookieName) {
	//alert('getCookie('+cookieName+')');
	var searchName = cookieName+'=';
	var cookieArr = document.cookie.split(';');
	var c = false;
	for(var i=0;i<cookieArr.length;i++) {
		c = cookieArr[i];
		while (c.charAt(0)==' ')
			c = c.substring(1,c.length);
		if (c.indexOf(searchName) == 0)
			return decodeURIComponent(c.substring(searchName.length,c.length));
	}
	return null;
}
//METHOD: cc.getCookieByValue - gets the name of the cookie with the specified value, allows skipping one cookie
cc.getCookieByValue = function(cookieValue,skipName) {
	//alert('getCookieByValue('+cookieValue+')');
	var searchName = '='+cookieValue;
	var cookieArr = document.cookie.split(';');
	var c = false;
	for(var i=0;i<cookieArr.length;i++) {
		c = cookieArr[i];
		while (c.charAt(0)==' ')
			c = c.substring(1,c.length);
		p = c.indexOf(searchName);
		if (p > 0 && c.substring(0,p) != skipName)
			return c.substring(0,p);
	}
	return null;
}
//METHOD: cc.deleteCookie - removes the cookie with the specified name from the browser //TODO:this needs to be fixed.  it needs to scan the cookie string for any instance of the specified cookie name
cc.deleteCookie = function(cookieName) {
	document.cookie = cookieName + "=; expires=Thu, 01-Jan-70 00:00:01 GMT;";
	if(getCookie(cookieName))
		document.cookie = cookieName + "=; expires=Thu, 01-Jan-70 00:00:01 GMT; path=/";
	if(getCookie(cookieName))
		document.cookie = cookieName + "=; expires=Thu, 01-Jan-70 00:00:01 GMT; domain=" + document.domain;
	if(getCookie(cookieName))
		document.cookie = cookieName + "=; expires=Thu, 01-Jan-70 00:00:01 GMT; path=/; domain=" + document.domain;
	return getCookie(cookieName);
}
//METHOD: cc.deleteAllCookies - removes all cookies
cc.deleteAllCookies = function() {
	// Get cookie string and separate into individual cookie phrases:
	var cookie_string = "" + document.cookie;
	var cookie_array = cookie_string.split("; ");

	// Try to delete each cookie:
	for(var i = 0; i < cookie_array.length; ++i)
	{
		var single_cookie = cookie_array[i].split("=");
		if(single_cookie.length != 2)
			continue;
		var cookieName = unescape(single_cookie[0]);
		deleteCookie(cookieName);
	}
}
//METHOD: cc.countCookies - returns the number of valid cookies in the cookie string
cc.countCookies = function() {
	//Get cookie string and separate into individual cookie phrases
	var cookieString = String(document.cookie);
	var cookieArray = cookieString.split('; ');
	var cookieCount = 0;

	//Parse and count each cookie
	for(var i=0; i < cookieArray.length; i++)
	{
		if(cookieArray[i].indexOf('='))
		{//this cookie string has an = in it
			var cookieName = decodeURIComponent(cookieArray[i].substring(0,cookieArray[i].indexOf('=')).replace(/\+/g,' ').trim());
		}
		else
		{//this cookie string doesn't have a = delimiter, set value to null
			var cookieName = decodeURIComponent(cookieArray[i].replace(/\+/g,' ').trim());
		}
		if(cookieName) cookieCount++;
	}

	return cookieCount;
}

/****************************************************************************************/
// DOM methods: for easier DOM manipulation

//METHOD: cc.clear(elm) - empties the specified DOM element by removing all its child nodes
cc.clear = function(elm) {
	while(elm.childNodes.length)
		elm.removeChild(elm.childNodes[0]);
	return elm;
}
//METHOD: cc.getParentWithId(elm,id_in) - returns a reference to the parent element with passed id
cc.getParentWithId = function(elm,id_in) {
	return (elm.id==id_in ? elm : (elm.nodeName=='HTML' ? null : (this.getParentWithId(elm.parentNode,id_in))));
}
//METHOD: cc.getParentWithClass(elm,class_name) - returns a reference to the parent element with passed className
cc.getParentWithClass = function(elm,class_name) {
	return (elm.className==class_name ? elm : (elm.nodeName=='HTML' ? false : (this.getParentWithClass(elm.parentNode,class_name))));
}
//METHOD: cc.getParentNode(elm,node_name) - returns a reference to the parent element matching a particular node
cc.getParentNode = function(elm,node_name) {
	return (elm.nodeName==node_name ? elm : (elm.nodeName=='HTML' ? false : (this.getParentNode(elm.parentNode,node_name))));
}
//METHOD: cc.getChildWithClass(elm,class_name) - returns a reference to the first child element with passed class_name
cc.getChildWithClass = function(elm,class_name) {
	for(var i=0;i<elm.childNodes.length;i++) {
		var classArr = (elm.childNodes[i].className ? elm.childNodes[i].className.split(' ') : Array());
		for(var j=0;j<classArr.length;j++)
			if(classArr[j] == class_name)
				return elm.childNodes[i];
	}
	var childResult = false;
	for(i=0;i<elm.childNodes.length;i++) {
		childResult = this.getChildWithClass(elm.childNodes[i],class_name);
		if(childResult) return childResult;
	}
	return false;
}
//METHOD: cc.getChildNode(elm,node_name) - returns a reference to the first child element with passed node_name
cc.getChildNode = function(elm,node_name) {
	for(var i=0;i<elm.childNodes.length;i++)
		if(elm.childNodes[i].nodeName == node_name)
			return elm.childNodes[i];
	var childResult = false;
	for(i=0;i<elm.childNodes.length;i++)
		if(childResult = this.getChildNode(elm.childNodes[i],node_name)) return childResult;
	return false;
}
//METHOD: cc.getType(x) - tries to return the type of a variable or object
// by David Flanagan, Copyright © 2006 O'Reilly Media, Inc., used with permission
//function getType(x) {
cc.getType = function(x) {
    // If x is null, return "null"
    if (x == null) return "null";

    // Next try the typeof operator
    var t = typeof x;
    // If the result is not vague, return it
    if (t != "object")  return t;

    // Otherwise, x is an object. Use the default toString( ) method to
    // get the class value of the object.
    var c = Object.prototype.toString.apply(x);  // Returns "[object class]"
    c = c.substring(8, c.length-1);              // Strip off "[object" and "]"

    // If the class is not a vague one, return it.
    if (c != "Object") return c;

    // If we get here, c is "Object".  Check to see if
    // the value x is really just a generic object.
    if (x.constructor == Object) return c;  // Okay the type really is "Object"
    // For user-defined classes, look for a string-valued property named
    // classname, that is inherited from the object's prototype
    if ("classname" in x.constructor.prototype &&  // inherits classname
        typeof x.constructor.prototype.classname == "string") // its a string
        return x.constructor.prototype.classname;

    // If we really can't figure it out, say so.
    return "<unknown type>";
}
//METHOD: cc.pad0(val,newlength) - Zero padding (types other than String or Number)
cc.pad0 = function(val,newlength) {
	if(isFinite(val))
		return String(val).pad0(newlength);
	else
		return val;
}
//METHOD: cc.setFormControlValue(name,val,form) - Easy form element value setter for all types of form controls:
//                                                text,hidden,password,button,submit,reset,image: sets the value attribute
//                                                checkbox: finds a checkbox with matching value and checks that box; if val===false, all checkboxes in the group are unchecked
//                                                radio: finds a radio button with matching value and selects it; this should automagically deselect all other radio buttons with the same name
//                                                select (w/o multiple attribute): finds an option in the select list with matching value and selects it, unselecting all others
//                                                select (with multiple attribute): finds an option in the select list with matching value and selects it, in addition to other selections; if val===false, all options are deselected
//                                                file: sets the value attribute, which only sets the default file name, not the actual file data
//                                                textarea: sets the text attribute??
//  name     The name of the form control to update. TODO: make it support ID's and object references as well
//  val      Any value
//  form     A reference to a form; can be omitted, defaults to 1st form in DOM
//  returns  A reference to the form control that was updated, an array if more than one form controls were updated, or false if no control was found
cc.setFormControlValue = function(name,val,form) {
	var elms = false;
	if(name) {
		if(((!form) || (!form.nodeName) || (form.nodeName != 'FORM')) && document.forms[0]) form = document.forms[0]; //if not passed in, use the first form element in DOM
		if(form) {
			//this is really a valid form
			for(var i=0;i<form.elements.length;i++) {
				if(form.elements[i].name == name) {
					if(!elms) elms = [];
					elms[elms.length] = form.elements[i];
				}
			}
			if(elms && elms.length > 0) {
				//found the form control
				var radioChecked = false; //remember which radio button was checked
				for(var i=0;i<elms.length;i++) {
					//alert("set: "+elms[i].type+"("+elms[i].name+") = "+val);
					if(elms[i].type == 'text' || elms[i].type == 'hidden' || elms[i].type == 'password' || elms[i].type == 'button' || elms[i].type == 'submit' || elms[i].type == 'reset' || elms[i].type == 'image' || elms[i].type == 'file') {
						//just set the value attribute
						elms[i].value = val;
					}
					else if(elms[i].type == 'radio') {
						if(elms[i].value == val) {
							//select this radio button
							elms[i].checked = true;
							radioChecked = elms[i];
						}
						else {
							//deselect this radio button
							elms[i].checked = false;
						}
					}
					else if(elms[i].type == 'checkbox') {
						//TODO:
					}
					else if(elms[i].type == 'select') {
						//TODO:
					}
					else if(elms[i].type == 'textarea') {
						//TODO:
					}
				}
				//if elms contains one element, or is a radio group, then change the return type to a reference instead of an array
				if(elms.length == 1)
					elms = elms[0];
				else if(radioChecked)
					elms = radioChecked;
			}
			else {
				//could not find any form controls matching the name
				elms = false;
			}
		}
	}
	return elms;
}




/****************************************************************************************/
// Window methods: for manipulation of browser windows

//METHOD: cc.absPos(elm) - returns the absolute {x,y} coordinates (px) of an element
cc.absPos = function(elm) {
	return ( elm.offsetParent == null
		? {
				x:elm.offsetLeft,
				y:elm.offsetTop
			}
		: this.absPos(elm.offsetParent)
	);
}
//METHOD: cc.absPosX(elm) - returns the absolute x coordinate (px) of an element - inspired by Mike Hall, getPageOffsetLeft, http://www.brainjar.com/dhtml/menubar/default3.asp
cc.absPosX = function(elm) {
	return (elm.offsetParent == null ? elm.offsetLeft : elm.offsetLeft + this.absPosX(elm.offsetParent));
}
//METHOD: cc.absPosY(elm) - returns the absolute y coordinate (px) of an element - inspired by Mike Hall, getPageOffsetTop, http://www.brainjar.com/dhtml/menubar/default3.asp
cc.absPosY = function(elm) {
	return (elm.offsetParent == null ? elm.offsetTop : elm.offsetTop + this.absPosY(elm.offsetParent));
}
//METHOD: cc.windowSize() - returns the dimensions of the browser window (works better when document body width/height are set to 100%)
cc.windowSize = function() {
	return {
		x:document.body.clientWidth,
		y:document.body.clientHeight
	};
}
//METHOD: cc.pageSize() - returns the dimensions of the whole web page (including scrolled portions)
cc.pageSize = function() {
	var html = document.getElementsByTagName('HTML');
	return {
		x:(html[0] ? html[0].clientWidth : null),
		y:(html[0] ? html[0].clientHeight : null)
	};
}

/****************************************************************************************/
// SFX methods: for creating cross-browser special effects

//MEMBER OBJECT: cc.ds - Drop shadow object
cc.ds = {};
//PROPERTIES:
cc.ds.simpleShadowClass = 'dropShadow';
cc.ds.fadingShadowClass = 'fadingDropShadow';
cc.ds.simpleColor = 'black';
cc.ds.fadingColor = '44'; //Hex number between 00 and FF
// Warning: This drop shadow effect does not work well when text is wrapped, or when pages are zoomed.

//METHOD: cc.ds.scanForElementsToDropShadow() - Scans DOM for elements that want drop shadows on text
//  Inspired by: Stan Slaughter - http://stansight.com/WordPress/2007/10/28/text-drop-shadows/
//               with significant mods
cc.ds.scanForElementsToDropShadow = function() {
	// Use these class names to specify elements to drop shadow, and which effect to use
	var node = document;
	var tag = '*';

	// Build regular expressions that will search for drop shadow classes
	var patternSimple = new RegExp("(^|\\s)"+cc.ds.simpleShadowClass+"(\\s|$)");
	var patternFading = new RegExp("(^|\\s)"+cc.ds.fadingShadowClass+"(\\s|$)");

	// Scan through all tag elements in the document
	var scanElm = node.getElementsByTagName(tag);
	for (i = 0; i < scanElm.length; i++) {

		if (patternSimple.test(scanElm[i].className) )
		{//element wants a fading shadow
			//alert(scanElm[i].nodeName);
			// Create Simple Shadow Child for this element
			cc.ds.createSimpleShadow(scanElm[i]);
		}
		else if (patternFading.test(scanElm[i].className) )
		{//element wants a simple drop shadow
			// Get the value from the element
			var text_value = scanElm[i].innerHTML;

			// Create Fading Shadow Children for this element
			cc.ds.createFadingShadow(scanElm[i],text_value);
		}
	} // End for loop
}
//METHOD: ds.createFadingShadow(shadow_element,shadow_value) - Creates child DOM elements for the fading drop shadow effect
//  By: Stan Slaughter - http://stansight.com/WordPress/2007/10/28/text-drop-shadows/
//      with slight mod (TODO:fix the half-pixel problem)
cc.ds.createFadingShadow = function(shadow_element,shadow_value) {
	// Starting relative offset for child DIVs
	var top_pos = .5;
	var left_pos = .5;

	// Assign starting color (in Hex notation) for the Red, Green, and Blue
	// Components (when they all have the same value you will alwys get a gray color).
	// For lighter shadows start with a "lighter" color of 66, 77, 88 99, aa, bb, etc..
	var cRed = parseInt(this.fadingColor,'16');
	var cGreen = parseInt(this.fadingColor,'16');
	var cBlue = parseInt(this.fadingColor,'16');

	// Set the max number of shadow elements to create.
	// This should never be set larger than the Z-Index value of dropshadow class
	var max_shadows = 10;

	// Calculate color increament based on range of gray colors (from this.fadingColor to
	// the lighest gray color of #fefefe) and max number of shadows you want
	var color_inc =  parseInt(( parseInt('fe','16') - parseInt(this.fadingColor,'16') ) / max_shadows,'10');

	for (j = 1; j <= max_shadows; j++) {

		// Build full color Hex string from it's individual RGB values
		var full_color_value = cRed.toString(16) + cGreen.toString(16) + cBlue.toString(16);

		// Create a Shadow DIV
		var shadow_div = document.createElement('div');

		//  Add the shadow_value to Shadow DIV
		shadow_div.innerHTML = shadow_value;

		// Style Shadow DIV
		shadow_div.style.width=shadow_element.offsetWidth + "px";
		shadow_div.style.color = '#' + full_color_value;
		shadow_div.style.borderColor = '#' + full_color_value;
		shadow_div.style.display = "block";
		shadow_div.style.position = "absolute";
		shadow_div.style.top = top_pos + "px";
		shadow_div.style.left = left_pos + "px";
		shadow_div.style.zIndex = (-1) * j;

		// Apppend Shadow DIV to shadow element
		shadow_element.appendChild(shadow_div);

		// Increment positons and shadows individual RGB color values
		top_pos += .5;
		left_pos += .5;
		cRed += color_inc;
		cGreen += color_inc;
		cBlue += color_inc;
	}
}
//METHOD: cc.ds.createSimpleShadow(sourceElm,textVal) - creates drop-shadow text
//    Set attribute class="dropShadow" in the desired element
//  optional:
//    Set attribute dsWidth="{number}" to specify a custom pixel width (and by default, height)
//    Set attribute dsHeight="{number}" to specify a custom pixel height
//    Set attribute dsColor="{CSS color value}" to specify a custom color
//    Set attribute dsOpacity="{CSS3 opacity value}" to specify a custom opacity (auto-converts to IE compatible value)
//    Set attribute dsFirefoxCorrect="{number}" to specify the number of pixels to correct the height (Firefox-only)
//    Set attribute dsSafariCorrect="{number}" to specify the number of pixels to correct the height (Safari-only)
//    Set attribute dsBrowserAllow="{comma-separated list of browser names with optional space and version number}" drop shadow effect will only appear on listed browsers
//    Set attribute dsBrowserDisable="{comma-separated list of browser names with optional space and version number}" drop shadow effect will not appear on listed browsers
//  notes:
//    I researched having the optional values configurable as custom style properties, but it proved to be too difficult to read custom properties from style sheets because each browser's DOM has its own pre-defined list of properties in the style obect. (see: http://www.quirksmode.org/dom/w3c_css.html)
//    For some reason, Firefox pushes the text in the child element vertically, sometimes resulting in incorrect drop shadow height.  I haven't figured out why this happens, so it currently requires a manual fix.  See the dsFirefoxCorrect attribute above.
cc.ds.createSimpleShadow = function(sourceElm,textVal)
{
	if(sourceElm && sourceElm.style)
	{//sourceElm is a valid element
		var browserEnabled = true;
		//Look for dsBrowserAllow
		var dsBrowserAllow = sourceElm.getAttribute('dsBrowserAllow');
		if(dsBrowserAllow)
		{//Need to verify if this browser is disabled
			browserEnabled = false;
			var thisBrowser = cc.BrowserDetect.browser+' '+cc.BrowserDetect.version;
			var browsers = dsBrowserAllow.split(',');
			for(var i=0; i < browsers.length; i++) {
				var searchBrowser = browsers[i].trim();
				var pattern = new RegExp(searchBrowser);
				//alert("dsBrowserAllow:"+dsBrowserAllow+'\n'+"thisBrowser:"+thisBrowser+'\n'+"searchBrowser:"+searchBrowser+'\n'+"Pattern match:"+(pattern.test(thisBrowser) ? 'TRUE' : 'FALSE'));
				if(pattern.test(thisBrowser))
				{//the browser listed in dsBrowserAllow matches this browser's name
					browserEnabled = true;
					break;
				}
			}
		}
		//Look for dsBrowserDisable
		var dsBrowserDisable = sourceElm.getAttribute('dsBrowserDisable');
		if(dsBrowserDisable)
		{//Need to verify if this browser is disabled
			var thisBrowser = cc.BrowserDetect.browser+' '+cc.BrowserDetect.version;
			var browsers = dsBrowserDisable.split(',');
			for(var i=0; i < browsers.length; i++) {
				var searchBrowser = browsers[i].trim();
				var pattern = new RegExp(searchBrowser);
				//alert("dsBrowserDisable:"+dsBrowserDisable+'\n'+"thisBrowser:"+thisBrowser+'\n'+"searchBrowser:"+searchBrowser+'\n'+"Pattern match:"+(pattern.test(thisBrowser) ? 'TRUE' : 'FALSE'));
				if(pattern.test(thisBrowser))
				{//the browser listed in dsBrowserDisable matches this browser's name
					browserEnabled = false;
					break;
				}
			}
		}
		//If this browser hasn't been explicitly disabled, do the drop shadow
		if( browserEnabled )
		{
			//Verify style properties of the source element
			sourceElm.style.position = 'relative';
			sourceElm.style.zIndex = 1;

			//Create the shadow element in the DOM as a child of the source element
			var shadowElm = document.createElement('DIV');
			shadowElm.innerHTML = sourceElm.innerHTML;
			shadowElm.className = this.simpleShadowClass + '_Shadow';
			shadowElm.style.width = sourceElm.offsetWidth + 'px';
			shadowElm.style.display = 'block';
			shadowElm.style.position = 'absolute';
			shadowElm.style.zIndex = -100;

			//Check custom attributes of the source element, or use defaults
			var dsColor = sourceElm.getAttribute('dsColor');
			shadowElm.style.color = (dsColor === null ? this.simpleColor : dsColor);
			var dsWidth = sourceElm.getAttribute('dsWidth');
			shadowElm.style.left = (dsWidth === null ? 1 : dsWidth) + 'px';
			var dsHeight = sourceElm.getAttribute('dsHeight');
			var dsBrowserCorrect = 0;
			if(cc.BrowserDetect.browser == 'Firefox' && sourceElm.getAttribute('dsFirefoxCorrect'))
				dsBrowserCorrect = parseInt(sourceElm.getAttribute('dsFirefoxCorrect'));
			if(cc.BrowserDetect.browser == 'Safari' && sourceElm.getAttribute('dsSafariCorrect'))
				dsBrowserCorrect = parseInt(sourceElm.getAttribute('dsSafariCorrect'));
			shadowElm.style.top = ((dsHeight === null ? (dsWidth === null ? 1 : dsWidth) : dsHeight) + dsBrowserCorrect) + 'px';
			//TODO:custom opacity

			sourceElm.appendChild(shadowElm);
		}
	}
}

// End of cc library object.
/****************************************************************************************/




/****************************************************************************************/
// CodeCavalier library auto-loaders:  Some of these commands are run immediately, and
// others are automatically run upon page load.  They are considered default features of
// the library.
/****************************************************************************************/
//Initialize the browser detection object
cc.BrowserDetect.init();
//Fix the transparent PNGs on window.onload
if(window.attachEvent) //this function is native only to IE 5 & 6
	window.attachEvent("onload", cc.fixPngs);
//Scan for drop shadow text
cc.addLoadEvent( cc.ds.scanForElementsToDropShadow );
//Alert the browser version (if this works, then none of the other auto-loaders crashed)
//cc.addLoadEvent( function() {alert(cc.BrowserDetect.browser+' '+cc.BrowserDetect.version);} );
/****************************************************************************************/

