

/**************************************************************
 BEGIN component/global_search_bar                                           */
//<script>

var SearchBar;
window.addEvent('domready', function () {
	SearchBar = search_bar;
	SearchBar.init();
})


function do_event_search() {
	var cat_id = $$('#search_bar #search_cat')[0].get('value');
	var search_term = $$('#search_bar #search_term')[0].get('value');
	var date_range = $$('#search_bar #search_range')[0].get('value');
	var type = $$('#search_bar #search_type_switch')[0].get('html');
	goto(URL+'index.php?page=search&t='+type+'&c='+cat_id+'&q='+search_term+'&d='+date_range);
	return false;
}


var search_bar = {

	init : function () {
		this.tab = $('search_tab');
		this.bar = $('search_bar');
		this.options_container = $('search_options');
		this.state = 'closed';
		this.options_state = 'closed';
		this.options_display = $('search_type_switch');
		this.term = $('search_term');
		this.layout = $('search_layout');
		
		$('search_btn').addEvent('click', function() {
			do_event_search();
			return false;
		})
		$('search_tab').addEvent('click', function () {
			SearchBar.toggle_search();	
		});
		this.options_display.addEvent('click', this.toggle_options);
	
		this.search_target = $('search_start_opt').get('html');
		this.options_display.set('html', this.search_target);
	
		$('search_optn_news').addEvent('click', this.switch_search_target);
		$('search_optn_news').set('rel', 'news');
		if (this.search_target == 'news') {
			$('search_optn_news').addClass('orange').removeClass('white');
			this.search_target_link = $('search_optn_news');
		}
		$('search_optn_events').addEvent('click', this.switch_search_target);
		$('search_optn_events').set('rel', 'events');
		if (this.search_target == 'events') {
			$('search_optn_events').addClass('orange').removeClass('white');
			this.search_target_link = $('search_optn_events');
		}
		
		$('search_optn_all').addEvent('click', this.switch_search_target);
		$('search_optn_all').set('rel', 'all');
		if (this.search_target == 'all') {
			$('search_optn_all').addClass('orange').removeClass('white');
			this.search_target_link = $('search_optn_all');
		}
		
		this.term.addEvent('click', this.toggle_options);
		this.term.addEvent('keydown', function (e) {
			if(SearchBar.options_container.getSize().y > 0) {
				SearchBar.options_container.tween('height', '0px').hide();
				SearchBar.options_state = 'closed';
			}
			
			if (e.event.keyCode == 13) {
				do_event_search();
			}
		});
		
	},
	term_focus : function () {
		
		SearchBar.layout.show();
		SearchBar.term.focus();
	},
	toggle_search : function (force) {
		console.log('here:'+SearchBar.state);
		if (SearchBar.state == 'closed' || force == 'open') {
			SearchBar.layout.hide();
			console.log('tweening:')
			console.log(SearchBar.bar)
			SearchBar.bar.get('tween', {property: 'height', duration: 'short'});
			SearchBar.bar.get('tween').addEvent('complete', SearchBar.term_focus).start('48px');
			SearchBar.state = 'open';
			setTimeout('SearchBar.set_auto_close()', 1000);
			if (SearchBar.layout.getPosition().y < 0) {
				SearchBar.layout.setStyle('top', (SearchBar.layout.getPosition().y * -1) +'px');
			}

		} else if (SearchBar.state == 'open' || force == 'closed') {
			SearchBar.bar.tween('height', '0px');
			SearchBar.state = 'closed';
			SearchBar.layout.hide();
			SearchBar.toggle_options(true);
			$('header').removeEvent('click', SearchBar.do_auto_close);
			$('content').removeEvent('click', SearchBar.do_auto_close);
		}
	},
	

	reload_cats : function () {
		jsonreq('global_search_bar', 'action=search_cats&type='+this.search_target, 'SearchBar.reload_cats_callback');
	},
	
	

	reload_cats_callback : function (response) {
		$('search_cat').options.length = 0;
		var v = 0;

		var nOpt = new Option('select category', '0');
		$('search_cat').options[v] = nOpt;
		v++;
		
		var nOpt = new Option('any', '0');
		$('search_cat').options[v] = nOpt;
		v++;
		
		for (var g=0; g<response.length; g++) {
			var nOpt = new Option(response[g].name, response[g].id);
			$('search_cat').options[v] = nOpt;
			v++;
		}
		
		
		
	},
	
	
	
	
	
	toggle_options : function (force) {	
		if (typeof force == 'undefined' || typeof force != 'boolean')
			force = false;

		if (SearchBar.options_state == 'closed' && !force) {
			SearchBar.options_container.show().tween('height', '74px');
			SearchBar.options_state = 'open';
		} else {
			SearchBar.options_container.tween('height', '0px').hide();
			SearchBar.options_state = 'closed';
		}
	
	}, 
	switch_search_target : function () {	
		SearchBar.options_display.set('html', this.get('rel'));
		SearchBar.search_target_link.removeClass('orange').addClass('white');
		SearchBar.search_target_link = this;
		this.addClass('orange').removeClass('white');
		SearchBar.search_target = this.get('rel');
		SearchBar.term.focus();
		SearchBar.reload_cats();
		SearchBar.toggle_options();
	},
	
	
	set_auto_close : function () {
		console.log('setting autoclose');
		$('header').addEvent('click', SearchBar.do_auto_close);
		$('content').addEvent('click', SearchBar.do_auto_close);
	},
	
	do_auto_close : function () {
		console.log('fired  autoclose: '+SearchBar.state);
		if (SearchBar.state == 'open')
			SearchBar.toggle_search();
		$('header').removeEvent('click', SearchBar.do_auto_close);
		$('content').removeEvent('click', SearchBar.do_auto_close);
	}


	

}


/* END component/global_search_bar
*************************************************************/

/**************************************************************
 BEGIN site/base                                           */
//<script>
var jsoRegisterTemplate = new Class({
	initialize: function () {
		this.registry = new Hash();
	},
	registerComponent: function (name, reference) {
		var nr = new Hash();
		nr.name = name;
		nr.reference = reference;
		nr.uid = nr.uid;
		this.registry.include(nr.uid, nr);
	},
	dumpRegister: function () {
		console.log('++ JSO REGISTRY ++');
		$each(this.registry, function (v) {
			console.log('---------------- '+v.name+': '+v.reference.uid);
			console.log(v.reference);
			console.log('---------------- END '+v.name+': '+v.reference.uid);
			console.log(' ');
		}, this);
	}
});
var jsoRegister = false;
window.addEvent('domready', function () {
	jsoRegister = new jsoRegisterTemplate();
});





if (typeof console == 'undefined' || typeof console.log == 'undefined') { console = { log : function (text) { /* alert (text); */ return false; } } }
function rolldoc (resp) {
	if (resp.err)
		return show_error(resp.msg);
	document.location = document.location;
}

function nothing () {
	return;
}

function sprintf ( ) {
    // http://kevin.vanzonneveld.net
    // +   original by: Ash Searle (http://hexmen.com/blog/)
    // + namespaced by: Michael White (http://getsprink.com)
    // +    tweaked by: Jack
    // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +      input by: Paulo Freitas
    // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +      input by: Brett Zamir (http://brett-zamir.me)
    // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // *     example 1: sprintf("%01.2f", 123.1);
    // *     returns 1: 123.10
    // *     example 2: sprintf("[%10s]", 'monkey');
    // *     returns 2: '[    monkey]'
    // *     example 3: sprintf("[%'#10s]", 'monkey');
    // *     returns 3: '[####monkey]'

    var regex = /%%|%(\d+\$)?([-+\'#0 ]*)(\*\d+\$|\*|\d+)?(\.(\*\d+\$|\*|\d+))?([scboxXuidfegEG])/g;
    var a = arguments, i = 0, format = a[i++];

    // pad()
    var pad = function (str, len, chr, leftJustify) {
        if (!chr) {chr = ' ';}
        var padding = (str.length >= len) ? '' : Array(1 + len - str.length >>> 0).join(chr);
        return leftJustify ? str + padding : padding + str;
    };

    // justify()
    var justify = function (value, prefix, leftJustify, minWidth, zeroPad, customPadChar) {
        var diff = minWidth - value.length;
        if (diff > 0) {
            if (leftJustify || !zeroPad) {
                value = pad(value, minWidth, customPadChar, leftJustify);
            } else {
                value = value.slice(0, prefix.length) + pad('', diff, '0', true) + value.slice(prefix.length);
            }
        }
        return value;
    };

    // formatBaseX()
    var formatBaseX = function (value, base, prefix, leftJustify, minWidth, precision, zeroPad) {
        // Note: casts negative numbers to positive ones
        var number = value >>> 0;
        prefix = prefix && number && {'2': '0b', '8': '0', '16': '0x'}[base] || '';
        value = prefix + pad(number.toString(base), precision || 0, '0', false);
        return justify(value, prefix, leftJustify, minWidth, zeroPad);
    };

    // formatString()
    var formatString = function (value, leftJustify, minWidth, precision, zeroPad, customPadChar) {
        if (precision != null) {
            value = value.slice(0, precision);
        }
        return justify(value, '', leftJustify, minWidth, zeroPad, customPadChar);
    };

    // doFormat()
    var doFormat = function (substring, valueIndex, flags, minWidth, _, precision, type) {
        var number;
        var prefix;
        var method;
        var textTransform;
        var value;

        if (substring == '%%') {return '%';}

        // parse flags
        var leftJustify = false, positivePrefix = '', zeroPad = false, prefixBaseX = false, customPadChar = ' ';
        var flagsl = flags.length;
        for (var j = 0; flags && j < flagsl; j++) {
            switch (flags.charAt(j)) {
                case ' ': positivePrefix = ' '; break;
                case '+': positivePrefix = '+'; break;
                case '-': leftJustify = true; break;
                case "'": customPadChar = flags.charAt(j+1); break;
                case '0': zeroPad = true; break;
                case '#': prefixBaseX = true; break;
            }
        }

        // parameters may be null, undefined, empty-string or real valued
        // we want to ignore null, undefined and empty-string values
        if (!minWidth) {
            minWidth = 0;
        } else if (minWidth == '*') {
            minWidth = +a[i++];
        } else if (minWidth.charAt(0) == '*') {
            minWidth = +a[minWidth.slice(1, -1)];
        } else {
            minWidth = +minWidth;
        }

        // Note: undocumented perl feature:
        if (minWidth < 0) {
            minWidth = -minWidth;
            leftJustify = true;
        }

        if (!isFinite(minWidth)) {
            throw new Error('sprintf: (minimum-)width must be finite');
        }

        if (!precision) {
            precision = 'fFeE'.indexOf(type) > -1 ? 6 : (type == 'd') ? 0 : undefined;
        } else if (precision == '*') {
            precision = +a[i++];
        } else if (precision.charAt(0) == '*') {
            precision = +a[precision.slice(1, -1)];
        } else {
            precision = +precision;
        }

        // grab value using valueIndex if required?
        value = valueIndex ? a[valueIndex.slice(0, -1)] : a[i++];

        switch (type) {
            case 's': return formatString(String(value), leftJustify, minWidth, precision, zeroPad, customPadChar);
            case 'c': return formatString(String.fromCharCode(+value), leftJustify, minWidth, precision, zeroPad);
            case 'b': return formatBaseX(value, 2, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
            case 'o': return formatBaseX(value, 8, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
            case 'x': return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
            case 'X': return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad).toUpperCase();
            case 'u': return formatBaseX(value, 10, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
            case 'i':
            case 'd':
                number = parseInt(+value, 10);
                prefix = number < 0 ? '-' : positivePrefix;
                value = prefix + pad(String(Math.abs(number)), precision, '0', false);
                return justify(value, prefix, leftJustify, minWidth, zeroPad);
            case 'e':
            case 'E':
            case 'f':
            case 'F':
            case 'g':
            case 'G':
                number = +value;
                prefix = number < 0 ? '-' : positivePrefix;
                method = ['toExponential', 'toFixed', 'toPrecision']['efg'.indexOf(type.toLowerCase())];
                textTransform = ['toString', 'toUpperCase']['eEfFgG'.indexOf(type) % 2];
                value = prefix + Math.abs(number)[method](precision);
                return justify(value, prefix, leftJustify, minWidth, zeroPad)[textTransform]();
            default: return substring;
        }
    };

    return format.replace(regex, doFormat);
}


function getNamedElements(parent) {
	var eles = $(parent).getElements('*');
	var found_eles = [];
	$each(eles, function (e) {
		if (typeof e.get == 'function' && e.get('name') != null && e.get('name').length > 0)
			found_eles.include(e);
	});
	return found_eles;
}
function getElementNamed(parent, name) {
	var eles = $(parent).getElements('*');
	var found_ele = false;
	$each(eles, function (e) {
		if (typeof e.get == 'function' && e.get('name') == name && found_ele == false)
			found_ele = e;
	});
	return found_ele;
}

// nasty but effective
function time_string_to_hours(time_string) {
	var hours = 0;
	var minutes = 0;
	var t = time_string.split(' hours');
	if (t.length > 1)
		hours = t[0];

	var t = time_string.split(' minutes');
	if (t.length > 1) {
		t = t[0].replace('hours', '|');
		t = t.replace(',', '');
		t = t.replace(' ', '');
		t = t.split('|');
		if (t.length == 1)
			minutes = t[0];
		else if (t.length == 2)
			minutes = t[1];
	}
	return parseFloat(hours) + parseFloat(minutes / 60);
}
function time_string_to_minutes(time_string) {
	var hours = 0;
	var minutes = 0;
	var t = time_string.split(' hours');
	if (t.length > 1) {
		hours = t[0];
	}
	var t = time_string.split(' minutes');
	if (t.length > 1) {
		t = t[0].replace('hours', '|');
		t = t.replace(',', '');
		t = t.replace(' ', '');
		t = t.split('|');
		if (t.length == 1)
			minutes = t[0];
		else if (t.length == 2)
			minutes = t[1];
	}
	return (parseFloat(hours) * 60) + parseFloat(minutes);
}
function minutes_to_time_string(mins) {
	var hours = 0;
	var minutes = 0;
	
	hours = Math.floor(parseFloat(mins) / 60);
	minutes = parseFloat(mins) - (hours * 60);

	var outstring = '';
	if (hours > 0)
		outstring = hours + ' hours';
	
	if (hours > 0 && minutes > 0)
		outstring += ', ';
	
	if (minutes > 0)
		outstring += minutes + ' minutes';
	return outstring;
}
function hours_to_time_string(hrs) {
	return minutes_to_time_string(parseFloat(hrs) * 60);
}











function discard(ele) {
	if ($(ele))
		$(ele).dispose();
	return true;
}


function cloneObj(o) {
     if(typeof(o) != 'object') return o;
     if(o == null) return o;
   
     var newO = new Object();
   
     for(var i in o) newO[i] = cloneObj(o[i]);
      return newO;
}

function queryAndReplace(query, replace_el_id) {
	var myAjax = new Request({
		url:URL+query,
		method: 'post',
		onComplete: function(text) {
			$(replace_el_id).set('html', text);
		}
	});
	myAjax.send();
	return;
} 


// This function removes non-numeric characters
function stripNonNumeric( str ) {
   	str += '';
   	var rgx = /^\d|\.|-$/;
   	var out = '';
	for( var i = 0; i < str.length; i++ ) {
		if( rgx.test( str.charAt(i) ) ){
			if( 
				!( ( str.charAt(i) == '.' && out.indexOf( '.' ) != -1 ) ||
				( str.charAt(i) == '-' && out.length != 0 ) ) 
			){
				out += str.charAt(i);
			}
		}
  	}
	return out;
}

function number_format(format_string) {
   if (! isType(format, 'string')) {return "";} // sanity check
  
   var hasComma = -1 < format.indexOf(','),
     psplit = format.stripNonNumeric().split('.'),
     that = this;
  
   // compute precision
   if (1 < psplit.length) {
     // fix number precision
     that = that.toFixed(psplit[1].length);
   }
   // error: too many periods
   else if (2 < psplit.length) {
     throw('NumberFormatException: invalid format, formats should have no more than 1 period: ' + format);
   }
   // remove precision
   else {
     that = that.toFixed(0);
   } 
  
   // get the string now that precision is correct
   var fnum = that.toString();
  
   // format has comma, then compute commas
   if (hasComma) {
     // remove precision for computation
     psplit = fnum.split('.');
  
     var cnum = psplit[0],
       parr = [],
       j = cnum.length,
       m = Math.floor(j / 3),
       n = cnum.length % 3 || 3; // n cannot be ZERO or causes infinite loop
  
     // break the number into chunks of 3 digits; first chunk may be less than 3
     for (var i = 0; i < j; i += n) {
       if (i != 0) {n = 3;}
       parr[parr.length] = cnum.substr(i, n);
       m -= 1;
     }
  
     // put chunks back together, separated by comma
     fnum = parr.join(',');
  
     // add the precision back in
     if (psplit[1]) {fnum += '.' + psplit[1];}
   } 
  
   // replace the number portion of the format with fnum
   return format.replace(/[\d,?\.?]+/, fnum);
}

function cash_format(amount) {
	if (typeof amount.replace != 'undefined')
		amount = amount.replace('$', '');
	var i = parseFloat(amount);
	if(isNaN(i)) { i = 0.00; }
	var minus = '';
	if(i < 0) { minus = '-'; }
	i = Math.abs(i);
	i = parseInt((i + .005) * 100);
	i = i / 100;
	s = new String(i);
	if(s.indexOf('.') < 0) { s += '.00'; }
	if(s.indexOf('.') == (s.length - 2)) { s += '0'; }
	s = minus + s;
	return s;
}




function popform_callback (response) {
	if (response.err) {
		show_error(response.msg);
		return false;
	}
	
	var properties = {
		'width':'800px'
	}
	Dialog.box(response.data, properties);
	return false;
}
function mailto (email) {
	document.location = 'mailto:'+email;
}

function showPopupWithText(text) {
	Dialog.box(text)
}
var player = '';

//open and start the audio player
//function listenpopUp(url) {
//window.open(url,'','scrollbars,resizable,width=320px,height=120px,left=50px,top=50px,toolbar=no');
//}
function listenpopUp() {
	player=window.open('listen.php','', 'toolbar=0,scrollbars=0,resizable=1,height=220,width=320'); 
	if (!player.opener) player.opener = self;
	
}



function pop_out(pop_url) {
	day = new Date();
	id = day.getTime();
	eval("page" + id + " = window.open(pop_url, '" + id + "', 'toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=0,width=380,height=500');");
	return id;
}


function truncate(str, limit) {
	if (typeof str == 'undefined' || typeof limit == 'undefied')
		return '';
	if (str.length < limit)
		return str;
	var bits, i;

	bits = str.split('');
	if (bits.length > limit) {
		for (i = bits.length - 1; i > -1; --i) {
			if (i > limit) {
				bits.length = i;
			}
			else if (' ' === bits[i]) {
				bits.length = i;
				break;
			}
		}
		bits.push('...');
	}
	return bits.join('');
}


function popup(url, width, height, left, top) {
	if (typeof width == 'undefined')
		width = 600;
	if (typeof height == 'undefined')
		height = 450;
	if (typeof url == 'undefined')
		return false;
	if (typeof left == 'undefined')
		left = 200;
	if (typeof top == 'undefined')
		top = 100;
	window.open(url, '', 'menubar=1,location=1,resizable=1,scrollbars=1,dependent=1,status=1,width='+width+',height='+height+',left='+left+',top='+top);
	return false;
}


function moreInfoLink(url){
	try {
		//window.opener.document.title = window.opener.document.title;
		//return "Parent Window is Open!";
		var re = /www.grcmc.org\/radio\//i
		opener_url = window.opener.location;

		if(opener_url){
			//if the user is still in the local resonance structure
			if(re.test(opener_url)){
				//change the opener page location
				//alert('still in lr');
				window.opener.location.replace(url);
			} else {
				//alert('not in lr');
				window.opener.open(url);
			}
			window.opener.focus();
			
		} else {
			alert('out of domain');
		}
	}
	catch(e) {
		window.open(url)
	 }
}

function moreInfoLinkO(url){

	if(!window.opener){
		window.open(url);
	} else {
		var opener_url = ''
		try{
			opener_url = window.opener.location;
		} catch(err) {
			opener_url = '';
		}
		var re = /www.grcmc.org\/radio\//i

		if(opener_url){
			//if the user is still in the local resonance structure
			if(re.test(opener_url)){
				//change the opener page location
				//alert('still in lr');
				window.opener.location.replace(url);
			} else {
				//alert('not in lr');
				window.opener.open(url);
			}
			window.opener.focus();
			
		} else {
			alert('out of domain');
		}
	}
}

function set_expander_events () {
	$each($$('.expander'), function (ele) {
		if (!ele.retrieve('jso_complete')) {
			ele.addEvent('click', function () {
				$$('.expander_tip').fade('out').destroy();
				if ($(this).hasClass('open')) { 
					$(this).addClass('closed').removeClass('open').getNext().hide(); 
					if (this.hasClass('expander_boxhelp'))
						$(this).set('html', 'show form description')
				} else {
					if (!$(this).hasClass('multi_open'))
						$$('.expander').removeClass('open').addClass('closed').getNext().hide();
					$(this).addClass('open').removeClass('closed').getNext().show(); 
					if (this.hasClass('expander_boxhelp'))
						$(this).set('html', 'hide form description')
				}
			});
			ele.store('jso_complete', true);
		}
	});
}

window.addEvent('domready', function () {
	set_expander_events();
	
	var smalls = $$('small[html^=\[tk\]]');
	for (i in smalls) {
		if (smalls[i].set)
			smalls[i].set('html', '<a href="#" class="truncate_link">[more]</a>');
	}
	$$('.truncate_link').addEvent('click', function () {
		var parent = this.getParent();
		if (!parent.getNext('div'))
			parent = parent.getParent();
		if (!parent.getNext('div'))
			return;
		var content = parent.getNext('div').get('html');
		show_info(content);
		return false;	
	});

	$$('.qtips').each(function(element,index) {
		if (element.get('title') !== null) {
			var content = element.get('title').split('::');
			element.store('tip:title', content[0]);
		    element.store('tip:text', content[1]);
	
			var qtips = new Tips(element);
			element.store('tips', qtips);
		}
	});
	

	
});
	
	
function ascii_value (c)
{
	// restrict input to a single character
	c = c . charAt (0);

	// loop through all possible ASCII values
	var i;
	for (i = 0; i < 256; ++ i)
	{
		// convert i into a 2-digit hex string
		var h = i . toString (16);
		if (h . length == 1)
			h = "0" + h;

		// insert a % character into the string
		h = "%" + h;

		// determine the character represented by the escape code
		h = unescape (h);

		// if the characters match, we've found the ASCII value
		if (h == c)
			break;
	}
	return i;
}

function random_string(string_length) {
	var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz";
	if (typeof string_length == 'undefined')
		string_length = 8;
	var randomstring = '';
	for (var i=0; i<string_length; i++) {
		var rnum = Math.floor(Math.random() * chars.length);
		randomstring += chars.substring(rnum,rnum+1);
	}
	return randomstring;
}



function $_GET(key) {
	var args = new Object();
	var query = location.search.substring(1);
	var pairs = query.split("&");
	for(var i = 0; i < pairs.length; i++) {
		var pos = pairs[i].indexOf('=');
		if (pos == -1) continue;
		var argname = pairs[i].substring(0,pos);
		var value = pairs[i].substring(pos+1);
		args[argname] = unescape(value);
	}

	if (typeof key == 'undefined') 
		return args;
	
	if (typeof args[key] == 'undefined')
		return null;
	else
		return args[key]
} 




/**
 * Accepts 2 arrays, x and y
 * Loops through both, returns a single array containing
 * a merged copy of the two
 */
function mergeArrays( x, y ) {
	var t = [];
	var cnt = 0;
	
	for( var i = 0; i < x.length; ++i ) {
		t[cnt] = x[i];
		cnt++;
	}
	
	for( var i = 0; i < y.length; ++i ) {
		t[cnt] = y[i];
		cnt++;
	}
	
	return t;
}


function stringToElement(string) {
	var ele = new Element('div', {
		'html':string
	});
	return ele;
}



var aj = false;
window.addEvent('domready', function () {
	aj = new ajax_request();
});
var ajax_request = new Class({
	initialize: function () {
		this.req = new Request({
			'link':'chain',
			'noCache':true,
			'method':'post'
		});
	},
	get: function (handler, data, call) {
		if (typeof call == 'string') {
			call += '(json_resp)';
		}
		this.req.send({
			'url':URL+'index.php',
			'onComplete': function(text) { // no default update element, we do it manually
				console.log(call)
				alert('v');
				eval(call);
			},
			'data': 'component='+handler+'&'+data
		});
	}
})


/**
 * Generic ajax call to handler
 */
function req (handler, data, callback) {
	callback += '(text)';
	var url     = 'index.php';
	
	var myAjax = new Request({
		url:url,
		method: 'post',
		onComplete: function(text) { // no default update element, we do it manually
			eval(callback);
		}
	});
	myAjax.send('component='+handler+'&'+data);
	return;		
	
}

/**
 * Generic ajax call, returns json object
 */
function jsonreq (handler, data, call) {
	if (typeof call == 'string') {
		call += '(json_resp)';
	}
	var myAjax = new Request({
		url:URL+'index.php',
		method: 'post',
		onComplete: function(responseText) {
			json_resp = eval('(' + responseText + ')');
			if (typeof call == 'string') {
				eval(call);
			} else if (typeof call == 'function') {
				call(json_resp);
			}
		}
	});
	myAjax.send('component='+handler+'&'+data);
	return;
}

/**
 * Generic ajax call, returns json object
 */
function jsonreqs (handler, data, call) {
	if (typeof call == 'string') {
		call += '(json_resp)';
	}
	var myAjax = new Request({
		url:SITE_URL+'index.php',
		method: 'post',
		onComplete: function(responseText) {

			json_resp = eval('(' + responseText + ')');
			if (typeof call == 'string') {
				eval(call);
			} else if (typeof call == 'function') {
				call(json_resp);
			}
		}
	});
	myAjax.send('component='+handler+'&'+data);
	return;
}

function titleCaps(title) {
        var small = "(a|an|and|as|at|but|by|en|for|if|in|of|on|or|the|to|v[.]?|via|vs[.]?)";
        var punct = "([!\"#$%&'()*+,./:;<=>?@[\\\\\\]^_`{|}~-]*)";
        var parts = [], split = /[:.;?!] |(?: |^)["Ò]/g, index = 0;
        title = lower(title);
        while (true) {
                var m = split.exec(title);
                parts.push( title.substring(index, m ? m.index : title.length)
                        .replace(/\b([A-Za-z][a-z.'Õ]*)\b/g, function(all){
                                return /[A-Za-z]\.[A-Za-z]/.test(all) ? all : upper(all);
                        })
                        .replace(RegExp("\\b" + small + "\\b", "ig"), lower)
                        .replace(RegExp("^" + punct + small + "\\b", "ig"), function(all, punct, word){
                                return punct + upper(word);
                        })
                        .replace(RegExp("\\b" + small + punct + "$", "ig"), upper));
               
                index = split.lastIndex;
               
                if ( m ) parts.push( m[0] );
                else break;
        }
               
        return parts.join("").replace(/ V(s?)\. /ig, " v$1. ")
                .replace(/(['Õ])S\b/ig, "$1s")
                .replace(/\b(AT&T|Q&A)\b/ig, function(all){
                        return all.toUpperCase();
                });
}
   
function lower(word){
        return word.toLowerCase();
}
function upper(word){
  return word.substr(0,1).toUpperCase() + word.substr(1);
}

function implode( glue, pieces ) {
    // Joins array elements placing glue string between items and return one string  
    // example: implode(' ', ['Apples', 'and', 'Oranges']);
    // returns: 'Apples and Oranges'
    return ( ( pieces instanceof Array ) ? pieces.join ( glue ) : pieces );
}









function urldecode (encoded_text) {
	return decodeURIComponent(encoded_text.replace(/\+/g,  " "));
}






function formatCurrency(num) {
num = num.toString().replace(/\$|\,/g,'');
if(isNaN(num))
num = "0";
sign = (num == (num = Math.abs(num)));
num = Math.floor(num*100+0.50000000001);
cents = num%100;
num = Math.floor(num/100).toString();
if(cents<10)
cents = "0" + cents;
for (var i = 0; i < Math.floor((num.length-(1+i))/3); i++)
num = num.substring(0,num.length-(4*i+3))+','+
num.substring(num.length-(4*i+3));
return (((sign)?'':'-') + '$' + num + '.' + cents);
}

function IsNumeric(strString)
   //  check for valid numeric strings	
   {
   var strValidChars = "0123456789";
   var strChar;
   var blnResult = true;

	if (typeof strString == 'undefined' || strString == null)
		return false;
		
   if (strString.length == 0) return false;

   //  test strString consists of valid characters listed above
   for (i = 0; i < strString.length && blnResult == true; i++)
      {
      strChar = strString.charAt(i);
      if (strValidChars.indexOf(strChar) == -1)
         {
         blnResult = false;
         }
      }
   return blnResult;
   }


function goto(page) {
	location.href = page;
	return;
}
function redirect(page, query) {
	var loc = SITE_URL+'index.php?page='+page;
	if (typeof query != 'undefined')
		loc += '&'+query;
	document.location.href = loc;
	return;
}

function redirects(page, query) {
	var loc = SITE_URLS+'index.php?page='+page;
	if (typeof query != 'undefined')
		loc += '&'+query;
	document.location.href = loc;
	return;
}









function callback(func,opts){ 
	var cb = function(){ 
		var args = opts.args ? opts.args : [];
		var bind = opts.bind ? opts.bind : this;
		var fargs = opts.supressArgs === true ? [] : toArray(arguments);
		func.apply(bind,fargs.concat(args));
	 } 
	 return cb; 
} 
/* A utility function for callback() */ 
function toArray(arrayLike){ 
	var arr = []; 
	for(var i = 0; i < arrayLike.length; i++) {
		arr.push(arrayLike[i]);
	} 
	return arr; 
}



var componentJSO = new Class({
	Implements: Options,
	options: {},
	uid:'',

	// data for dialogs
	confirmData: false,
	errorData: false,
	questionData: false,
	infoData: false,

	boxCallback: $empty(),
	boxOnClose: $empty(),
	boxContentEl: new Element('div'),
	boxOpen: false,

	loading_message: '<center><h3>Please wait</h3><img src="'+(typeof SITE_URLS != 'undefined' ? SITE_URLS : '')+'site/img/system/small_loading.gif" /></center>',
	showLoadingMessage: function (ele, message) {
		if (!ele || !$chk(ele.set))
			return false;

		if ($chk(message)) {
			ele.set('html', '<center><img src="'+(typeof SITE_URLS != 'undefined' ? SITE_URLS : '')+'site/img/system/small_loading.gif" />'+message+'</center>');
		} else {
			ele.set('html', this.loading_message);
		}
		return;
	},

	$: function (id) {
		var c_name = this.uid+'_container';
		return $(c_name).getElements('.'+id)[0];
	},
	$$: function (arg) {
		var c_name = this.uid+'_container';
		return $(c_name).getElements(arg);
	},
	showResultsInBox: function (resp) {
		return this.show_results_in_box(resp);
	},
	show_results_in_box: function (resp) {
		if (resp.err) {
			return show_error(resp.msg);
		}
		
		if (!this.boxOpen)
			Dialog.box(resp.data, {'onClose':this.closingShowInBox.bind(this)});
		else
			this.boxContentEl.set('html', resp.data);

		setTimeout(this.finalizeShowInBox.bind(this), 250);
		return resp;
	},
	finalizeShowInBox: function () {
		if ($('box_content_div')) {
			this.boxOpen = true;
			this.boxContentEl = $('box_content_div');
		
			set_expander_events();
			$('box_content_div').getElements('*[class*=qtips]').each(function(element,index) {
				if (element.get('title') !== null && !element.hasClass('qtips_initialized')) {
					element.addClass('qtips_initialized');
					var content = element.get('title').split('::');
					element.store('tip:title', content[0]);
				    element.store('tip:text', content[1]);
	
					var qtips = new Tips(element);
					element.store('tips', qtips);
				}
			});
			Form.init_forms();
		} else {
			console.log('After show_results_in_box, could not find box');
		}

		if (typeof this.boxCallback == 'function')
			this.boxCallback();

		this.boxCallback = $empty();
	},
	closingShowInBox: function () {
		this.boxOpen = false;
		if (typeof this.boxOnClose == 'function')
			this.boxOnClose();
		this.boxOnClose = $empty();
	},
	
	showConfirm: function (msg, cb, data, buttons) {
		if (typeof cb != 'function')
			return;
		cb = cb.bind(this);
		this.confirmData = {'data':data, 'cb':cb};
		if (!$chk(buttons))
			buttons = {'textBoxBtnOk':'OK', 'textBoxBtnCancel':'Cancel'};
		show_confirm(msg, 'JSO_'+this.uid+'.showConfirmCallback.bind(JSO_'+this.uid+')', buttons);
		return;
	},
	showConfirmCallback: function (answer) {
		if (this.confirmData == false)
			return;
		if (!answer)
			return;
		if (typeof this.confirmData.cb != 'function')
			return;
		this.confirmData.cb(this.confirmData.data);
		this.confirmData = false;
		return;
	},

	showInfo: function (msg, cb) {
		if (typeof cb == 'function')
			cb = cb.bind(this);
		else
			cb = false;
		this.infoData = {'cb':cb};
		show_info(msg, 'JSO_'+this.uid+'.showInfoCallback.bind(JSO_'+this.uid+')');
		return;
	},
	showInfoCallback: function () {
		if (this.infoData == false)
			return;
		if (typeof this.infoData.cb != 'function')
			return;
		this.infoData.cb();
		this.infoData = false;
		return;
	},

	showQuestion: function (msg, cb, data) {
		if (typeof cb != 'function')
			return;

		cb = cb.bind(this);
		this.questionData = {'data':data, 'cb':cb};
		show_question(msg, 'JSO_'+this.uid+'.showQuestionCallback.bind(JSO_'+this.uid+')');
		return;
	},
	showQuestionCallback: function (answer) {
		if (this.questionData == false)
			return;

		if (!answer)
			return;

		if (typeof this.questionData.cb != 'function')
			return;

		this.questionData.cb(this.questionData.data, answer);
		this.questionData = false;
		return;
	},
	showError: function (msg, cb) {
		if (typeof cb == 'function')
			cb = cb.bind(this);
		else
			cb = false;
		this.errorData = {'cb':cb};
		show_error(msg, 'JSO_'+this.uid+'.showErrorCallback.bind(JSO_'+this.uid+')');
		return;
	},
	showErrorCallback: function () {
		if (this.errorData == false)
			return;
		if (typeof this.errorData.cb != 'function')
			return;
		this.errorData.cb();
		this.errorData = false;
		return;
	}
	
	
});








String.noLC = new Object
  ({the:1, a:1, an:1, and:1, or:1, but:1, aboard:1,
    about:1, above:1, across:1, after:1, against:1,
    along:1, amid:1, among:1, around:1, as:1, at:1,
    before:1, behind:1, below:1, beneath:1, beside:1,
    besides:1, between:1, beyond:1, but:1, by:1, 'for':1,
    from:1, 'in':1, inside:1, into:1, like:1, minus:1,
    near:1, of:1, off:1, on:1, onto:1, opposite:1,
    outside:1, over:1, past:1, per:1, plus:1,
    regarding:1, since:1, than:1, through:1, to:1,
    toward:1, towards:1, under:1, underneath:1, unlike:1,
    until:1, up:1, upon:1, versus:1, via:1, 'with':1,
    within:1, without:1});

String.prototype.titleCase = function () {
  var parts = this.split(' ');
  if ( parts.length == 0 ) return '';

  var fixed = new Array();
  for ( var i in parts ) {
    var fix = '';
    if (typeof parts[i] == 'string') {
	    if ( String.noLC[parts[i]] )
	    {
	      fix = parts[i].toLowerCase();
	    }
	    else if ( parts[i].match(/^([A-Z]\.)+$/i) )
	    { // will mess up "i.e." and like
	      fix = parts[i].toUpperCase();
	    }
	    else if ( parts[i].match(/^[^aeiouy]+$/i) )
	    { // voweless words are almost always acronyms
	      fix = parts[i].toUpperCase();
	    }
	    else
	    {
	      fix = parts[i].substr(0,1).toUpperCase() +
	                 parts[i].substr(1,parts[i].length);
	    }
	    fixed.push(fix);
	}
  }
  fixed[0] = fixed[0].substr(0,1).toUpperCase() +
                 fixed[0].substr(1,fixed[0].length);
  return fixed.join(' ');
}


/* END site/base
*************************************************************/

/**************************************************************
 BEGIN site/dialog                                           */
var newDialog = new Class ({
	initialize: function (options) {

	}
});




var dialog = new Class({
  Implements: [Chain],

	getOptions: function(){
		return {
			name: 'dialog',
			zIndex: 999,
			onReturn: false,
			onReturnFunction : $empty,
			BoxStyles: {
				'width': 500
			},
			OverlayStyles: {
				'background-color': '#000',
				'opacity': 0.7
			},
			showDuration: 200,
			showEffect: Fx.Transitions.linear,
      		closeDuration: 100,
			closeEffect: Fx.Transitions.linear,
			moveDuration: 500,
			moveEffect: Fx.Transitions.Back.easeOut,
			onShowStart : $empty,
			onShowComplete : $empty,
			onCloseStart : $empty,
			onCloseComplete : function(properties) {
				this.options.onReturnFunction(this.options.onReturn);
			}.bind(this)
		};
	},

	initialize: function(options){
    	this.i=0;
		this.is_wait = false;
    
		this.setOptions(this.getOptions(), options);

		this.Overlay = new Element('div', {
			'id': 'BoxOverlay',
			'styles': {
				'display': 'none',
				'z-index': this.options.zIndex,
				'position': 'absolute',
				'top': '0',
				'left': '0',
				'background-color': this.options.OverlayStyles['background-color'],
				'opacity': 0,
				'height': window.getScrollHeight() + 'px',
				'width': window.getScrollWidth() + 'px'
			}
		});

		this.Content = new Element('div', {
			'id': this.options.name + '-BoxContainer'
		});

	    this.Container = new Element('div', {
	      'id': this.options.name + '-BoxContent'
	    }).adopt(this.Content);

		this.InBox = new Element('div', {
			'id': this.options.name + '-InBox'
		}).adopt(this.Container);;
		
		this.Box = new Element('div', {
			'id': this.options.name + '-Box',
			'styles': {
				'display': 'none',
				'z-index': this.options.zIndex + 2,
				'position': 'absolute',
				'top': '0',
				'left': '0',
				'width': this.options.BoxStyles['width'] + 'px'
			}
		}).adopt(this.InBox);

    	this.Overlay.injectInside(document.body);
    	this.Box.injectInside(document.body);

    	this.preloadImages();
    
		window.addEvent('resize', function() {
			if(this.options.display == 1) {
				this.Overlay.setStyles({
					'height': window.getScrollHeight() + 'px',
					'width': window.getScrollWidth() + 'px'
				});
				this.replaceBox();
			}
			if(this.DisplayBox == 1) {
				this.Overlay.setStyles({
					'height': window.getScrollHeight() + 'px',
					'width': window.getScrollWidth() + 'px'
				});
				this.replaceDisplayBox();
			}
		}.bind(this));
		
		window.addEvent('scroll', this.replaceBox.bind(this));
		window.addEvent('scroll', this.replaceDisplayBox.bind(this));
	},
	
	setOverlaySize: function () {
		if (this.Overlay) {
			this.Overlay.setStyle('height', document.getScrollSize().y);
			this.Overlay.setStyle('width', document.getScrollSize().x);
		}
	},
	
	preloadImages: function() {
		//var img = new Array(2);
		//img[0] = new Image();img[1] = new Image();img[2] = new Image();
		//img[0].src = this.Box.getStyle('background-image').replace(new RegExp("url\\('?([^']*)'?\\)", 'gi'), "$1");
		//img[1].src = this.InBox.getStyle('background-image').replace(new RegExp("url\\('?([^']*)'?\\)", 'gi'), "$1");
		//img[2].src = this.Container.getStyle('background-image').replace(new RegExp("url\\('?([^']*)'?\\)", 'gi'), "$1");
	},


	/*
	Property: display
		Show or close box
		
	Argument:
		option - integer, 1 to Show box and 0 to close box (with a transition).
	*/	
	display: function(option){
		if(this.Transition)
			this.Transition.cancel();				

		// Show Box	
		if(this.options.display == 0 && option != 0 || option == 1) {

			if(Browser.Engine.trident4)
				$$('select', 'object', 'embed').each(function(node){ node.style.visibility = 'hidden' });

			this.Overlay.setStyle('display', 'block');
			this.options.display = 1;
			this.fireEvent('onShowStart', [this.Overlay]);

			this.Transition = new Fx.Tween(this.Overlay,
				{
          			property: 'opacity',
					duration: this.options.showDuration,
					transition: this.options.showEffect,
					onComplete: function() {
						sizes = window.getSize();
						scrollito = window.getScroll();
						this.Box.setStyles({
							'display': 'block',
							'left': (scrollito.x + (sizes.x - this.options.BoxStyles['width']) / 2).toInt()
						});
						this.replaceBox();
						this.fireEvent('onShowComplete', [this.Overlay]);
					}.bind(this)
				}
			).start(this.options.OverlayStyles['opacity']);
			this.i++;

		} else { // Close Box
			if(Browser.Engine.trident4)
				$$('select', 'object', 'embed').each(function(node){ node.style.visibility = 'visible' });

  			this.queue.delay(500,this);

			this.Box.setStyles({
				'display': 'none',
				'top': 0
			});
			this.Content.empty();
			this.options.display = 0;
						
			this.fireEvent('onCloseStart', [this.Overlay]);
			
			if(this.i==1) {
				this.Transition = new Fx.Tween(this.Overlay,
					{
						property: 'opacity',
						duration: this.options.closeDuration,
						transition: this.options.closeEffect,
						onComplete: function() {
						this.fireEvent('onCloseComplete', [this.Overlay]);
						}.bind(this)
					}
				).start(0);
				this.i--;
			}
		}
	},

	/*
	Property: replaceBox
		Move Box in screen center when brower is resize or scroll
	*/
	replaceBox: function() {
		if(this.options.display == 1) {
			sizes = window.getSize();
      scrollito = window.getScroll();

			if(this.MoveBox)
				this.MoveBox.cancel();
			
			this.MoveBox = new Fx.Morph(this.Box, {
				duration: this.options.moveDuration,
				transition: this.options.moveEffect
			}).start({

				'left': (scrollito.x + (sizes.x - this.options.BoxStyles['width']) / 2).toInt(),
				'top': (scrollito.y + (sizes.y - this.Box.offsetHeight) / 2).toInt()

			});

		}
	},


	queue: function() {
		if (this.i > 0) {
			this.i--;
			this.callChain();
		}
	},

	/*
	Property: messageBox
		Core system for show all type of box
		
	Argument:
		type - string, 'alert' or 'confirm' or 'prompt'
		message - text to show in the box
		properties - see Options below
		input - text value of default 'input' when prompt
		
	Options:
		textBoxBtnOk - text value of 'Ok' button
		textBoxBtnCancel - text value of 'Cancel' button
		onComplete - a function to fire when return box value
	*/	
	messageBox: function(type, message, properties, input) {
		this.setOverlaySize();
		this.chain(function () {

      properties = $extend({
        'textBoxBtnOk': 'OK',
        'textBoxBtnCancel': 'Cancel',
        'textBoxInputPrompt': null,
        'password': false,
        'onComplete': $empty
      }, properties || {});


      this.options.onReturnFunction = properties.onComplete;

      this.ContainerButtons = new Element('div', {
        'id': this.options.name + '-Buttons'
      });
      


      if(type == 'alert' || type == 'info' || type == 'error')
      {
          this.AlertBtnOk = new Element('input', {
            'id': 'BoxAlertBtnOk',
            'type': 'submit',
            'value': properties.textBoxBtnOk,
            'styles': {
              'width': '70px'
            }
          });
          this.AlertBtnOk.addEvent('click', function() {
            this.options.onReturn = true;
            Dialog.hide();
          }.bind(this));
        
          if(type == 'alert')
            this.clase = 'BoxAlert';
          else if(type == 'error')
            this.clase = 'BoxError';
          else if(type == 'info')
            this.clase = 'BoxInfo';
        
          this.Content.setProperty('class',this.clase).set('html',message);

          this.AlertBtnOk.injectInside(this.ContainerButtons);

          this.ContainerButtons.injectInside(this.Content);
          this.display(1);
      }
	  else if(type == 'show')
      {
          this.Content.set('html',message);
          this.display(1);
      }
	  else if(type == 'wait')
      {
		  if (typeof message == 'undefined' || message.length < 1)
		  		message = 'Please wait....';
      	  this.is_wait = true;
          this.Content.set('html','<img src="'+SITE_URLS+'site/img/system/small_loading.gif" style="" alt="Please wait..." /> '+message);
          this.clase = '';
          this.Content.className = '';
          this.display(1);
          this.advance_loading_ani();
      }
      else if(type == 'confirm')
      {
          this.ConfirmBtnOk = new Element('input', {
            'id': 'BoxConfirmBtnOk',
            'type': 'submit',
            'value': properties.textBoxBtnOk,
            'styles': {
              'width': '70px'
            }
          });

          this.ConfirmBtnCancel = new Element('input', {
            'id': 'BoxConfirmBtnCancel',
            'type': 'submit',
            'value': properties.textBoxBtnCancel,
            'styles': {
              'width': '70px'
            }
          });

          this.ConfirmBtnOk.addEvent('click', function() {
            this.options.onReturn = true;
            this.display(0);
          }.bind(this));

          this.ConfirmBtnCancel.addEvent('click', function() {
            this.options.onReturn = false;
            this.display(0);
          }.bind(this));

          this.Content.setProperty('class','BoxConfirm').set('html',message);

          this.ConfirmBtnOk.injectInside(this.ContainerButtons);
          this.ConfirmBtnCancel.injectInside(this.ContainerButtons);
          
          this.ContainerButtons.injectInside(this.Content);
          this.display(1);
      }
      else if(type == 'prompt')
      {
          this.PromptBtnOk = new Element('input', {
            'id': 'BoxPromptBtnOk',
            'type': 'submit',
            'value': properties.textBoxBtnOk,
            'styles': {
              'width': '70px'
            }
          });

          this.PromptBtnCancel = new Element('input', {
            'id': 'BoxPromptBtnCancel',
            'type': 'submit',
            'value': properties.textBoxBtnCancel,
            'styles': {
              'width': '70px'
            }
          });
          
          type = properties.password ? 'password' : 'text';
          this.PromptInput = new Element('textarea', {
            'id': 'BoxPromptInput',
            'type': type,
            'value': input,
            'styles': {
              'width': '250px',
              'height': '80px'
            }
          });

          this.PromptBtnOk.addEvent('click', function() {
            this.options.onReturn = this.PromptInput.value;
            this.display(0);
          }.bind(this));

          this.PromptBtnCancel.addEvent('click', function() {
            this.options.onReturn = false;
            this.display(0);
          }.bind(this));

          this.Content.setProperty('class','BoxPrompt').set('html',message + '<br />');
          this.PromptInput.injectInside(this.Content);
          new Element('br').injectInside(this.Content);
          this.PromptBtnOk.injectInside(this.ContainerButtons);
          this.PromptBtnCancel.injectInside(this.ContainerButtons);


          this.ContainerButtons.injectInside(this.Content);

          this.display(1);
      }
      else
      {
          this.options.onReturn = false;
          this.display(0);		
      }

    });

		this.i++;

		if(this.i==1) this.callChain();

	},

	advance_loading_ani: function () {
	
		if ($('loading_ani') == null)
			return;
	
		if ($('loading_ani').getSize().x >= $('loading_container').getSize().x) {
			$('loading_ani').setStyle('width', '0px');
		} else {
			var new_width_increment = (($('loading_container').getStyle('width').replace('px', '')) / 50);
			var new_width = ($('loading_ani').getSize().x + new_width_increment) + 'px'
			$('loading_ani').setStyle('width', new_width);
		} 
		setTimeout('Dialog.advance_loading_ani()', 100);
	},

	/*
	Property: hide
		Shortcut for hiding the dialog
		
	Argument:
		none
	*/		
	hide: function(message, properties){
		this.display(0);
	},

	/*
	Property: show
		Shortcut for show
		
	Argument:
		properties - see Options in messageBox
	*/		
	show: function(message, properties){
		this.messageBox('show', message, properties);
	},


	/*
	Property: wait
		Shortcut for wait
		
	Argument:
		properties - see Options in messageBox
	*/		
	please_wait: function(message, properties){
		this.messageBox('wait', message);
	},

	/*
	Property: alert
		Shortcut for alert
		
	Argument:
		properties - see Options in messageBox
	*/		
	alert: function(message, properties){
		this.messageBox('alert', message, properties);
	},

	/*
	Property: info
		Shortcut for alert info
		
	Argument:
		properties - see Options in messageBox
	*/		
	info: function(message, properties){
		this.messageBox('info', message, properties);
	},

	/*
	Property: error
		Shortcut for alert error
		
	Argument:
		properties - see Options in messageBox
	*/		
	error: function(message, properties){
		this.messageBox('error', message, properties);
	},

	/*
	Property: confirm
		Shortcut for confirm
		
	Argument:
		properties - see Options in messageBox
	*/
	confirm: function(message, properties){
		this.messageBox('confirm', message, properties);
	},

	/*
	Property: prompt
		Shortcut for prompt
		
	Argument:
		properties - see Options in messageBox
	*/	
	prompt: function(message, input, properties){
		this.messageBox('prompt', message, properties, input);
	},
	
	
	box : function (message, properties, message_type, message_source_ele, show_overlay, auto_move) {
		this.setOverlaySize();
		var box_div = new Element('div', {'id': 'box_box_div'});
		var content_div = new Element('div', {
			'id': 'box_content_div',
			'styles': {
				'width': '100%',
				'overflow':'auto'
			}
		});
		var closer_div = new Element('div', {
			'id': 'box_closer_div',
			'styles': {
				'width':  '24px',
				'height': '24px',
				'backgroundImage': 'url('+SITE_URLS+'site/img/dialog/close.png)',
				'backgroundRepeat': 'no-repeat',
				'float': 'right',
				'marginTop': '-30px',
				'marginRight': '-30px',
				'cursor': 'pointer'
			}
		});
		closer_div.addEvent('click', function () {
			Dialog.removeDisplayBox();
		});
		closer_div.injectInside(box_div);
		content_div.injectInside(box_div);
		box_div.injectInside(document.body);	
		
		if (typeof show_overlay == 'undefined')
			show_overlay = true;
	
		if (typeof auto_move == 'undefined')
			auto_move = true;
	
		properties = $extend({
			'left': '50%',
			'width': '600px',
			'height': '550px',
			'marginLeft': '-400px',
			'backgroundColor':'white',
			'borderTop': '20px solid black',
			'borderBottom': '20px solid black',
			'borderLeft': '20px solid black',
			'borderRight': '20px solid black',
			'position':'absolute',
			'zIndex':'999',
			'visibility': 'hidden'
		}, properties || {});
		
		
		if (typeof message_type == 'undefined') {
			content_div.set('html', message);
			Form.init_forms(true);
		} else if (message_type == 'link') {
			var content_iframe = new Element('iframe', {
				'id': 'DisplayBoxIF',
				'frameborder':'0',
				'styles' : {
					'padding' : '0 0 0 0',
					'margin' : '0 0 0 0' 
				}
			});
			content_iframe.set('src', message);
			content_iframe.store('overall', box_div);
			content_iframe.injectInside(content_div);
			content_iframe.setStyle('height', '99%');
			content_iframe.setStyle('width', '100%');
			content_iframe.setStyle('border', '0');
			content_iframe.addEvent('load', function () {
        		var rv = null; 
				// if contentDocument exists, W3C compliant (e.g. Mozilla) 
				if (this.contentDocument) {
					rv = this.contentDocument;
					//this.retrieve('overall').setStyle('height', rv.body.scrollHeight - 5);
				} else { // bad Internet Explorer  ;)
					//rv = document.frames['DisplayBoxIF'].document;
				}
				//this.setStyle('height', rv.body.scrollHeight);
				//this.retrieve('overall').setStyle('height', rv.body.scrollHeight - 5);
			})
		} else if (message_type == 'img') {
			var content_img = new Element('img');
			content_img.set('src', message);
			content_img.injectInside(content_div);
			
			content_div.setStyle('overflow', 'hidden');
			
			var content_title = new Element('p');
			content_title.setStyle('width', '100%');
			content_title.setStyle('height', '100%');
			content_title.setStyle('paddingBottom', '20px');
			content_title.setStyle('paddingTop', '10px');
			content_title.setStyle('backgroundColor', 'black');
			content_title.setStyle('color', 'white');
			content_title.set('html', '<br>'+message_source_ele.get('alt'));
			content_title.injectInside(content_div);
			content_title.addClass('mediumText');
			
			properties.height = (content_img.getSize().y + 10 + content_title.getSize().y) + 'px';
			properties.width = content_img.getSize().x + 'px';
		} else {
			content_div.set('html', message);
			Form.init_forms(true);
		}



		// get vertical center
		if (typeof properties.top == 'undefined') {
			var bheight = properties.height.replace('px', '');
			var center_start = ((document.body.getSize().y) / 2) - (bheight / 2) + 'px';
			properties.top = center_start;
		}

		// recalculate horizontal center
		var bwidth = properties.width.replace('px', '');
		var margin_start = (bwidth / 2) + 'px';
		properties.marginLeft = '-' + margin_start;
		
		
		for (i in properties) {
			box_div.setStyle(i, properties[i]);
		}
		
		this.DisplayBoxStyles = properties;
		this.DisplayBoxContainer = box_div;
		this.DisplayBox = 1;

		
		content_div.setStyle('height', box_div.clientHeight);
		

		if (show_overlay) {
			this.Overlay.setStyle('display', 'block');
			this.Transition = new Fx.Tween(this.Overlay,
				{
	     			property: 'opacity',
					duration: this.options.showDuration,
					transition: this.options.showEffect,
					onComplete: function() {
						if (auto_move)
							this.showDisplayBox();
						else
							this.DisplayBoxContainer.setStyle('visibility', 'visible');
					}.bind(this)
				}
			).start(this.options.OverlayStyles['opacity']);
		} else {
			if (auto_move)
				this.showDisplayBox();
			else
				this.DisplayBoxContainer.setStyle('visibility', 'visible');
		}
	},
	
	showDisplayBox: function (moveDirection) {	
		if (typeof moveDirection == 'undefined') {
			sizes = window.getSize();
	  		scrollito = window.getScroll();
			this.DisplayBoxContainer.setStyle('top', ((scrollito.y + (sizes.y - 550) / 2).toInt()) + 'px');
			this.DisplayBoxContainer.setStyle('height', '0px');
			this.DisplayBoxContainer.setStyle('width', '0px');
			this.DisplayBoxContainer.setStyle('visibility', 'visible');
			this.chain(function () {
				this.Transition = new Fx.Tween(this.DisplayBoxContainer,
					{
		     			property: 'width',
						duration: this.options.showDuration,
						transition: this.options.showEffect,
						onComplete: function() {
							this.showDisplayBox(1);
						}.bind(this)
					}
				).start(this.DisplayBoxStyles.width);
			});
		} else {
			this.chain(function () {
				this.Transition = new Fx.Tween(this.DisplayBoxContainer,
					{
		     			property: 'height',
						duration: this.options.showDuration,
						transition: this.options.showEffect,
						onComplete: function() {
							if ($chk(this.DisplayBoxStyles.onOpen) && typeof this.DisplayBoxStyles.onOpen == 'function')
								this.DisplayBoxStyles.onOpen();
						}.bind(this)
					}
				).start(this.DisplayBoxStyles.height);
			});
		}
		this.callChain();
	},
	
	removeDisplayBox: function (moveDirection) {
		if (typeof moveDirection != 'undefined') {
			this.chain(function () {
				this.Transition = new Fx.Tween(this.DisplayBoxContainer,
					{
		     			property: 'width',
						duration: this.options.showDuration,
						transition: this.options.showEffect,
						onComplete: function() {
							this.DisplayBoxContainer.destroy();
							this.Transition = new Fx.Tween(this.Overlay,
								{
					     			property: 'opacity',
									duration: this.options.showDuration,
									transition: this.options.showEffect,
									onComplete: function() {
										if ($chk(this.DisplayBoxStyles.onClose) && typeof this.DisplayBoxStyles.onClose == 'function')
											this.DisplayBoxStyles.onClose();
										this.Overlay.setStyle('display', 'none');
										this.DisplayBox = 0;
										this.DisplayBoxProperties = {};
									}.bind(this)
								}
							).start(0);	
						}.bind(this)
					}
				).start(0);
			});
		} else {
			if ($chk(this.DisplayBoxStyles.beforeClose)) {
				var resp = this.DisplayBoxStyles.beforeClose();
				if (resp == false)
					return;
			}
			this.chain(function () {
				this.Transition = new Fx.Tween(this.DisplayBoxContainer,
					{
		     			property: 'height',
						duration: this.options.showDuration,
						transition: this.options.showEffect,
						onComplete: function() {
							this.removeDisplayBox(1);						
						}.bind(this)
					}
				).start(0);
			});
		}
		this.callChain();
	},
	
	/*
	Property: replaceDisplayBox
		Move DisplayBox in screen center when brower is resize or scroll
	*/
	replaceDisplayBox: function() {
		if(this.DisplayBox == 1) {
			sizes = window.getSize();
      		scrollito = window.getScroll();

			if(this.MoveDisplayBox)
				this.MoveDisplayBox.cancel();
			
			this.MoveDisplayBox = new Fx.Morph(this.DisplayBoxContainer, {
				duration: this.options.moveDuration,
				transition: this.options.moveEffect
			}).start({
				'top': (scrollito.y + (sizes.y - this.DisplayBoxContainer.offsetHeight) / 2).toInt()
			});
		}
	}	
});

dialog.implement(new Events, new Options);


window.addEvent('domready', function() {
	Dialog = new dialog();
	
	
	NewDialog = new newDialog();
	
	var db_elements = $('body').getElements('a[rel*=DisplayBox]');
	for (var z=0 ; z<db_elements.length; z++) {
		db_elements[z].addEvent('click', function () {
			Dialog.box(this.get('href'), {}, 'link', this);
			return false;		
		});
	}
	
	var db_elements = document.body.getElements('img[rel*=DisplayBox]');
	for (var z=0 ; z<db_elements.length; z++) {
		db_elements[z].setStyle('cursor', 'pointer');
		db_elements[z].addEvent('click', function () {
			Dialog.box(this.get('src'), {}, 'img', this);
			return false;
		});
	}
	
	window.addEvent('resize', function () {
		Dialog.setOverlaySize();
	});

});


/**
 * Show please wait popup
 *
 * @author	Chris Baker
 *
 * @access	public
 *
 * @version 0.3-11
*/
function show_please_wait (msg) {
	if (typeof msg == 'undefined' || !$chk(msg))
		msg = 'Please wait...';
	Dialog.hide()
	Dialog.please_wait(msg);
	return false;
}
/**
 * Hide the 'Please Wait' dialog
 *
 * @author	Chris Baker
 *
 * @access	public
 *
 * @version 0.3-11
*/
function hide_please_wait () {
	Dialog.hide()
	return false;
}

/**
 * Show html in a popup
 *
 * @author	Chris Baker
 *
 * @access	public
 *
 * @version 0.3-11
*/
function show_html (html) {
	Dialog.hide()
	Dialog.show(html);
	return false;
}


/**
 * Show alert_text in a dialog with an ok button and a warning icon
 *
 * @author	Chris Baker
 *
 * @access	public
 *
 * @version 0.3-11
*/
function show_alert (alert_text) {
	Dialog.hide()
	Dialog.alert(alert_text);
	return false;
}

/**
 * Show err_text in a dialog with an ok button and an error icon
 *
 * @author	Chris Baker
 *
 * @access	public
 *
 * @version 0.3-11
*/
function show_error (err_text, callback) {
	Dialog.hide()
	if (typeof callback != 'undefined') {
		Dialog.error(err_text, { onComplete:function() {
			eval(callback + '()')
		}});
	} else {
		Dialog.error(err_text);
	}
	return false;
}

/**
 * Show conf_text in a dialog with an ok button and a lightbulb icon
 *
 * @author	Chris Baker
 *
 * @access	public
 *
 * @version 0.3-11
*/
function show_info (info_text, callback) {
	Dialog.hide()
	if (typeof callback != 'undefined') {
		Dialog.info(info_text, { onComplete:function() {
			eval(callback + '()')
		}});
	} else {
		Dialog.info(info_text);
	}
	return false;
}

/**
 * Show confirm_text in a dialog with yes and no button with a question icon
 *   - will return the result as boolean
 *
 * @author	Chris Baker
 *
 * @access	public
 *
 * @version 0.3-11
*/
function show_confirm (confirm_text, callback, buttons) {
	if (!$chk(buttons))
		buttons = {'textBoxBtnOk':'OK', 'textBoxBtnCancel':'Cancel'};
	Dialog.hide()
 	Dialog.confirm(confirm_text, { onComplete:function(question_return) {
		eval(callback + '(question_return)')
	}, 
	textBoxBtnOk: buttons.textBoxBtnOk,
	textBoxBtnCancel: buttons.textBoxBtnCancel
	});
	return false;
}

/**
 * Show confirm_text in a dialog with yes and no button with a question icon
 *   - will return the result as boolean
 *
 * @author	Chris Baker
 *
 * @access	public
 *
 * @version 0.3-11
*/
function show_question (ques_text, callback) {
	Dialog.hide()
 	Dialog.prompt(ques_text, '', { onComplete:function(question_return) {
		eval(callback + '(question_return)')
	}});
	return false;
}


/**
 * Displays a full-screen black div with opacity, referred herein as 'blind'
 *
 * @author	Chris Baker
 *
 * @access	public
 *
 * @version 0.3-11
*/
function show_blind() {
	Dialog.hide();
	if ($('BoxOverlay')) {
		$('BoxOverlay').style.display = 'block';
		$('BoxOverlay').style.visibility = 'visible';
		$('BoxOverlay').tween('opacity', '.7');
	} else {
		Dialog.initialize();
		show_blind();		
	}
	return false;
}

/**
 * Remove the blind and any dialogs from the document
 *
 * @author	Chris Baker
 *
 * @access	public
 *
 * @version 0.3-11
*/
function hide_blind () {
	Dialog.hide();
	if ($('BoxOverlay')) {
		$('BoxOverlay').style.visibility = 'hidden';
	}
	return false;
}


/* END site/dialog
*************************************************************/

/**************************************************************
 BEGIN site/form                                           */
// base function for form edit event
function form_edit(){
	console.log('form edit called');
}
// base function for form validation (called onSubmit)
function validate_form(){}


var ___page_has_dp = false;
var ___page_has_dtp = false;
var ___page_has_tp = false;
var ___formCityState = false;

var FormClass = new Class({
	getOptions: function(){
		return {
			'adjust_closers' : false	
		};
	},

	initialize: function(options){
	
		// get an array of all forms
		if (!$('body'))
			return;

	    this.forms = $('body').getElements('form');

	    if (this.forms.length == 0)
	    	return false;
	
		this.adjust_closers();
		this.CityStateUpdater = CityStateUpdater;
		this.init_forms();	
		this.set_hints();
		this.set_limits();
	},
	
	
	adjust_closers: function () {
		var closers = $$('.formDescriptionCloser');
		$each(closers, function(ele, key){
			ele.setStyle('border', '0').setStyle('margin', '0');
	    	ele.setStyle('top', parseFloat(ele.getNext().offsetTop) - 50 );
	    	ele.setStyle('left', (parseFloat(ele.getNext().offsetLeft) +  parseFloat(ele.getNext().clientWidth)) - 150);
	    	ele.show();
		});	
	},

	add_error_to_field: function (field_id, error_text) {
		var field = $(field_id);
		if (!field)
			return false;

		var fparent = field.getParent('div[class*=formElementContainer]');
		if (!fparent)
			return false;

		err_msg_ele = fparent.getElement('p.formErrorField');
		if ($chk(err_msg_ele))
			return false;

		if (typeof error_text == 'undefined')
			error_text = 'Undefined field error!';

		var err = new Element('p', {
			'class': 'formErrorField',
			'html': '<strong>&raquo;&nbsp;' + error_text + '</strong>'
		});

		fparent.addClass('withError');
		err.fade('hide');
		err.inject(fparent, 'top');
		err.fade('in');
		return false;
	},
	remove_field_errors: function (field_id) {
		if (typeof field_id != 'undefined') {
			if (!$(field_id))
				return false;
			var target = $(field_id).getParent();
			target.removeClass('withError');
			err_msg_ele = target.getElement('p.formErrorField');
			if ($chk(err_msg_ele)) {
				var rme = new Fx.Tween(err_msg_ele, {'duration ':'short'});
				rme.addEvent('complete', function (e) {
					e.dispose();
				});
				rme.start('opacity', '1', '0');
			}
			return false;
		}
		$each($$('.withError'), function (ele) {
			ele.removeClass('withError');
			err_msg_ele = ele.getElement('p.formErrorField');
			if ($chk(err_msg_ele)) {
				var rme = new Fx.Tween(err_msg_ele, {'duration ':'short'});
				rme.addEvent('complete', function (e) {
					e.dispose();
				});
				rme.start('opacity', '1', '0');
			}
		});
		return false;
	},	
	
	/*******************************************************************************
	 * Function: 	none - form element focus/blur listeners
	 *
	 * This code executes on the event DOMREADY, it adds a blur and focus event
	 * to all form inputs.  The events add/remove a yellow hilite to a field when it
	 * gains/loses focus.
	 * 
	 * It also hides the field hints, which are then displayed when the user clicks
	 * a particular field. A focus/blur event is added to show/hide the hints
	 * 
	 * Parameters: 	none
	 *   
	 * Author:  	Chris Baker
	 * Date:		01-21-2009
	  ******************************************************************************/
	init_forms: function (rescan_for_new_forms) {
		$each($$('.folded_fieldset'), function (ele) {
			ele.getElements('div[class*=formElementContainer]').hide();
		});
	
	
		//console.log('INIT FORMS');
		//console.log('Form.init_form - active');
		if (typeof rescan_for_new_forms != 'undefined')
			this.forms = $('body').getElements('form');

	    // loop each form
	    for (var i=0; i <this.forms.length; i++) {
			//console.log('Form.init_form - checking');
			//console.log(this.forms[i]);

			//console.log('Form.init_form - will init');
	    	// container for all elements within this form
	        var these_children = this.forms[i].elements;
	        
	        if (typeof these_children == 'undefined' || these_children.length == 0)
	        	break;
	
	        // loop each element
			this.init_elements(these_children);
		        
	    	this.forms[i].store('jso_initialized', true);
	    } // end :: for looping all forms 
	},
	
	
	init_elements: function (eles) {
        for (var z=0; z<eles.length; z++) {
        	// grab a moo element for this child
        	var this_child = $(eles[z]);

			if (this_child.retrieve('jso_initialized') == null) {
	        	// skip fieldsets, buttons, and radios
	            if (this_child.tagName != 'FIELDSET' && this_child.tagName != 'BUTTON' && this_child.type != 'radio') {
	                
					// check if it is a date element
					if (this_child.hasClass('datefield')) {
						var dp_options = false;

						if (this_child.getPrevious().hasClass('dp_options')) {
							var dp_optionsR = this_child.getPrevious().get('html');
							dp_optionsR = dp_optionsR.split('|');
							dp_options = {};
							$each(dp_optionsR,function(d){d = d.split(':');dp_options[d[0]] = d[1];});
							//console.log(dp_options)
						} else {
							dp_options = this_child.retrieve('dp_options');
						}							
						if (!dp_options) {
							dp_options = {};
						}
						var dp = new dateTimePicker(this_child, dp_options);
						this_child.store('jso_ref', dp);
					}
					// check if it is a time element
					if (this_child.hasClass('timefield')) {
						var dp_options = false;
						if (this_child.getPrevious().hasClass('dp_options')) {
							var dp_optionsR = this_child.getPrevious().get('html');
							dp_optionsR = dp_optionsR.split('|');
							dp_options = {};
							$each(dp_optionsR,function(d){d = d.split(':');dp_options[d[0]] = d[1];});
							//console.log(dp_options)
						} else {
							dp_options = this_child.retrieve('dp_options');
						}							
						if (!dp_options) {
							dp_options = {};
						}
						var dp = new dateTimePicker(this_child, dp_options);
						this_child.store('jso_ref', dp);
					}
					// check if it is a date/time element
					if (this_child.hasClass('date_timefield')) {
						var dp_options = false;
						if (this_child.getPrevious().hasClass('dp_options')) {
							var dp_optionsR = this_child.getPrevious().get('html');
							dp_optionsR = dp_optionsR.split('|');
							dp_options = {};
							$each(dp_optionsR,function(d){d = d.split(':');dp_options[d[0]] = d[1];});
							//console.log(dp_options)
						} else {
							dp_options = this_child.retrieve('dp_options');
						}							
						if (!dp_options) {
							dp_options = {};
						}
						var dp = new dateTimePicker(this_child, dp_options);
						this_child.store('jso_ref', dp);
					}
					if (this_child.hasClass('cash_format')) {
						this_child.addEvent('blur', function () {
							this.value = cash_format(this.value);
						});
						this_child.addEvent('change', function () {
							this.value = cash_format(this.value);
						});
						this_child.set('value', cash_format(this_child.get('value')));
					}
					if (this_child.hasClass('number_format')) {
						this_child.addEvent('blur', function () {
							var c = stripNonNumeric(this.value);
							if (c.length > 0)
								this.value = c;
							else
								this.value = 0;
						});
						this_child.addEvent('change', function () {
							var c = stripNonNumeric(this.value);
							if (c.length > 0)
								this.value = c;
							else
								this.value = 0;
						});
					}
					// add the events, both toggle the class withFocus to achieve the yellow bg/border
					this_child.addEvent('focus', function () {
						if ($(this.parentNode).hasClass('formElementContainer'))
							$(this.parentNode).addClass('withFocus');
	                });
	                this_child.addEvent('blur', function () {
	                	if ($(this.parentNode).hasClass('withFocus'))
	                		$(this.parentNode).removeClass('withFocus');
	                });
	                
	                var chk_help = this_child.getNext('span[class*=field_help]');
					if (chk_help && chk_help.get('html').length == 0)
						chk_help.hide(); 
				
				// radios get a special case, because of their element container           
	            } else if (this_child.type == 'radio') {
	
					// each event must cycle upward to find the formElementContainer,
					// which is the element we want to apply the css class to.
	                this_child.addEvent('focus', function () {
	                
		            	var find_parent = $(this.parentNode);
		            	var found_parent = false;
		            	
		            	// check the next 6 parents, we're after the one with the
		            	// classname 'formElementContainer'
		            	for (var t=0;t<6;t++) {
							if (find_parent && find_parent.get('class').indexOf('formElementContainer') != -1) {
								find_parent.addClass('withFocus');
								found_parent = true;
								break;
							}	
							find_parent = $(find_parent.parentNode);					
						}
	                });
	                this_child.addEvent('blur', function () {
		            	var find_parent = $(this.parentNode);
		            	var found_parent = false;
		            	for (var t=0;t<6;t++) {
							if (find_parent && find_parent.get('class').indexOf('formElementContainer') != -1) {
								find_parent.removeClass('withFocus');
								found_parent = true;
								break;
							}					
							find_parent = $(find_parent.parentNode);					
						}
	                });
				} // end :: if checking element type
			} // end :: if checking if this element has been jso_initialized
        	this_child.store('jso_initialized', true);					
        } // end :: for looping form elements
	},
	
	
	/**
	 * Textarea/input limit handler
	 * Adds an onKeyUp event to every input and textarea element with
	 * rel="limit" and maxlength="x" attributes, adds a counter below the element
	 *  that informs the user of the remaining characters for the field
	 *
	 *  I.E.
	 *  Limit: 30/Remaining: 30
	 *
	 * As the user types, the 'remaining' count updates with the new count
	 */
	set_limits: function () {
		if (!$('body'))
			return false;	
		// grab a list of all limited fields
		var textareas = $('body').getElements('input[rel*=limit]');
		var inputs = $('body').getElements('textarea[rel*=limit]');
		inputs = mergeArrays(inputs, textareas);
	
		// loop through the fields
		for (var i=0; i<inputs.length; i++){
			// easier reference to the element
			var this_input = inputs[i];
			
			// check the rel for proper limit indication
			var this_rel = this_input.get('rel');
			this_rel = this_rel.split('limit:');
			if (this_rel.length != 2)
				continue;
	
			// make sure there is nothing AFTER the limit amount
			this_rel = this_rel[1].split(' ');
			var this_limit = this_rel[0];
			
			
			// get a reference to the element's field help
			var this_help = $(this_input.get('id') + '_help');
	
			// determine how many chars are left in the limit with the current value
			var charsRemain = parseFloat(this_limit) - parseFloat(this_input.value.length);
			
			if (charsRemain < 0)
				var valString = '<span class="bold red">' + charsRemain + '</span>';
			else
				var valString = '<span class="green">' + charsRemain + '</span>';		
	
			var append_html = '';
			if (this_help.innerHTML.length > 0)
				append_html = '<br><br>'+this_help.innerHTML;
			
			this_help.innerHTML = 'Limit: ' + this_limit + '/Remaining: <span id="' + this_input.get("id") + '_limit">' + valString + '</span>'+append_html;
			this_input.addEvent('keyup', function () {
				Form.updateLimit(this);
				return false;
			});
		}
	},
	
	/**
	 * OnKeyUp event handler for form elements with maxlen=x and rel=limit
	 * Updates the counter for characters remaining
	 */
	updateLimit: function (targetElement) {
		var limitBox = $(targetElement.id + '_limit');
		if (!limitBox) {
		    return;
		}
		
		// check the rel for proper limit indication
		var this_rel = targetElement.get('rel');
		this_rel = this_rel.split('limit:');
		if (this_rel.length != 2)
			return;
	
		// make sure there is nothing AFTER the limit amount
		this_rel = this_rel[1].split(' ');
		var lenLimit = this_rel[0];
		var currLen = targetElement.value.length;
		var charsLeft = parseFloat(lenLimit) - parseFloat(currLen);
		if (charsLeft < 0)
			valString = '<span class="bold red">' + charsLeft + '</span>';
		else
			valString = '<span class="green">' + charsLeft + '</span>';
		limitBox.innerHTML = valString;
		return;
	},
	
	
	set_hints: function () {
		// hide field hints
		$$('.field_hint').setStyles({
			float: '',
		    display: 'none',
		    position: 'relative',
		    width: '300px'
		});
		$$('.field_hint_text').setStyles({
		    border: '2px solid #ADAC9F',
		    backgroundColor: 'white'
		});
		$$('.field_hint_arrow').setStyle('display', 'block');
		var t = $$('.field_hint');
		
		// loop the hints, add the show/hide events
		for (var i=0; i<t.length; i++) {
		
			// grab a reference to the form node
			var formNode = t[i].getPrevious();
			
			
			// some containers have subcontainers, look out for those
			if (formNode.tagName != 'DIV') {
	
				// regular field, add the events to show/hide the hints
				t[i].getPrevious().addEvent('focus', function () {
					this.getNext().style.display = '';
					var ofHeight = (this.getNext().offsetHeight);
					ofHeight = ofHeight + this.getNext().getPrevious().offsetHeight;
					//console.log(ofHeight)
					this.getNext().style.marginTop = '-'+(ofHeight)+'px';
				})
				t[i].getPrevious().addEvent('blur', function () {
					this.getNext().style.display = 'none';	
				})			
			} else {		
		    	// check the next 6 parents, we're after the one with the
		    	// classname 'formElementContainer'
		    	find_parent = t[i].getParent();
		    	use_parent = false;
		    	for (var g=0;g<6;g++) {  		
					if (find_parent.get('class').indexOf('formElementContainer') != -1) {
						use_parent = find_parent;
						break;
					}	
					find_parent = $(find_parent.parentNode);					
				}
				
				// we were able to find the container, now we can target all form 
				// elements inside the container
				if (use_parent) {
				
					// grab a copy of the parent's id
					var up_id = use_parent.id;
					
					// give the hint an id so it can be referenced later
					t[i].id = up_id+'_hint';
					var ti_id = t[i].id; 
					$(ti_id).set('rel', up_id);
					
					// get all form nodes inside the parent
					var nodes = $$('#'+up_id+' input');
					
					// loop the nodes, add the events
					for (var z=0; z<nodes.length;z++) {
						// add the hint's id to the node's rel, so it can be
						// referenced later
						nodes.set('rel',ti_id);
						
						// add the events
						nodes[z].addEvent('focus', function () {
							$(this.get('rel')).style.display = '';
							var ofHeight = $(this.get('rel')).offsetHeight;
							ofHeight = $(this.get('rel')).getPrevious().offsetHeight + ofHeight + 10;
							$(this.get('rel')).style.marginTop = '-'+ofHeight+'px';
						})
						nodes[z].addEvent('blur', function () {
							$(this.get('rel')).style.display = 'none';	
						})
					} // end :: for looping nodes
				}// end :: if checking for parent
			} // end :: if checking for a element or a div
		}// end for :: looping all hints
	}
	
	
});
FormClass.implement(new Events, new Options);







var ___captcha_reloading = false;
function ___reload_captcha() {
	if (___captcha_reloading)
		return false;
		
	var captcha_key = $('__captcha_key').value;
	___captcha_reloading = true;
	$('___reload_captcha').innerHTML = 'Loading...';
	$('___captcha_wait').style.display = '';
	$('___captcha_image').src = $('___captcha_image').src + '&d=' + (new Date()).getTime();
	setTimeout("___release_reloading();", 1000)
	return false;
}
function ___release_reloading() {
	___captcha_reloading = false;
	$('___reload_captcha').innerHTML = 'Try a new one';
	$('___captcha_wait').style.display = 'none';
}


var ___formCityState = null;
CityStateUpdater = {
	element_groups : {},
	init : function (ele) {
		if (typeof ele == 'undefined')
			return false;
		if (this.initialized) {
			this.add_element(ele);
			return true;
		}
		this.verbose_errors = true;
		
		this.initialized = true;
		return this.add_element(ele);
	},
	
	add_element : function (ele) {
		if (ele.get('rel').indexOf('CityStateType:') != -1) {
			// parse the type out from the element's rel
			var regx = new RegExp('CityStateType:(.*)\\|(.*)\\| ');
  			var parms = regx.exec(ele.get('rel'));
  			
  			if (parms.length != 3)
  				return Form.CityStateUpdater.show_error('CityState::add_element() invalid CityState type or xref');


			if (parms[1] != 'state' && parms[1] != 'city' && parms[1] != 'zip')
				return Form.CityStateUpdater.show_error('CityState::add_element() invalid CityState type. Expecting "city", "state", or "zip", got "'+parms[1]+'"');

			if (parms[2].length == 0) {
				parms[2] = random_string(6)
				var new_ref_string = 'CityStateType:'+parms[1]+'|'+parms[2]+'|';
				var old_ref_string = 'CityStateType:'+parms[1]+'||';
				ele.set('rel', ele.get('rel').replace(old_ref_string, new_ref_string));								
			}

			if (typeof Form.CityStateUpdater.element_groups[parms[2]] == 'undefined') {
				Form.CityStateUpdater.element_groups[parms[2]] = {};
			}

			Form.CityStateUpdater.element_groups[parms[2]][parms[1]] = ele;
			ele.store('xref', parms[2]);
			ele.store('ref', Form.CityStateUpdater);
			// add the events
			if (parms[1] == 'city') {
				ele.addEvent('blur', function () {
					Form.CityStateUpdater.changed_city(this);
				});
				
				if (ele.get('value').length > 0)
					ele.store('current_value', ele.get('value'));

				var state_val = (typeof this.element_groups[parms[2]]['state'] != 'undefined') ? this.element_groups[parms[2]]['state'].get('value') : false;
				if (typeof this.element_groups[parms[2]]['state'] != 'undefined' && state_val) {
					jsonreq('___form_element_handler___', 'action=get_city_list&state='+this.element_groups[parms[2]]['state'].get('value')+'&xref='+parms[2], Form.CityStateUpdater.populate_cities);
				} else {
					if (ele.get('value').length > 0)
						jsonreq('___form_element_handler___', 'action=get_city_list&city='+ele.get('value')+'&xref='+parms[2], Form.CityStateUpdater.populate_cities);				
					else if (typeof this.element_groups[parms[2]]['state'] == 'undefined')
						jsonreq('___form_element_handler___', 'action=get_city_list&state=-1+&xref='+parms[2], Form.CityStateUpdater.populate_cities);
				}
				
			} else if (parms[1] == 'state') {
				ele.addEvent('blur', function () {
					Form.CityStateUpdater.changed_state(this);
				});
				$(ele).store('current_value', ele.get('value'));
				jsonreq('___form_element_handler___', 'action=get_state_list&xref='+parms[2], Form.CityStateUpdater.populate_states.bind(this));
			}

			return true;
		}

		return Form.CityStateUpdater.show_error('CityState::add_element() invalid element rel.');
	},
	show_error : function (err) {
		if (Form.CityStateUpdater.verbose_errors)
			show_error('This form contains errors, and may not function properly.<br><br>Error description: '+err);
		return false;
	},
	dump_elements : function () {
		Form.CityStateUpdater.show_errors(this.element_groups);
		return false;
	},

	changed_city : function (ele) {
		return true;
	},

	changed_state : function (ele) {
		if (!ele.get('value') || ele.get('value') == 0)
			return false;
		var xref = ele.retrieve('xref');
		// clear the zip
		if (typeof Form.CityStateUpdater.element_groups[xref]['zip'] != 'undefined') {
			Form.CityStateUpdater.element_groups[xref]['zip'].value = '';
		}
		// clear the cities, display loading message
		if (typeof Form.CityStateUpdater.element_groups[xref]['city'] != 'undefined') {
			Form.CityStateUpdater.element_groups[xref]['city'].options.length = 0;
			Form.CityStateUpdater.element_groups[xref]['city'].options[0] = new Option('loading...');
			jsonreq('___form_element_handler___', 'action=get_city_list&state='+ele.get('value')+'&xref='+xref, Form.CityStateUpdater.populate_cities)
		}		
		return true;
	},
	populate_cities : function (response) {
		//console.log('populate cities');
		if (typeof response.xref == 'undefined') {
			//console.log('no xref in populate cities');
			return false;
		}

		if (response.msg) {
			Form.CityStateUpdater.show_error(response.msg);
			return;
		}


		var current_value = Form.CityStateUpdater.element_groups[response.xref]['city'].retrieve('current_value');

		if (!$chk(current_value)) {
			current_value = response.default_value;
		}

		Form.CityStateUpdater.element_groups[response.xref]['city'].options.length = 0;
		
		// make sure it is visible
		Form.CityStateUpdater.element_groups[response.xref]['city'].show();
		
		var nOpt = new Option('select a city', '0');
		Form.CityStateUpdater.element_groups[response.xref]['city'].options[Form.CityStateUpdater.element_groups[response.xref]['city'].options.length] = nOpt;
		for (var y=0; y < response.list.length; y++) {
			var nOpt = new Option(response['list'][y].city, response['list'][y].city);
			$(nOpt).setAttribute('rel', response['list'][y].zip);
			Form.CityStateUpdater.element_groups[response.xref]['city'].options[y] = nOpt;
			if (current_value && current_value == response['list'][y].city)
				$(nOpt).set('selected', 'true');
		}
	
		return true;	
	},
	populate_states : function (response) {
		if (typeof response.xref == 'undefined')
			return false;

		if (response.msg) {
			Form.CityStateUpdater.show_errors(reponse.msg)
		}

		var using_default = false;
		var current_value = Form.CityStateUpdater.element_groups[response.xref]['state'].retrieve('current_value');

		if (current_value.length == 0) {
			current_value = response.default_value;
			using_default = true;
		}

		Form.CityStateUpdater.element_groups[response.xref]['state'].options.length = 0;
		
		var nOpt = new Option('select a state', '0');
		Form.CityStateUpdater.element_groups[response.xref]['state'].options[Form.CityStateUpdater.element_groups[response.xref]['state'].options.length] = nOpt;

		if (!Form.CityStateUpdater.element_groups[response.xref]['city'].retrieve('current_value')) {
			Form.CityStateUpdater.element_groups[response.xref]['city'].options.length = 0;
			var nOpt = new Option('select a state first', '0');
			Form.CityStateUpdater.element_groups[response.xref]['city'].options[Form.CityStateUpdater.element_groups[response.xref]['city'].options.length] = nOpt;
		}		
		for (var y=0; y < response.list.length; y++) {
			var nOpt = new Option(response['list'][y].state, response['list'][y].state);
			Form.CityStateUpdater.element_groups[response.xref]['state'].options[Form.CityStateUpdater.element_groups[response.xref]['state'].options.length] = nOpt;
			if (current_value && current_value == response['list'][y].state)
				$(nOpt).set('selected', 'true');
		}

		if (using_default == true) {
			jsonreq('___form_element_handler___', 'action=get_city_list&state='+current_value+'&xref='+response.xref, Form.CityStateUpdater.populate_cities.bind(this));
		}

		return true;	
	}
}



function form_tab_control (mode, targEle, fieldset_id) {
	if (typeof mode == 'undefined' || typeof targEle == 'undefined')
		return;	
	switch (mode) {
		case 'over':
			if (!$(targEle).hasClass('active'))
				$(targEle).addClass('hover');
			break;
		case 'out':
			if (!$(targEle).hasClass('active'))
				$(targEle).removeClass('hover');
			break;
		case 'click':
			___turn_off_all_form_tabs(fieldset_id);
			$(targEle).addClass('active');
			$('fieldset_'+fieldset_id).show();
			break;	
	}

}

function ___turn_off_all_form_tabs (fieldset_id) {
	var frm = $('fieldset_'+fieldset_id).form;
	var form_id = $(frm).get('id');
	var frm_tabs = $(frm).getPrevious('ul');
	var tds = $(frm_tabs).getChildren();
	tds.removeClass('hover');
	tds.removeClass('active');
	$(frm).getElements('fieldset').hide();
}



/*
Script: MooEditable.js
	Class for creating a WYSIWYG editor, for contentEditable-capable browsers.

License:
	MIT-style license.

Copyright:
	Copyright (c) 2007-2009 [Lim Chee Aun](http://cheeaun.com).
	
Build: %build%

Credits:
	- Code inspired by Stefan's work [Safari Supports Content Editing!](http://www.xs4all.nl/~hhijdra/stefan/ContentEditable.html) from [safari gets contentEditable](http://walkah.net/blog/walkah/safari-gets-contenteditable)
	- Main reference from Peter-Paul Koch's [execCommand compatibility](http://www.quirksmode.org/dom/execCommand.html)
	- Some ideas and code inspired by [TinyMCE](http://tinymce.moxiecode.com/)
	- Some functions inspired by Inviz's [Most tiny wysiwyg you ever seen](http://forum.mootools.net/viewtopic.php?id=746), [mooWyg (Most tiny WYSIWYG 2.0)](http://forum.mootools.net/viewtopic.php?id=5740)
	- Some regex from Cameron Adams's [widgEditor](http://widgeditor.googlecode.com/)
	- Some code from Juan M Martinez's [jwysiwyg](http://jwysiwyg.googlecode.com/)
	- Some reference from MoxieForge's [PunyMCE](http://punymce.googlecode.com/)
	- IE support referring Robert Bredlau's [Rich Text Editing](http://www.rbredlau.com/drupal/node/6)
	- Tango icons from the [Tango Desktop Project](http://tango.freedesktop.org/)
	- Additional Tango icons from Jimmacs' [Tango OpenOffice](http://www.gnome-look.org/content/show.php/Tango+OpenOffice?content=54799)
*/

var MooEditable = new Class({

	Implements: [Events, Options],

	options: {
		toolbar: true,
		cleanup: true,
		paragraphise: true,
		xhtml : true,
		semantics : true,
		actions: 'bold italic underline strikethrough | insertunorderedlist insertorderedlist indent outdent | undo redo | createlink unlink | urlimage | toggleview',
		handleSubmit: true,
		handleLabel: true,
		baseCSS: 'html{ height: 100%; cursor: text }\
			body{ font-family: Trebuchet MS, Verdana, Arial, sans-serif; border: 0; }',
		extraCSS: '',
		externalCSS: '',
		html: '<html>\
			<head>\
			<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">\
			<style>{BASECSS} {EXTRACSS}</style>\
			{EXTERNALCSS}\
			</head>\
			<body>{CONTENT}</body>\
			</html>'
	},

	initialize: function(el, options){
		this.setOptions(options);
		this.textarea = $(el);
		this.textarea.store('MooEditable', this);
		this.actions = this.options.actions.clean().split(' ');
		this.keys = {};
		this.dialogs = {};
		this.actions.each(function(action){
			var act = MooEditable.Actions[action];
			if (!act) return;
			if (act.options){
				var key = act.options.shortcut;
				if (key) this.keys[key] = action;
			}
			if (act.dialogs){
				$each(act.dialogs, function(dialog, name){
					dialog = dialog.attempt(this);
					dialog.name = action + ':' + name;
					if ($type(this.dialogs[action]) != 'object') this.dialogs[action] = {};
					this.dialogs[action][name] = dialog;
				}, this);
			}
			if (act.events){
				$each(act.events, function(fn, event){
					this.addEvent(event, fn);
				}, this);
			}
		}.bind(this));
		this.render();
	},
	
	toElement: function(){
		return this.textarea;
	},
	
	render: function(){
		var self = this;
		
		// Dimensions
		var dimensions = this.textarea.getSize();

		// Build the container
		this.container = new Element('div', {
			id: (this.textarea.id) ? this.textarea.id + '-mooeditable-container' : null,
			'class': 'mooeditable-container',
			styles: {
				width: (dimensions.x > 0 ? dimensions.x : this.textarea.style.width) 
			}
		});


		// Override all textarea styles
		this.textarea.addClass('mooeditable-textarea').setStyle('height', (dimensions.y > 0 ? dimensions.y : this.textarea.style.height));

		// Build the iframe
		this.iframe = new IFrame({
			'class': 'mooeditable-iframe',
			styles: {
				height: (dimensions.y > 0 ? dimensions.y : this.textarea.style.height)
			}
		});
		
		this.toolbar = new MooEditable.UI.Toolbar({
			onItemAction: function(){
				var args = $splat(arguments);
				var item = args[0];
				self.action(item.name, args);
			}
		});
		this.attach();
		
		// Update the event for textarea's corresponding labels
		if (this.options.handleLabel && this.textarea.id) $$('label[for="'+this.textarea.id+'"]').addEvent('click', function(e){
			if (self.mode != 'iframe') return;
			e.preventDefault();
			self.focus();
		});

		// Update & cleanup content before submit
		if (this.options.handleSubmit){
			this.form = this.textarea.getParent('form');
			if (!this.form) return;
			this.form.addEvent('submit', function(){
				if (self.mode == 'iframe') self.saveContent();
			});
		}		
		this.fireEvent('render', this);
	},

	attach: function(){
		var self = this;

		// Assign view mode
		this.mode = 'iframe';
		
		// Editor iframe state
		this.editorDisabled = false;

		// Put textarea inside container
		this.container.wraps(this.textarea);

		this.textarea.setStyle('display', 'none');
		
		this.iframe.setStyle('display', '').inject(this.textarea, 'before');
		
		$each(this.dialogs, function(action, name){
			$each(action, function(dialog){
				$(dialog).inject(self.iframe, 'before');
				var range;
				dialog.addEvents({
					open: function(){
						range = self.selection.getRange();
						self.editorDisabled = true;
						self.toolbar.disable(name);
						self.fireEvent('dialogOpen', this);
					},
					close: function(){
						self.toolbar.enable();
						self.editorDisabled = false;
						self.focus();
						if (range) self.selection.setRange(range);
						self.fireEvent('dialogClose', this);
					}
				});
			});
		});

		// contentWindow and document references
		this.win = this.iframe.contentWindow;
		this.doc = this.win.document;

		// Build the content of iframe
		var docHTML = this.options.html.substitute({
			BASECSS: this.options.baseCSS,
			EXTRACSS: this.options.extraCSS,
			EXTERNALCSS: (this.options.externalCSS) ? '<link rel="stylesheet" href="' + this.options.externalCSS + '">': '',
			CONTENT: this.cleanup(this.textarea.get('value'))
		});
		this.doc.open();
		this.doc.write(docHTML);
		this.doc.close();

		// Turn on Design Mode
		// IE fired load event twice if designMode is set
		(Browser.Engine.trident) ? this.doc.body.contentEditable = true : this.doc.designMode = 'On';

		// Mootoolize window, document and body
		if (!this.win.$family) new Window(this.win);
		if (!this.doc.$family) new Document(this.doc);
		$(this.doc.body);

		// Bind keyboard shortcuts
		this.doc.addEvents({
			mouseup: this.editorMouseUp.bind(this),
			mousedown: this.editorMouseDown.bind(this),
			contextmenu: this.editorContextMenu.bind(this),
			click: this.editorClick.bind(this),
			dbllick: this.editorDoubleClick.bind(this),
			keypress: this.editorKeyPress.bind(this),
			keyup: this.editorKeyUp.bind(this),
			keydown: this.editorKeyDown.bind(this)
		});
		this.textarea.addEvent('keypress', this.textarea.retrieve('mooeditable:textareaKeyListener', this.keyListener.bind(this)));
		
		// Fix window focus event not firing on Firefox 2
		if (Browser.Engine.gecko && Browser.Engine.version == 18) this.doc.addEvent('focus', function(){
			self.win.fireEvent('focus').focus();
		});

		// styleWithCSS, not supported in IE and Opera
		if (!(/trident|presto/i).test(Browser.Engine.name)){
			var styleCSS = function(){
				self.execute('styleWithCSS', false, false);
				self.doc.removeEvent('focus', styleCSS);
			};
			this.win.addEvent('focus', styleCSS);
		}

		if (this.options.toolbar){
			$(this.toolbar).inject(this.container, 'top');
			this.toolbar.render(this.actions);
		}

		this.selection = new MooEditable.Selection(this.win);
		
		this.fireEvent('attach', this);
		
		return this;
	},
	
	detach: function(){
		this.saveContent();
		this.textarea.setStyle('display', '').removeClass('mooeditable-textarea').inject(this.container, 'before');
		this.textarea.removeEvent('keypress', this.textarea.retrieve('mooeditable:textareaKeyListener'));
		this.container.dispose();
		this.fireEvent('detach', this);
		return this;
	},
	
	editorMouseUp: function(e){
		if (this.editorDisabled){
			e.stop();
			return;
		}
		
		if (this.options.toolbar) this.checkStates();
		
		this.fireEvent('editorMouseUp', e);
	},
	
	editorMouseDown: function(e){
		if (this.editorDisabled){
			e.stop();
			return;
		}
		
		this.fireEvent('editorMouseDown', e);
	},
	
	editorContextMenu: function(e){
		if (this.editorDisabled){
			e.stop();
			return;
		}
		
		this.fireEvent('editorContextMenu', e);
	},
	
	editorClick: function(e){
		// make images selectable and draggable in Safari
		if (Browser.Engine.webkit){
			var el = e.target;
			if (el.get('tag') == 'img'){
				this.selection.selectNode(el);
			}
		}
		
		this.fireEvent('editorClick', e);
	},
	
	editorDoubleClick: function(e){
		this.fireEvent('editorDoubleClick', e);
	},
	
	editorKeyPress: function(e){
		if (this.editorDisabled){
			e.stop();
			return;
		}
		
		this.keyListener(e);
		
		this.fireEvent('editorKeyPress', e);
	},
	
	editorKeyUp: function(e){
		if (this.editorDisabled){
			e.stop();
			return;
		}
		
		if (this.options.toolbar) this.checkStates();
		
		this.fireEvent('editorKeyUp', e);
	},
	
	editorKeyDown: function(e){
		if (this.editorDisabled){
			e.stop();
			return;
		}
		
		if (e.key == 'enter'){
			if (this.options.paragraphise) {
				if (e.shift && Browser.Engine.webkit){
					var s = this.selection;
					var r = s.getRange();
					// Insert BR element
					var br = this.doc.createElement('br');
					r.insertNode(br);

					// Place caret after BR
					r.setStartAfter(br);
					r.setEndAfter(br);
					s.setRange(r);
					
					// Could not place caret after BR then insert an nbsp entity and move the caret
					if (s.getSelection().focusNode == br.previousSibling){
						var nbsp = this.doc.createTextNode('\u00a0');
						var p = br.parentNode;
						var ns = br.nextSibling;
						(ns) ? p.insertBefore(nbsp, ns) : p.appendChild(nbsp);
						s.selectNode(nbsp);
						s.collapse(1);
					}
					
					// Scroll to new position, scrollIntoView can't be used due to bug: http://bugs.webkit.org/show_bug.cgi?id=16117
					this.win.scrollTo(0, Element.getOffsets(s.getRange().startContainer).y);
					
					e.preventDefault();
				} else if (Browser.Engine.gecko || Browser.Engine.webkit){
					var node = this.selection.getNode();
					var blockEls = /^(H[1-6]|P|DIV|ADDRESS|PRE|FORM|TABLE|LI|OL|UL|TD|CAPTION|BLOCKQUOTE|CENTER|DL|DT|DD)$/;
					var isBlock = node.getParents().include(node).some(function(el){
						return el.nodeName.test(blockEls);
					});
					if (!isBlock) this.execute('insertparagraph');
				} else if (!e.shift && !Browser.Engine.webkit && !Browser.Engine.gecko) {
					this.execute('insertparagraph');
				}
			} else {
				if (Browser.Engine.trident){
					var r = this.selection.getRange();
					var node = this.selection.getNode();
					if (r && node.get('tag') != 'li'){
						this.selection.insertContent('<br>');
						this.selection.collapse(false);
					}
					e.preventDefault();
				}
			}
		}
		
		this.fireEvent('editorKeyDown', e);
	},
	
	keyListener: function(e){
		var key = (Browser.Platform.mac) ? e.meta : e.control;
		if (!key || !this.keys[e.key]) return;
		e.preventDefault();
		var item = this.toolbar.getItem(this.keys[e.key]);
		item.action(e);
	},

	focus: function(){
		// needs the delay to get focus working
		(function(){ 
			(this.mode == 'iframe' ? this.win : this.textarea).focus();
			this.fireEvent('focus', this);
		}).bind(this).delay(10);
		return this;
	},

	action: function(command, args){
		var action = MooEditable.Actions[command];
		if (action.command && $type(action.command) == 'function'){
			action.command.run(args, this);
		} else {
			this.focus();
			this.execute(command, false, args);
			if (this.mode == 'iframe') this.checkStates();
		}
	},

	execute: function(command, param1, param2){
		if (this.busy) return;
		this.busy = true;
		this.doc.execCommand(command, param1, param2);
		this.saveContent();
		this.busy = false;
		return false;
	},

	toggleView: function(){
		this.fireEvent('beforeToggleView', this);
		if (this.mode == 'textarea'){
			this.mode = 'iframe';
			this.iframe.setStyle('display', '');
			this.setContent(this.textarea.value);
			this.textarea.setStyle('display', 'none');
		} else {
			this.saveContent();
			this.mode = 'textarea';
			this.textarea.setStyle('display', '');
			this.iframe.setStyle('display', 'none');
		}
		this.fireEvent('toggleView', this);
		this.focus();
		return this;
	},

	getContent: function(){
		return this.cleanup(this.doc.body.get('html'));
	},

	setContent: function(newContent){
		this.doc.body.set('html', newContent);
		return this;
	},

	saveContent: function(){
		if (this.mode == 'iframe') this.textarea.set('value', this.getContent());
		return this;
	},

	checkStates: function(){
		this.actions.each(function(action){
			var item = this.toolbar.getItem(action);
			if (!item) return;
			item.deactivate();

			var states = MooEditable.Actions[action]['states'];
			if (!states) return;
			
			var el = this.selection.getNode();
			if (!el) return;
			
			// custom checkState
			if ($type(states) == 'function'){
				states.attempt(el, item);
				return;
			}
			
			try{
				if (this.doc.queryCommandState(action)){
					item.activate();
					return;
				}
			} catch(e) {}
			
			if (states.tags){
				do {
					if ($type(el) != 'element') break;
					var tag = el.tagName.toLowerCase();
					if (states.tags.contains(tag)){
						item.activate(tag);
						break;
					}
				}
				while (el = el.parentNode);
			}

			if (states.css){
				var blockEls = /^(H[1-6]|P|DIV|ADDRESS|PRE|FORM|TABLE|LI|OL|UL|TD|CAPTION|BLOCKQUOTE|CENTER|DL|DT|DD)$/;
				do {
					if ($type(el) != 'element') break;
					var found = false;
					for (var prop in states.css){
						var css = states.css[prop];
						if ($(el).getStyle(prop).contains(css)){
							item.activate(css);
							found = true;
						}
					}
					if (found || el.tagName.test(blockEls)) break;
				}
				while (el = el.parentNode);
			}
		}.bind(this));
	},

	cleanup: function(source){
		if (!this.options.cleanup) return source.trim();
		
		if (typeof source == 'undefined')
			return '';
		
		do {
			var oSource = source;

			// Webkit cleanup
			source = source.replace(/<br class\="webkit-block-placeholder">/gi, "<br />");
			source = source.replace(/<span class="Apple-style-span">(.*)<\/span>/gi, '$1');
			source = source.replace(/ class="Apple-style-span"/gi, '');
			source = source.replace(/<span style="">/gi, '');

			// Remove padded paragraphs
			source = source.replace(/<p>\s*<br ?\/?>\s*<\/p>/gi, '<p>\u00a0</p>');
			source = source.replace(/<p>(&nbsp;|\s)*<\/p>/gi, '<p>\u00a0</p>');
			if (!this.options.semantics){
				source = source.replace(/\s*<br ?\/?>\s*<\/p>/gi, '</p>');
			}

			// Replace improper BRs (only if XHTML : true)
			if (this.options.xhtml){
				source = source.replace(/<br>/gi, "<br />");
			}

			if (this.options.semantics){
				//remove divs from <li>
				if (Browser.Engine.trident){
					source = source.replace(/<li>\s*<div>(.+?)<\/div><\/li>/g, '<li>$1</li>');
				}
				//remove stupid apple divs
				if (Browser.Engine.webkit){
					source = source.replace(/^([\w\s]+.*?)<div>/i, '<p>$1</p><div>');
					source = source.replace(/<div>(.+?)<\/div>/ig, '<p>$1</p>');
				}

				//<p> tags around a list will get moved to after the list
				if (['gecko', 'presto', 'webkit'].contains(Browser.Engine.name)){
					//not working properly in safari?
					source = source.replace(/<p>[\s\n]*(<(?:ul|ol)>.*?<\/(?:ul|ol)>)(.*?)<\/p>/ig, '$1<p>$2</p>');
					source = source.replace(/<\/(ol|ul)>\s*(?!<(?:p|ol|ul|img).*?>)((?:<[^>]*>)?\w.*)$/g, '</$1><p>$2</p>');
				}

				source = source.replace(/<br[^>]*><\/p>/g, '</p>');			//remove <br>'s that end a paragraph here.
				source = source.replace(/<p>\s*(<img[^>]+>)\s*<\/p>/ig, '$1\n'); 	//if a <p> only contains <img>, remove the <p> tags

				//format the source
				source = source.replace(/<p([^>]*)>(.*?)<\/p>(?!\n)/g, '<p$1>$2</p>\n');  	//break after paragraphs
				source = source.replace(/<\/(ul|ol|p)>(?!\n)/g, '</$1>\n'); 			//break after </p></ol></ul> tags
				source = source.replace(/><li>/g, '>\n\t<li>'); 				//break and indent <li>
				source = source.replace(/([^\n])<\/(ol|ul)>/g, '$1\n</$2>');  			//break before </ol></ul> tags
				source = source.replace(/([^\n])<img/ig, '$1\n<img'); 				//move images to their own line
				source = source.replace(/^\s*$/g, '');						//delete empty lines in the source code (not working in opera)
			}

			// Remove leading and trailing BRs
			source = source.replace(/<br ?\/?>$/gi, '');
			source = source.replace(/^<br ?\/?>/gi, '');

			// Remove useless BRs
			source = source.replace(/><br ?\/?>/gi, '>');

			// Remove BRs right before the end of blocks
			source = source.replace(/<br ?\/?>\s*<\/(h1|h2|h3|h4|h5|h6|li|p)/gi, '</$1');

			// Semantic conversion
			source = source.replace(/<span style="font-weight: bold;">(.*)<\/span>/gi, '<strong>$1</strong>');
			source = source.replace(/<span style="font-style: italic;">(.*)<\/span>/gi, '<em>$1</em>');
			source = source.replace(/<b\b[^>]*>(.*?)<\/b[^>]*>/gi, '<strong>$1</strong>');
			source = source.replace(/<i\b[^>]*>(.*?)<\/i[^>]*>/gi, '<em>$1</em>');
			source = source.replace(/<u\b[^>]*>(.*?)<\/u[^>]*>/gi, '<span style="text-decoration: underline;">$1</span>');

			// Replace uppercase element names with lowercase
			source = source.replace(/<[^> ]*/g, function(match){return match.toLowerCase();});

			// Replace uppercase attribute names with lowercase
			source = source.replace(/<[^>]*>/g, function(match){
				   match = match.replace(/ [^=]+=/g, function(match2){return match2.toLowerCase();});
				   return match;
			});

			// Put quotes around unquoted attributes
			source = source.replace(/<[^>]*>/g, function(match){
				   match = match.replace(/( [^=]+=)([^"][^ >]*)/g, "$1\"$2\"");
				   return match;
			});

			//make img tags xhtml compatable
			//           if (this.options.xhtml){
			//                source = source.replace(/(<(?:img|input)[^/>]*)>/g, '$1 />');
			//           }

			//remove double <p> tags and empty <p> tags
			source = source.replace(/<p>(?:\s*)<p>/g, '<p>');
			source = source.replace(/<\/p>\s*<\/p>/g, '</p>');
			source = source.replace(/<p>\W*<\/p>/g, '');

			// Final trim
			source = source.trim();
		}
		while (source != oSource);

		return source;
	}

});

MooEditable.Selection = new Class({

	initialize: function(win){
		this.win = win;
	},

	getSelection: function(){
		this.win.focus();
		return (this.win.getSelection) ? this.win.getSelection() : this.win.document.selection;
	},

	getRange: function(){
		var s = this.getSelection();

		if (!s) return null;

		try {
			return s.rangeCount > 0 ? s.getRangeAt(0) : (s.createRange ? s.createRange() : null);
		} catch(e) {
			// IE bug when used in frameset
			return this.doc.body.createTextRange();
		}
	},

	setRange: function(range){
		if (range.select){
			$try(function(){
				range.select();
			});
		} else {
			var s = this.getSelection();
			if (s.addRange){
				s.removeAllRanges();
				s.addRange(range);
			}
		}
	},

	selectNode: function(node, collapse){
		var r = this.getRange();
		var s = this.getSelection();

		if (r.moveToElementText){
			$try(function(){
				r.moveToElementText(node);
				r.select();
			});
		} else if (s.addRange){
			collapse ? r.selectNodeContents(node) : r.selectNode(node);
			s.removeAllRanges();
			s.addRange(r);
		} else {
			s.setBaseAndExtent(node, 0, node, 1);
		}

		return node;
	},

	isCollapsed: function(){
		var r = this.getRange();
		if (r.item) return false;
		return r.boundingWidth == 0 || this.getSelection().isCollapsed;
	},

	collapse: function(toStart){
		var r = this.getRange();
		var s = this.getSelection();

		if (r.select){
			r.collapse(toStart);
			r.select();
		} else {
			toStart ? s.collapseToStart() : s.collapseToEnd();
		}
	},

	getContent: function(){
		var r = this.getRange();
		var body = new Element('body');

		if (this.isCollapsed()) return '';

		if (r.cloneContents){
			body.appendChild(r.cloneContents());
		} else if ($defined(r.item) || $defined(r.htmlText)){
			body.set('html', r.item ? r.item(0).outerHTML : r.htmlText);
		} else {
			body.set('html', r.toString());
		}

		var content = body.get('html');
		return content;
	},

	getText : function(){
		var r = this.getRange();
		var s = this.getSelection();

		return this.isCollapsed() ? '' : r.text || s.toString();
	},

	getNode: function(){
		var r = this.getRange();

		if (!Browser.Engine.trident){
			var el = null;

			if (r){
				el = r.commonAncestorContainer;

				// Handle selection a image or other control like element such as anchors
				if (!r.collapsed)
					if (r.startContainer == r.endContainer)
						if (r.startOffset - r.endOffset < 2)
							if (r.startContainer.hasChildNodes())
								el = r.startContainer.childNodes[r.startOffset];

				while ($type(el) != 'element') el = el.parentNode;
			}

			return $(el);
		}

		return $(r.item ? r.item(0) : r.parentElement());
	},

	insertContent: function(content){
		if (Browser.Engine.trident){
			var r = this.getRange();
			r.pasteHTML(content);
			r.collapse(false);
			r.select();
		} else {
			this.win.document.execCommand('insertHTML', false, content);
		}
	}

});

MooEditable.UI = {};

MooEditable.UI.Toolbar= new Class({

	Implements: [Events, Options],

	options: {
		/*
		onItemAction: $empty,
		*/
		'class': ''
	},
    
	initialize: function(options){
		this.setOptions(options);
		this.el = new Element('div', {'class': 'mooeditable-ui-toolbar ' + this.options['class']});
		this.items = {};
		this.content = null;
	},
	
	toElement: function(){
		return this.el;
	},
	
	render: function(actions){
		if (this.content){
			this.el.adopt(this.content);
		} else {
			this.content = actions.map(function(action){
				return (action == '|') ? this.addSeparator() : this.addItem(action);
			}.bind(this));
		}
		return this;
	},
	
	addItem: function(action){
		var self = this;
		var act = MooEditable.Actions[action];
		if (!act) return;
		var type = act.type || 'button';
		var options = act.options || {};
		var item = new MooEditable.UI[type.camelCase().capitalize()]($extend(options, {
			name: action,
			'class': action + '-item toolbar-item',
			title: act.title,
			onAction: self.itemAction.bind(self)
		}));
		this.items[action] = item;
		$(item).inject(this.el);
		return item;
	},
	
	getItem: function(action){
		return this.items[action];
	},
	
	addSeparator: function(){
		return new Element('span', {'class': 'toolbar-separator'}).inject(this.el);
	},
	
	itemAction: function(){
		this.fireEvent('itemAction', arguments);
	},

	disable: function(except){
		$each(this.items, function(item){
			(item.name == except) ? item.activate() : item.deactivate().disable();
		});
		return this;
	},

	enable: function(){
		$each(this.items, function(item){
			item.enable();
		});
		return this;
	},
	
	show: function(){
		this.el.setStyle('display', '');
		return this;
	},
	
	hide: function(){
		this.el.setStyle('display', 'none');
		return this;
	}
	
});

MooEditable.UI.Button = new Class({

	Implements: [Events, Options],

	options: {
		/*
		onAction: $empty,
		*/
		title: '',
		name: '',
		text: 'Button',
		'class': '',
		shortcut: '',
		mode: 'icon'
	},

	initialize: function(options){
		this.setOptions(options);
		this.name = this.options.name;
		this.render();
	},
	
	toElement: function(){
		return this.el;
	},
	
	render: function(){
		var self = this;
		var key = (Browser.Platform.mac) ? 'Cmd' : 'Ctrl';
		var shortcut = (this.options.shortcut) ? ' ( ' + key + '+' + this.options.shortcut.toUpperCase() + ' )' : '';
		var text = this.options.title || name;
		var title = text + shortcut;
		this.el = new Element('button', {
			'class': 'mooeditable-ui-button ' + self.options['class'],
			title: title,
			html: '<span class="button-icon"></span><span class="button-text">' + text + '</span>',
			events: {
				click: self.click.bind(self),
				mousedown: function(e){ e.preventDefault(); }
			}
		});
		if (this.options.mode != 'icon') this.el.addClass('mooeditable-ui-button-' + this.options.mode);
		
		this.active = false;
		this.disabled = false;

		// add hover effect for IE
		if (Browser.Engine.trident) this.el.addEvents({
			mouseenter: function(e){ this.addClass('hover'); },
			mouseleave: function(e){ this.removeClass('hover'); }
		});
		
		return this;
	},
	
	click: function(e){
		e.preventDefault();
		if (this.disabled) return;
		this.action(e);
	},
	
	action: function(){
		this.fireEvent('action', [this].concat($A(arguments)));
	},
	
	enable: function(){
		if (this.active) this.el.removeClass('onActive');
		if (!this.disabled) return;
		this.disabled = false;
		this.el.removeClass('disabled').set({
			disabled: false,
			opacity: 1
		});
		return this;
	},
	
	disable: function(){
		if (this.disabled) return;
		this.disabled = true;
		this.el.addClass('disabled').set({
			disabled: true,
			opacity: 0.4
		});
		return this;
	},
	
	activate: function(){
		if (this.disabled) return;
		this.active = true;
		this.el.addClass('onActive');
		return this;
	},
	
	deactivate: function(){
		this.active = false;
		this.el.removeClass('onActive');
		return this;
	}
	
});

MooEditable.UI.Dialog = new Class({

	Implements: [Events, Options],

	options:{
		/*
		onOpen: $empty,
		onClose: $empty,
		*/
		'class': '',
		contentClass: ''
	},

	initialize: function(html, options){
		this.setOptions(options);
		this.html = html;
		
		var self = this;
		this.el = new Element('div', {
			'class': 'mooeditable-ui-dialog ' + self.options['class'],
			html: '<div class="dialog-content ' + self.options.contentClass + '">' + html + '</div>',
			styles: {
				'display': 'none'
			},
			events: {
				click: self.click.bind(self)
			}
		});
	},
	
	toElement: function(){
		return this.el;
	},
	
	click: function(){
		this.fireEvent('click', arguments);
		return this;
	},
	
	open: function(){
		this.el.setStyle('display', '');
		this.fireEvent('open', this);
		return this;
	},
	
	close: function(){
		this.el.setStyle('display', 'none');
		this.fireEvent('close', this);
		return this;
	}

});

MooEditable.UI.AlertDialog = function(alertText){
	if (!alertText) return;
	var html = alertText + ' <button class="dialog-ok-button">OK</button>';
	return new MooEditable.UI.Dialog(html, {
		'class': 'mooeditable-alert-dialog',
		onOpen: function(){
			var button = this.el.getElement('.dialog-ok-button');
			(function(){
				button.focus();
			}).delay(10);
		},
		onClick: function(e){
			e.preventDefault();
			if (e.target.tagName.toLowerCase() != 'button') return;
			if ($(e.target).hasClass('dialog-ok-button')) this.close();
		}
	});
};

MooEditable.UI.PromptDialog = function(questionText, answerText, fn){
	if (!questionText) return;
	var html = '<label class="dialog-label">' + questionText
		+ ' <input type="text" class="text dialog-input" value="' + answerText + '">'
		+ '</label> <button class="dialog-button dialog-ok-button">OK</button>'
		+ '<button class="dialog-button dialog-cancel-button">Cancel</button>';
	return new MooEditable.UI.Dialog(html, {
		'class': 'mooeditable-prompt-dialog',
		onOpen: function(){
			var input = this.el.getElement('.dialog-input');
			(function(){
				input.focus()
				input.select();
			}).delay(10);
		},
		onClick: function(e){
			e.preventDefault();
			if (e.target.tagName.toLowerCase() != 'button') return;
			var button = $(e.target);
			var input = this.el.getElement('.dialog-input');
			if (button.hasClass('dialog-cancel-button')){
				input.set('value', answerText);
				this.close();
			} else if (button.hasClass('dialog-ok-button')){
				var answer = input.get('value');
				input.set('value', answerText);
				this.close();
				if (fn) fn.attempt(answer, this);
			}
		}
	});
};

MooEditable.Actions = new Hash({

	bold: {
		title: 'Bold',
		options: {
			shortcut: 'b'
		},
		states: {
			tags: ['b', 'strong'],
			css: {'font-weight': 'bold'}
		}
	},
	
	italic: {
		title: 'Italic',
		options: {
			shortcut: 'i'
		},
		states: {
			tags: ['i', 'em'],
			css: {'font-style': 'italic'}
		}
	},
	
	underline: {
		title: 'Underline',
		options: {
			shortcut: 'u'
		},
		states: {
			tags: ['u'],
			css: {'text-decoration': 'underline'}
		}
	},
	
	strikethrough: {
		title: 'Strikethrough',
		options: {
			shortcut: 's'
		},
		states: {
			tags: ['s', 'strike'],
			css: {'text-decoration': 'line-through'}
		}
	},
	
	insertunorderedlist: {
		title: 'Unordered List',
		states: {
			tags: ['ul']
		}
	},
	
	insertorderedlist: {
		title: 'Ordered List',
		states: {
			tags: ['ol']
		}
	},
	
	indent: {
		title: 'Indent',
		states: {
			tags: ['blockquote']
		}
	},
	
	outdent: {
		title: 'Outdent'
	},
	
	undo: {
		title: 'Undo',
		options: {
			shortcut: 'z'
		}
	},
	
	redo: {
		title: 'Redo',
		options: {
			shortcut: 'y'
		}
	},
	
	unlink: {
		title: 'Remove Hyperlink'
	},

	createlink: {
		title: 'Add Hyperlink',
		options: {
			shortcut: 'l'
		},
		states: {
			tags: ['a']
		},
		dialogs: {
			alert: MooEditable.UI.AlertDialog.pass('Please select the text you wish to hyperlink.'),
			prompt: function(editor){
				return MooEditable.UI.PromptDialog('Enter URL', 'http://', function(url){
					editor.execute('createlink', false, url.trim());
				});
			}
		},
		command: function(){
			if (this.selection.isCollapsed()){
				this.dialogs.createlink.alert.open();
			} else {
				var text = this.selection.getText();
				var url = /^(https?|ftp|rmtp|mms):\/\/(([A-Z0-9][A-Z0-9_-]*)(\.[A-Z0-9][A-Z0-9_-]*)+)(:(\d+))?\/?/i;
				var prompt = this.dialogs.createlink.prompt;
				if (url.test(text)) prompt.el.getElement('.mooeditable-dialog-input').set('value', text);
				prompt.open();
			}
		}
	},

	urlimage: {
		title: 'Add Image',
		options: {
			shortcut: 'm'
		},
		dialogs: {
			prompt: function(editor){
				return MooEditable.UI.PromptDialog('Enter image URL', 'http://', function(url){
					editor.execute("insertimage", false, url.trim());
				});
			}
		},
		command: function(){
			this.dialogs.urlimage.prompt.open();
		}
	},

	toggleview: {
		title: 'Toggle View',
		command: function(){
			(this.mode == 'textarea') ? this.toolbar.enable() : this.toolbar.disable('toggleview');
			this.toggleView();
		}
	}

});

Element.Properties.mooeditable = {

	set: function(options){
		return this.eliminate('mooeditable').store('mooeditable:options', options);
	},

	get: function(options){
		if (options || !this.retrieve('mooeditable')){
			if (options || !this.retrieve('mooeditable:options')) this.set('mooeditable', options);
			this.store('mooeditable', new MooEditable(this, this.retrieve('mooeditable:options')));
		}
		return this.retrieve('mooeditable');
	}

};

Element.implement({

	mooEditable: function(options){
		return this.get('mooeditable', options);
	}

});



var UserPickerObject = new Class({	
	getOptions: function(){
		return {
			'target' : null,
			'userdata' : '',
			'change' : false,
			'clear' : false,
			'current_value' : false
		};
	},
	
	initialize: function(options){
		this.options = options;
		var up = $$('.USER_PICKER');
		//console.log('UP')
		//console.log(up)
	
		this.picker_open = false;
		this.preview_open = false;

		this.ref = options.ref;
		
		// parse the user data
		var raw_userdata = options.userdata.split(',');
		this.userdata = {};		
		$each(raw_userdata, function(this_user, index) {
			var userdata_parts = this_user.split('|');
			this.userdata[userdata_parts[0]] = userdata_parts;
		}, this);

		// grab the data target
		this.data_target = $(options.target);

		// create the display target
		var display_container = new Element('div').inject(this.data_target, 'after');
		var display_icon = new Element('img', {
			'src' : URL+'site/img/icons/user.png',
			'style' : 'float:left;'
		}).inject(display_container);
		this.display_target = new Element('div', {
			'styles' : {
				'margin-left' : '4px',
				'float' : 'left',
				'text-align': 'left'
			},
			'class' : 'mediumText darkblue bold'
		}).inject(display_container);
		if (options.current_value > 0) {
			this.display_target.set('html', this.userdata[options.current_value][1] + ' ' + this.userdata[options.current_value][2]);
		} else {
			this.display_target.set('html', '(no user selected)'); 
		}


		// add the control buttons
		if (options.change == true) {
			var change_link = new Element('a', {
				'class' : 'bottom_list_control user_picker_control',
				'style' : 'float:left;padding-top:0px;margin-top:0px'
			}).inject(display_container).addEvent('click', this.change.bind(this));
			var change_icon = new Element('img', {
				'src' : URL+'site/img/icons/check.png', 
				'class' : 'user_picker_control'
			}).inject(change_link).addEvent('click', function () {this.getParent().fireEvent('click')});
			var change_text = new Element('span', {
				'html' : ' select user', 
				'class' : 'user_picker_control'
			}).inject(change_link).addEvent('click', function () {this.getParent().fireEvent('click')});
		}
		if (options.clear == true) {
			var clear_link = new Element('a', {
				'class' : 'bottom_list_control user_picker_control',
				'style' : 'float:left;padding-top:0px;margin-top:0px'
			}).inject(display_container).addEvent('click', this.clear.bind(this));
			var change_icon = new Element('img', {
				'src' : URL+'site/img/icons/clear.png', 
				'class' : 'user_picker_control'
			}).inject(clear_link).addEvent('click', function () {this.getParent().fireEvent('click')});
			var change_text = new Element('span', {
				'html' : ' clear', 
				'class' : 'user_picker_control'
			}).inject(clear_link).addEvent('click', function () {this.getParent().fireEvent('click')});			
		}

		// set the data target as hidden
		this.data_target.set('type', 'hidden');
		this.data_target.set('rel', this.ref);

		document.addEvent('mousedown', this.close.bind(this));

		return this;
	},
	

	change : function () {
		if (this.preview_open == true || this.picker_open == true)
			return;

		// flag the picker as open	
		this.preview_open = false;
		this.picker_open = true;

		// grab the position of the target element
		var tPos = this.display_target.getPosition();
		
		// build the picker dialog
		this.container = new Element ('div', {
			'styles' : {
				'background-image' : 'url(site/img/forms/wide_frame.png)',
				'background-repeat' : 'no-repeat',
				'position' : 'absolute',
				'top' : tPos.y,
				'left' : tPos.x,
				'width' : '342px',
				'height' : '250px',
				'opacity' : '0.0',
				'text-align' : 'left',
				'padding-top' : '6px',
				'padding-left' : '8px',
				'overflow' : 'hidden'
			}, 
			'id' : 'user_picker_dialog',
			'class' : 'user_picker_control'
		}).inject($('body'));
		
		var heading = new Element('div', {
			'class' : 'mediumText white bold user_picker_control',
			'html' : 'Select a user'
		}).inject(this.container);
		
		
		var filter_label = new Element('div', {
			'class' : 'mediumText black bold user_picker_control',
			'html' : 'Type a name, address, or email address to filter',
			'styles' : {
				'margin-top' : '12px'
			}
		}).inject(this.container);
		var search_box = new Element('input', {
			'type' : 'textfield',
			'styles' : {
				'float' : 'none',
				'width' : '250px',
				'margin' : 'auto'
			},
			'class' : 'user_picker_control'
		}).inject(this.container).addEvent('keydown', this.parse_filter.bind(this))
		search_box.addEvent('click', this.check_preview.bind(this))

		var results_heading = new Element('div', {
			'class' : 'mediumText black bold user_picker_control',
			'html' : 'Results',
			'styles' : {
				'margin-top' : '8px',
				'border-bottom' : '1px solid black'
			}
		}).inject(this.container);		
		this.results_container = new Element('div', {
			'class' : 'mediumText black bold user_picker_control',
			'styles' : {
				'margin-top' : '8px',
				'height' : '146px',
				'overflow' : 'auto',
				'float' : 'left',
				'width' : '340px'
			},
			'html' : 'Type 3 more characters to begin filtering'
		}).inject(this.container);

		this.container.fade('in');
		return;
	},
	
	
	parse_filter : function (e) {
		//console.log(this)
		//console.log('picker open:'+this.picker_open);
		//console.log(this.ref)
		if (this.picker_open != true || this.preview_open == true)
			return;
		//console.log('working...')
		// get the target filter textbox
		var filter_ele = e.target;
		//console.log(filter_ele)
		// determine if this keystroke changes the length of the filter term
		var new_length = filter_ele.value.length;
		if (e.key == 'backspace')
			new_length--;
		else if ((e.code > 64 && e.code < 91) || e.code == 32)
			new_length++;
		else
			return true;

		if (new_length < 0)
			new_length = 0;
		
		// the input isn't long enough, ask for more
		if (new_length < 3) {	
			html = 'Type ' + (3 - new_length) + ' more characters to begin filtering';
			this.results_container.set('html', html);
			return true;
		}
		
		// clear the results container
		this.results_container.set('html', '');
		
		// determine what the lookup field is
		lookup_string = filter_ele.value.toLowerCase()
		lup = lookup_string.split(' ');			
		if (lup.length > 1) {
			if (IsNumeric(lup[0])) {
				// searching address
				search_type = 'address';
			} else {
				// searching first and last name
				search_type = 'name';
			}
		}
		if (IsNumeric(lookup_string)) {
			search_type = 'address';
		}
		lup = lookup_string.split('@');			
		if (lup.length > 1) {
			// searching email
			search_type = 'email';
		}
		
		if (typeof search_type == 'undefined') {
			search_type = 'both';
		}

		// loop the results, show 10, overflow the rest with a message
		add_cnt = 0;
		overflow_cnt = 0;
		for (index in this.userdata) {
			this_user = this.userdata[index];
			// make sure we've got enough data to list it
			if (typeof this_user[0] == 'undefined' || typeof this_user[1] == 'undefined' || typeof this_user[2] == 'undefined' || typeof this_user[3] == 'undefined' || typeof this_user[4] == 'undefined')
				continue;

			// add me flag determines if this is added to the results
			add_me = false;
			switch (search_type) {
				default:
				case 'both':
					term = this_user[1].toLowerCase() + ' ' + this_user[2].toLowerCase() + ' ' + this_user[3].toLowerCase();
					if (term.search(lookup_string) > -1) {
						add_me = true;
					}
					break;
				case 'name':
					full_name = this_user[1].toLowerCase() + ' ' + this_user[2].toLowerCase();
					lup = lookup_string.split(' ');
					if (lup.length > 1) {
						if (full_name.search(lup[0]) > -1 && full_name.search(lup[1]) > -1) {
							add_me = true;
						}
					} else {
						if (full_name.search(lookup_string) > -1) {
							add_me = true;
						}
					}				
					break;
				case 'address':
					term = this_user[3].toLowerCase();
					if (term.search(lookup_string) > -1) {
						add_me = true;
					}
					break;
				case 'email':
					term = this_user[4].toLowerCase();
					if (term.search(lookup_string) > -1) {
						add_me = true;
					}
					break;
			}
			
			// if add_me is true, check the overflow
			// as long as we're under the overflow, add the result
			// otherwise, increment overflow
			if (add_me == true) {
				if (add_cnt > 6) {
					overflow_cnt++;
				} else {
					this.add_row_to_lookup_results(this_user);
					add_cnt++;
				}
			} // end :: if checking for add_me
			
		} // end :: for looping users
	
		// if there is overflow, make a message to let the user know
		if (overflow_cnt > 0) {
			var overflow_notice = new Element('div', {
				'html' : '... and ' + overflow_cnt + ' more',
				'class' : 'bold red user_picker_control'
			}).inject(this.results_container);
		}
		
	},
	
	
	add_row_to_lookup_results : function (user_data) {
		//console.log(user_data)
		if (this.picker_open != true || this.preview_open == true)
			return;

		var one_result = new Element('div', {
			'styles' : {
				'border-bottom' : '1px dotted grey',
				'padding-top' : '3px',
				'padding-bottom' : '3px'
			},
			'class' : 'user_picker_control'
		});
		
		var user_img = new Element('img', {
			'src' : 'site/img/icons/user.png',
			'class' : 'user_picker_control'
		}).inject(one_result);
		var user_name = new Element('span', {
			'html' : (user_data[0] < 1000 ? '[STAFF] ' : '') + user_data[1] + ' ' + user_data[2],
			'class' : 'bold mediumText darkblue user_picker_control'
		}).inject(one_result);
		var select_img = new Element('img', {
			'src' : 'site/img/icons/check.png',
			'rel' : user_data[0],
			'styles' : {
				'float' : 'right'
			},
			'class' : 'user_picker_control'
		}).inject(one_result).addEvent('click', this.select.bind(this));;
		var preview_img = new Element('img', {
			'src' : 'site/img/icons/view.png',
			'rel' : user_data[0],
			'styles' : {
				'float' : 'right'
			},
			'class' : 'user_picker_control'
		}).inject(one_result).addEvent('click', this.preview.bind(this));
		one_result.inject(this.results_container);	
		var cb = new Element('div', {
			'class' : 'clearBoth'
		}).inject(one_result);
		var member_type = new Element('div', {
			'html' : (user_data[0] < 1000 ? 'Staff ' : '') + user_data[8],
			'class' : 'smallText user_picker_control',
			'styles' : {
				'float' : 'left'
			}			
		}).inject(one_result);
		var cb = new Element('div', {
			'class' : 'clearBoth'
		}).inject(one_result);
	},
	
	
	close : function (e, force) {
		if (this.preview_open == true || this.picker_open == true) {
			if ((typeof e == 'undefined' || typeof e.target == 'undefined') && typeof force == 'undefined') {
				return;
			}
			click_outside = false;
			if (typeof e != 'undefined' && typeof e.target != 'undefined' && !e.target.hasClass('user_picker_control')) {
				click_outside = true;
			}
			
			if (click_outside || force) {
				this.container.dispose();
				if (typeof this.preview_container != 'undefined')
					this.preview_container.dispose();
				//console.log('close has fired');
				this.picker_open = false;
				this.preview_open = false;
			}
		}
	},

	check_preview : function () {
		if (this.preview_open == true)
			this.close_preview();
	},
	close_preview : function () {
		if (this.preview_open == false)
			return;
		var tweenObj = new Fx.Tween(this.results_container, {
			'link' : 'chain',
			'duration' : 'short'		
		}).addEvent('chainComplete', this.remove_preview.bind(this));
		tweenObj.start('width', '340px');
		this.preview_open = false;
		this.picker_open = true;
	},
	remove_preview : function () {
		this.preview_container.dispose();
		this.preview_open = false;
		this.picker_open = true;		
	},
	preview : function (e) {
		if (this.picker_open == false || this.preview_open == true)
			return;

		this.preview_open = true;
		this.picker_open = false;
		
		var user_id = e.target.get('rel');
		
		var user_data = this.userdata[user_id];

		var br = new Element('br').addClass('user_picker_control');

		this.preview_container = new Element('div', {
			'class' : 'mediumText black user_picker_control',
			'styles' : {
				'margin-top' : '8px',
				'height' : '146px',
				'overflow' : 'hidden',
				'float' : 'left',
				'width' : '340px'
			}
		});
		
		
		var picture_div = new Element('div', {
			'styles' : {
				'float' : 'left'
			}, 
			'class' : 'user_picker_control'
		}).inject(this.preview_container);
		var pic = new Element('img', {
			'src' : URL+'site/img/users/' + user_data[9],
			'class' : 'user_picker_control',
			'styles' : {
				'height': '90px',
				'width': '90px'
			}
		}).inject(picture_div);
		
		var details_div = new Element('div', {
			'styles' : {
				'float' : 'left',
				'margin-left' : '6px'
			}, 
			'class' : 'user_picker_control'
		}).inject(this.preview_container);

		var name_span = new Element('span', {
			'class' : 'bold largeText user_picker_control',
			'html' : user_data[1] + ' ' + user_data[2]
		}).inject(details_div);
		br.clone().inject(details_div)
		
		var membership_span = new Element('span', {
			'html' : '<b>Member Type:</b>' + (user_data[0] < 1000 ? 'Staff ' : '') + user_data[8],
			'class' : 'user_picker_control'	
		}).inject(details_div);
		br.clone().inject(details_div)

		var address_span = new Element('span', {
			'html' : user_data[3] + '<br />' + user_data[5] + ', ' + user_data[6] + ' ' + user_data[7] + '<br />' + user_data[10],
			'class' : 'user_picker_control'
		}).inject(details_div);
		
		br.clone().addClass('clearBoth').inject(this.preview_container);		
		br.clone().inject(this.preview_container);


		var control_container = new Element('p').inject(this.preview_container);

		var select_link = new Element('a', {
			'class' : 'bottom_list_control user_picker_control',
			'rel' : user_data[0]
		}).inject(control_container).addEvent('click', this.select.bind(this));
		var select_icon = new Element('img', {
			'src' : URL+'site/img/icons/check.png', 
			'class' : 'user_picker_control',
			'rel' : user_data[0]
		}).inject(select_link).addEvent('click', function () {this.getParent().fireEvent('click')});
		var select_text = new Element('span', {
			'html' : ' select user', 
			'class' : 'user_picker_control',
			'rel' : user_data[0]
		}).inject(select_link).addEvent('click', function () {this.getParent().fireEvent('click')});

		var clear_link = new Element('a', {
			'class' : 'bottom_list_control user_picker_control'
		}).inject(control_container).addEvent('click', this.close_preview.bind(this));
		var clear_icon = new Element('img', {
			'src' : URL+'site/img/icons/clear.png', 
			'class' : 'user_picker_control'
		}).inject(clear_link).addEvent('click', this.close_preview.bind(this));
		var clear_text = new Element('span', {
			'html' : ' close preview', 
			'class' : 'user_picker_control'
		}).inject(clear_link).addEvent('click', this.close_preview.bind(this));
				

		this.preview_container.inject(this.container);
		
		
		// slide out the results
		this.results_container.tween('width', '0');		

		
	},
	
	select : function (e) {
		//console.log('SELECT - picker open:'+this.picker_open)
		if (!this.picker_open && !this.preview_open)
			return;

		//console.log('SELECT - e:')
		//console.log(e)
		if (typeof e == 'undefined')
			return ;
		var user_id = e.target.get('rel');
		//console.log('SELECT - e rel:' + user_id)
		this.display_target.set('html', this.userdata[user_id][1] + ' ' + this.userdata[user_id][2])
		this.data_target.set('value', this.userdata[user_id][0])
		this.close(false, true);
		
		if ($chk(this.options.onChange)) {
			if (typeof this.options.onChange != 'function')
				this.options.onChange = eval(this.options.onChange);
			this.options.onChange(this);
		}
		
	},
	
	update_display : function () {
		if (this.data_target.value > 0)
			this.display_target.set('html', this.userdata[this.data_target.value][1] + ' ' + this.userdata[this.data_target.value][2])
		else
			this.display_target.set('html', '(no user selected)'); 
	},
	
	clear : function () {
		this.display_target.set('html', '(no user selected)');
		this.data_target.set('value', '0');
	}
});


/* END site/form
*************************************************************/

/**************************************************************
 BEGIN site/paginating_table                                           */
//
// new PaginatingTable( 'my_table', 'ul_for_paginating', {
//   per_page: 10,     // How many rows per page?
//   current_page: 1,  // What page to start on when initialized
//   offset_el: false, // What dom element to stick the offset in
//   cutoff_el: false, // What dom element to stick the cutoff in
//   details: false    // Do we have hidden/collapsable rows?
// });
//
// The above were the defaults.  You could also pass an array of paginators
// instead of just one.
//
// Requires mootools Class, Array, Function, Element, Element.Selectors,
// Element.Event, and you should probably get Window.DomReady if you're smart.
//

var PaginatingTable = new Class({

  Implements: Options,
  
  options: {
    per_page: 10,
    current_page: 1,
    offset_el: false,
    cutoff_el: false,
    details: false
  },
  
  initialize: function( table, ids, options ) {
    this.table = $(table);
    this.setOptions(options);
    
    this.tbody = this.table.getElement('tbody');
    
    if (this.options.offset_el)
      this.options.offset_el = $(this.options.offset_el);
    if (this.options.cutoff_el)
      this.options.cutoff_el = $(this.options.cutoff_el);

    this.paginators = ($type(ids) == 'array') ? ids.map($) : [$(ids)];

    if (this.options.details) {
      this.options.per_page = this.options.per_page * 2
    }

    this.update_pages();
  },

  update_pages: function(){
    this.pages = Math.ceil( this.tbody.getChildren().length / this.options.per_page );
    this.create_pagination();
    this.to_page( 1 );
  },

  to_page: function( page_num ) {
    page_num = page_num.toInt();
    if (page_num > this.pages || page_num < 1) return;
    this.current_page = page_num;
    this.low_limit  = this.options.per_page * ( this.current_page - 1 );
    this.high_limit = this.options.per_page * this.current_page;
    var trs = this.tbody.getChildren();
    if (trs.length < this.high_limit) this.high_limit = trs.length;
    for (var i = 0, j = trs.length; i < j; i++) {
      trs[i].style.display = (this.low_limit  <= i && this.high_limit > i) ? '' : 'none';
    }
    this.paginators.each(function(paginator){
      var as = paginator.getElements('a').removeClass('currentPage');
      as[this.current_page].addClass('currentPage');
    }, this);
    if (this.options.offset_el)
      this.options.offset_el.set('text', Math.ceil( this.low_limit / ( this.options.details ? 2 : 1 ) + 1 ) );
    if (this.options.cutoff_el)
      this.options.cutoff_el.set('text', ( this.high_limit / ( this.options.details ? 2 : 1 ) ) );
  },

  to_next_page: function() {
    this.to_page( this.current_page + 1 );
  },

  to_prev_page: function() {
    this.to_page( this.current_page - 1 );
  },

  create_pagination: function() {
    this.paginators.each(function(paginator){
      paginator.empty();
      this.create_pagination_node( '&#171;', function(evt){
        var evt = new Event( evt );
        this.to_prev_page();
        evt.stop();
        return false;
      }).injectInside( paginator );
      for (var page=1; page <= this.pages; page++){
        this.create_pagination_node( page, function(evt){
          var evt = new Event( evt );
          this.to_page( evt.target.get( 'text' ) );
          evt.stop();
          return false;
        }).injectInside( paginator );  
      }
      this.create_pagination_node( '&#187;', function(evt){
        var evt = new Event( evt );
        this.to_next_page();
        evt.stop();
        return false;
      }).injectInside( paginator );
    }.bind( this ));
  },

  create_pagination_node: function( text, evt ) {
    var span = new Element( 'span' ).set( 'html', text );
    if (text == '&#171;'){
      var a = new Element( 'a', { 'href': '#', 'class': 'previous-page' }).addEvent( 'click', evt.bind( this ) );
    } else if (text == '&#187;'){
      var a = new Element( 'a', { 'href': '#', 'class': 'next-page' }).addEvent( 'click', evt.bind( this ) );
    } else {
      var a = new Element( 'a', { 'href': '#'}).addEvent( 'click', evt.bind( this ) );
    }
    var li   = new Element( 'li' );
    span.injectInside( a.injectInside( li ) );
    return li;
  }

});


/* END site/paginating_table
*************************************************************/

/**************************************************************
 BEGIN site/sorting_table                                           */
//
// new SortingTable( 'my_table', {
//   zebra: true,                        // Stripe the table, also on initialize
//   details: false,                     // Has details every other row
//   paginator: false,                   // Pass a paginator object
//   onSorted: function(){},             // Callback to run after sort
//   dont_sort_class: 'nosort',          // Class name on th's that don't sort
//   forward_sort_class: 'forward_sort', // Class applied to forward sort th's
//   reverse_sort_class: 'reverse_sort'  // Class applied to reverse sort th's
// });
//
// The above were the defaults.  The regexes in load_conversions test a cell
// begin sorted for a match, then use that conversion for all elements on that
// column.
//
// Requires mootools Class, Array, Function, Element, Element.Selectors,
// Element.Event, and you should probably get Window.DomReady if you're smart.
//

var SortingTable = new Class({

  Implements: Options,
  
  options: {
    zebra: true,
    details: false,
    paginator: false,
    onSorted: $empty,
    dont_sort_class: 'nosort',
    forward_sort_class: 'forward_sort',
    reverse_sort_class: 'reverse_sort'
  },

  initialize: function( table, options ) {
    this.table = $(table);
    this.filter = $(table+'_filter_text');
    this.filter_col = $(table+'_filter_col');
    
    this.setOptions(options);
    
    this.tbody = this.table.getElement('tbody');
    if (this.options.zebra) {
      SortingTable.stripe_table(this.tbody.getChildren());
    }

	if (this.table.getElement('thead')) {
    this.headers = this.table.getElement('thead').getElements('th');
    this.headers.each(function( header, index ) {
      if (header.hasClass( this.options.dont_sort_class )) { return }
      header.store( 'column', index )
      header.setStyle('cursor', 'pointer')
      header.addEvent( 'mousedown', function(evt){
        this.sort_by_header( evt.target );
        if ( this.options.paginator) this.options.paginator.to_page( 1 );
      }.bind( this ) );
    }, this);}

	if (this.filter) {
	this.filter.addEvent( 'keyup', function(evt){
		this.search_in_rows(evt.target);
	}.bind( this ) );}

    this.load_conversions();
  },

  search_in_rows: function (ele) {
 		
 		// check for target 
 		if (this.filter_col.value.length < 1) {
		 	return;
		 }
 		
	    var rows = [];
	    
	    var before = this.tbody.getPrevious();
	    this.tbody.dispose();
	        
	    var trs = this.tbody.getChildren();
	    while ( row = trs.shift() ) {
	      row = { row: row.dispose() };
	      if ( this.options.details ) {
	        row.detail = trs.shift().dispose();
	      }
	      rows.unshift( row );
	    }

	    var index = 0;
	    var added_this_row = false;
	    while ( row = rows.shift() ) {
	    	added_this_row = false;
			var children = row.row.getChildren();
			for (i in children) {
				if (typeof children[i].get == 'function') {
					var this_col_name = children[i].get('rel');
					if (this.filter_col.value != this_col_name)
						continue;
					var this_col_data = children[i].get('html');

					this.tbody.appendChild(row.row);
					if (this_col_data.contains(this.filter.value)) {
						row.row.setStyle('display', '');
						added_this_row = true;
						row.row.set('rel', '');
						continue;
					} else {
						row.row.setStyle('display', 'none');
						row.row.set('rel', 'hide');
					}
				}
			}
	    	
	      //this.tbody.appendChild(row.row);
			if (added_this_row) {
		      if (row.detail) this.tbody.appendChild(row.detail);
		      if ( this.options.zebra ) {
		        row.row.className = row.row.className.replace( this.removeAltClassRe, '$1').clean();
		        if (row.detail)
		          row.detail.className = row.detail.className.replace( this.removeAltClassRe, '$1').clean();
		        if (index % 2) {
		          row.row.addClass( 'alt' ); 
		          if (row.detail) row.detail.addClass( 'alt' );
		        }
		      }
		      index++;
		    }
	    }
	   this.tbody.inject(before, 'after');
	   //this.fireEvent('sorted', this); 
  		this.options.paginator.update_pages();
  		return;
  },

  sort_by_header: function( header ){

    var rows = [];
    
    var before = this.tbody.getPrevious();
    this.tbody.dispose();
        
    var trs = this.tbody.getChildren();
    while ( row = trs.shift() ) {
      row = { row: row.dispose() };
      if ( this.options.details ) {
        row.detail = trs.shift().dispose();
      }
      rows.unshift( row );
    }
    
    if ( this.sort_column >= 0 &&
         this.sort_column == header.retrieve('column') ) {
      // They were pulled off in reverse
      if ( header.hasClass( this.options.reverse_sort_class ) ) {
        header.removeClass( this.options.reverse_sort_class );
        header.addClass( this.options.forward_sort_class );
      } else {
        header.removeClass( this.options.forward_sort_class );
        header.addClass( this.options.reverse_sort_class );
      }
    } else {
      this.headers.each(function(h){
        h.removeClass( this.options.forward_sort_class );
        h.removeClass( this.options.reverse_sort_class );
      }, this);
      this.sort_column = header.retrieve('column');
      if (header.retrieve('conversion_function')) {
        this.conversion_matcher = header.retrieve('conversion_matcher');
        this.conversion_function = header.retrieve('conversion_function');
      } else {
        this.conversion_function = false;
        rows.some(function(row){
          var to_match = $(row.row.getElementsByTagName('td')[this.sort_column]).get('text');
          if (to_match == '') return false;
          this.conversions.some(function(conversion){
            if (conversion.matcher.test( to_match )){
              this.conversion_matcher = conversion.matcher;
              this.conversion_function = conversion.conversion_function;
              return true;
            }
            return false;
          }, this);
          return !!(this.conversion_function);
        }, this);
        header.store('conversion_function', this.conversion_function );
        header.store('conversion_matcher', this.conversion_matcher );
      }
      header.addClass( this.options.forward_sort_class );
      rows.each(function(row){
        var compare_value = this.conversion_function( row );
        row.toString = function(){
          return compare_value;
        };
      }, this);
      rows.sort();
    }

    var index = 0;
    while ( row = rows.shift() ) {
      this.tbody.appendChild(row.row);
      if (row.detail) this.tbody.appendChild(row.detail);
      if ( this.options.zebra ) {
        row.row.className = row.row.className.replace( this.removeAltClassRe, '$1').clean();
        if (row.detail)
          row.detail.className = row.detail.className.replace( this.removeAltClassRe, '$1').clean();
        if (index % 2) {
          row.row.addClass( 'alt' ); 
          if (row.detail) row.detail.addClass( 'alt' );
        }
      }
      index++;
    }
   this.tbody.inject(before, 'after');
   //this.fireEvent('sorted', this);
  },

  load_conversions: function() {
    this.conversions = $A([
      // 1.75 MB, 301 GB, 34 KB, 8 TB
      { matcher: /([0-9.]{1,8}).*([KMGT]{1})B/,
        conversion_function: function( row ) {
          var cell = $(row.row.getElementsByTagName('td')[this.sort_column]).get('text');
          cell = this.conversion_matcher.exec( cell );
          if (!cell) { return '0' }
          if (cell[2] == 'M') {
            sort_val = '1';
          } else if (cell[2] == 'G') {
            sort_val = '2';
          } else if (cell[2] == 'T') {
            sort_val = '3';
          } else {
            sort_val = '0';
          }
          var i = cell[1].indexOf('.')
          if (i == -1) {
            post = '00'
          } else {
            var dec = cell[1].split('.');
            cell[1] = dec[0];
            post = dec[1].concat('00'.substr(0,2-dec[1].length));
          }
          return sort_val.concat('00000000'.substr(0,2-cell[1].length).concat(cell[1])).concat(post);
        }
      },
      // 1 day ago, 4 days ago, 38 years ago, 1 month ago
      { matcher: /(\d{1,2}) (.{3,6}) ago/,
        conversion_function: function( row ) {
          var cell = $(row.row.getElementsByTagName('td')[this.sort_column]).get('text');
          cell = this.conversion_matcher.exec( cell );
          if (!cell) { return '0' }
          var sort_val;
          if (cell[2].indexOf('month') != -1) {
            sort_val = '1';
          } else if (cell[2].indexOf('year') != -1) {
            sort_val = '2';
          } else {
            sort_val = '0';
          }
          return sort_val.concat('00'.substr(0,2-cell[1].length).concat(cell[1]));
        }
      },
      // Currency
      { matcher: /((\d{1}\.\d{2}|\d{2}\.\d{2}|\d{3}\.\d{2}|\d{4}\.\d{2}|\d{5}\.\d{2}|\d{6}\.\d{2}))/,
        conversion_function: function( row ) {
          var cell = $(row.row.getElementsByTagName('td')[this.sort_column]).get('text');
          cell = cell.replace(/[^\d]/g, "");
          return '00000000000000000000000000000000'.substr(0,32-cell.length).concat(cell);
        }
      },
      // YYYY-MM-DD, YYYY-m-d
      { matcher: /(\d{4})-(\d{1,2})-(\d{1,2})/,
        conversion_function: function( row ) {
          var cell = $(row.row.getElementsByTagName('td')[this.sort_column]).get('text');
          cell = this.conversion_matcher.exec( cell );
          return cell[1]+
                 '00'.substr(0,2-cell[2].length).concat(cell[2])+
                 '00'.substr(0,2-cell[3].length).concat(cell[3]);
        }
      },
      // Numbers
      { matcher: /^\d+$/,
        conversion_function: function( row ) {
          var cell = $(row.row.getElementsByTagName('td')[this.sort_column]).get('text');
          return '00000000000000000000000000000000'.substr(0,32-cell.length).concat(cell);
        }
      },
      // Fallback 
      { matcher: /.*/,
        conversion_function: function( row ) {
          return $(row.row.getElementsByTagName('td')[this.sort_column]).get('text');
        }
      }
    ]);
  }

});

SortingTable.removeAltClassRe = new RegExp('(^|\\s)alt(?:\\s|$)');
SortingTable.implement({ removeAltClassRe: SortingTable.removeAltClassRe });

SortingTable.stripe_table = function ( tr_elements  ) {
  var counter = 0;
  tr_elements.each( function( tr ) {
    if ( !tr.hasClass('collapsed') ) counter++;
    tr.className = tr.className.replace( this.removeAltClassRe, '$1').clean();
    if (counter % 2) tr.addClass( 'alt' );
  });
}


/* END site/sorting_table
*************************************************************/