/*************************************************************
	Class:		elReady
	Version:	1.0
	Author:		Samuel Birch
*************************************************************/
var elReady = new Class({
	
	initialize: function(el, func){
		if($$(el)[0]){
			func();
		}else{
			this.timer = this.check.periodical(10, this, [el, func]);
		}
		
		window.addEvent('domready', function(){
			$clear(this.timer);
			func();
		}.bind(this))
	},
	
	check: function(el, func){
		if($$(el)[0]){
			$clear(this.timer);
			func();
		}
	}
	
});
/************************************************************/


/**************************************************************

	Script		: Swiff
	Version		: 1.0
	Authors		: Samuel Birch
	Desc		: Adds version checking to the Swiff class

**************************************************************/

Swiff = new Class({

	Extends: Swiff,

	options: {
		version: 8,
		containerClass: '',
		onInject: $empty
	},

	initialize: function(path, options){
		this.setOptions(options);
		if (Browser.Plugins.Flash.version >= this.options.version) {
			this.parent(path, options);
			this.options.onInject.attempt($(this.options.container));
			$(this.options.container).addClass(this.options.containerClass);
		}else{
			return false;
		}
	}

});

Swiff.CallBacks = {};

Swiff.remote = function(obj, fn){
	var rs = obj.CallFunction('<invoke name="' + fn + '" returntype="javascript">' + __flash__argumentsToXML(arguments, 2) + '</invoke>');
	return eval(rs);
};

/*************************************************************/



/**************************************************************

	Script		: Text Resize Detector
	Version		: 1.2
	Authors		: Samuel birch
	Desc		: Captures when the text is resized.
	Licence		: Open Source MIT Licence

**************************************************************/

var textResizeDetector = new Class({
	getOptions: function(){
		return {
			delay: 200
		};
	},
	
	initialize: function(options){
		this.setOptions(this.getOptions(), options);
		
		this.funcs = [];
		
		this.element = new Element('div').set({
			'id': 'textResizeController_'+$time(),
			'styles': {
				'position': 'absolute',
				//'left': '-9999px',
				'top': 0,
				'width': '1em',
				'height': '20em',
				'background': 'red'
			},
			'text': 'a'
		}).inject(document.body);
		this.oldSize = this.element.getCoordinates().height;
		this.defaultSize = this.oldSize;
		//console.log(this.defaultSize/16); //20
		
		this.start();
	},
	
	add: function(func){
		this.funcs.push(func);
	},
	
	defaultCheck: function(){
		if(this.defaultSize/16 != 20){
			this.defaultSize = 20*16;
			//this.options._onChange(this.defaultSize, this.oldSize);
			this.funcs.each(function(el,i){
				el.attempt(this.defaultSize, this.oldSize);
			}, this);
		}
	},
	
	check: function(){
		var newSize = this.element.getCoordinates().height;
		if(this.oldSize != newSize){
			//this.options._onChange(this.defaultSize, newSize, this.oldSize);
			this.funcs.each(function(el,i){
				el.attempt(this.defaultSize, newSize, this.oldSize);
			}, this);
			this.oldSize = newSize;
		}
	},
	
	start: function(){
		this.timer = this.check.periodical(this.options.delay, this);
	},
	
	stop: function(){
		$clear(this.timer);
	}
});
textResizeDetector.implement(new Events);
textResizeDetector.implement(new Options);


/*************************************************************/



/**************************************************************

	Script		: uTRD - Universal Text Resize Detector
	Version		: 1.0
	Authors		: Samuel birch
	Desc		: Captures when the text is resized.
	Licence		: Open Source MIT Licence

**************************************************************/

var uTRD = new Class({
	
	Implements: [Options,Events],
	
	getOptions: function(){
		return {
			delay: 200,
			base: 16
		};
	},
	
	initialize: function(options){
		this.setOptions(this.getOptions(), options);
		this.functions = [];
		this.element = new Element('div', {
			'id': 'uTRD_Controller_'+$time(),
			'styles': {
				'position': 'absolute',
				'left': '-1000em',
				'top': 0,
				'width': '1em',
				'height': '20em'
			}
		}).inject($(document.body));
		
		this.oldSize = this.element.getCoordinates().height;
		this.defaultSize = this.oldSize;
		this.checking = false;
	},
	
	start: function(){
		this.checking = true;
		this.timer = this.check.periodical(this.options.delay, this);
	},
	
	stop: function(){
		$clear(this.timer);
	},
	
	check: function(){
		var newSize = this.element.getCoordinates().height;
		if(this.oldSize != newSize){
			var size = 20*this.options.base;
			var percent = ((newSize / size) * 100).toInt();

			this.functions.each(function(el,i){
				el.attempt([percent]);
			}, this);
			this.oldSize = newSize;
		}
	},
	
	defaultCheck: function(){
		if((this.defaultSize/this.options.base).toInt() != 20){
			this.defaultSize = 20*this.options.base;
			var percent = ((this.oldSize / this.defaultSize) * 100).toInt();
			this.functions.each(function(el,i){
				el.attempt([percent, true]);
			}, this);
		}
	},
	
	add: function(func){
		this.functions.push(func);
		this.defaultCheck();
		if(!this.checking){
			this.start();
		}
	}
	
});

/*************************************************************/



/*************************************************************
	Class:		background image resizer
	Version:	1.0
	Author:		Samuel Birch
*************************************************************/
var bgResizer = new Class({
	
	Implements: [Options,Events],
	
	getOptions: function(){
		return {
			resizer: null
		};
	},
	
	initialize: function(elements, options){
		this.setOptions(this.getOptions(), options);
		this.elements = $$(elements);
		
		this.options.resizer.add(this.resize.bind(this));
	},
	
	resize: function(oldSize, newSize){
		var percent = ((newSize / oldSize) * 100).toInt();
		this.elements.each(function(el){
			var src = el.getStyle('backgroundImage');
				if(src.indexOf('?') > 0){
					end = src.indexOf('?');
				}else{
					end = src.length;
				}
				src = src.substring(0, end);
				src = src.replace('url(','');
				src = src.replace(')','');
				src = src.replace('"','');
				src = src.replace('"','');
				
			el.setStyle('backgroundImage', 'url('+src+'?p='+percent+')');
		});
		(function(){
			new Element('div', {
				'styles': {
					'position': 'absolute',
					'top': 0,
					'left': 0,
					'width': '10',
					'height': '10'
				},
				'html': ''
			}).inject(document.body).destroy();
		}).delay(250)
	}
});
/************************************************************/


/*************************************************************
	Class:		flash text
	Version:	1.0
	Author:		Samuel Birch
*************************************************************/
var flashText = new Class({
	
	Implements: [Options,Events],
	
	getOptions: function(){
		return {
			font: '/_common/swf/custom.swf',
			version: 8,
			resizer: null
		};
	},
	
	initialize: function(elements, options){
		this.setOptions(this.getOptions(), options);
		this.elements = $$(elements);
		this.properties = [];
		
		if(Browser.Plugins.Flash.version >= this.options.version){
			
			$(document.body).addClass('flashText');
			
			this.elements.each(function(el, i){
				//el.addClass('flashText');
				
				var size = el.getStyle('fontSize');
				if(size.contains('em')){
					size = size.toFloat() * 16;
				}else{
					size = size.toFloat();
				}
				
				var props = {
					'colour': el.getStyle('color').replace('#',''),
					'size': size,
					'text': el.get('html').clean()
				};
				this.properties.push(props);
				
				this.addFlash(el, props);
				
			}, this);
			
			this.options.resizer.add(this.update.bind(this));
		}
		
	},
	
	addFlash: function(el, props){
		var obj = new Swiff(this.options.font, {
			container: el,
			version: this.options.version,
			width: '100%',
			height: '100%',//size.height+10,
			params: {
				wMode: 'transparent'
			},
			vars: {
				text: props.text,
				colour: props.colour,
				size: props.size
			},
			properties: {
				style: 'outline:none;'
			}
		});
	},
	
	update: function(defaultSize, newSize, oldSize){
		var percent = ((newSize / oldSize) * 100).toInt();
		if(oldSize){
			this.elements.each(function(el, i){
				el.getChildren().destroy();
				var props = this.properties[i];
					props.size = ((percent/100)*props.size);
				this.addFlash(el, props);
			}, this);
		}
	}
});
/************************************************************/

/*
Script: Fx.Slide.js
	Effect to slide an element in and out of view.

License:
	MIT-style license.
*/

Fx.Slide = new Class({

	Extends: Fx,

	options: {
		mode: 'vertical'
	},

	initialize: function(element, options){
		this.addEvent('complete', function(){
			this.open = (this.wrapper['offset' + this.layout.capitalize()] != 0);
			if (this.open && Browser.Engine.webkit419) this.element.dispose().inject(this.wrapper);
		}, true);
		this.element = this.subject = $(element);
		this.parent(options);
		var wrapper = this.element.retrieve('wrapper');
		this.wrapper = wrapper || new Element('div', {
			styles: $extend(this.element.getStyles('margin', 'position'), {'overflow': 'hidden'})
		}).wraps(this.element);
		this.element.store('wrapper', this.wrapper).setStyle('margin', 0);
		this.now = [];
		this.open = true;
	},

	vertical: function(){
		this.margin = 'margin-top';
		this.layout = 'height';
		this.offset = this.element.offsetHeight;
	},

	horizontal: function(){
		this.margin = 'margin-left';
		this.layout = 'width';
		this.offset = this.element.offsetWidth;
	},

	set: function(now){
		this.element.setStyle(this.margin, now[0]);
		this.wrapper.setStyle(this.layout, now[1]);
		return this;
	},

	compute: function(from, to, delta){
		var now = [];
		var x = 2;
		x.times(function(i){
			now[i] = Fx.compute(from[i], to[i], delta);
		});
		return now;
	},

	start: function(how, mode){
		if (!this.check(arguments.callee, how, mode)) return this;
		this[mode || this.options.mode]();
		var margin = this.element.getStyle(this.margin).toInt();
		var layout = this.wrapper.getStyle(this.layout).toInt();
		var caseIn = [[margin, layout], [0, this.offset]];
		var caseOut = [[margin, layout], [-this.offset, 0]];
		var start;
		switch (how){
			case 'in': start = caseIn; break;
			case 'out': start = caseOut; break;
			case 'toggle': start = (this.wrapper['offset' + this.layout.capitalize()] == 0) ? caseIn : caseOut;
		}
		return this.parent(start[0], start[1]);
	},

	slideIn: function(mode){
		return this.start('in', mode);
	},

	slideOut: function(mode){
		return this.start('out', mode);
	},

	hide: function(mode){
		this[mode || this.options.mode]();
		this.open = false;
		return this.set([-this.offset, 0]);
	},

	show: function(mode){
		this[mode || this.options.mode]();
		this.open = true;
		return this.set([0, this.offset]);
	},

	toggle: function(mode){
		return this.start('toggle', mode);
	}

});

Element.Properties.slide = {

	set: function(options){
		var slide = this.retrieve('slide');
		if (slide) slide.cancel();
		return this.eliminate('slide').store('slide:options', $extend({link: 'cancel'}, options));
	},
	
	get: function(options){
		if (options || !this.retrieve('slide')){
			if (options || !this.retrieve('slide:options')) this.set('slide', options);
			this.store('slide', new Fx.Slide(this, this.retrieve('slide:options')));
		}
		return this.retrieve('slide');
	}

};

Element.implement({

	slide: function(how, mode){
		how = how || 'toggle';
		var slide = this.get('slide'), toggle;
		switch (how){
			case 'hide': slide.hide(mode); break;
			case 'show': slide.show(mode); break;
			case 'toggle':
				var flag = this.retrieve('slide:flag', slide.open);
				slide[(flag) ? 'slideOut' : 'slideIn'](mode);
				this.store('slide:flag', !flag);
				toggle = true;
			break;
			default: slide.start(how, mode);
		}
		if (!toggle) this.eliminate('slide:flag');
		return this;
	}

});

/*************************************************************/
/* Calendar functions
/*************************************************************/

// Calendar: a Javascript class for Mootools that adds accessible and unobtrusive date pickers to your form elements <http://electricprism.com/aeron/calendar>
// Calendar RC4.1, Copyright (c) 2007 Aeron Glemann <http://electricprism.com/aeron>, MIT Style License.

var Calendar = new Class({	

	options: {
		blocked: [], // blocked dates 
		classes: [], // ['calendar', 'prev', 'next', 'month', 'year', 'today', 'invalid', 'valid', 'inactive', 'active', 'hover', 'hilite']
		days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], // days of the week starting at sunday
		direction: 0, // -1 past, 0 past + future, 1 future
		draggable: false,
		months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
		navigation: 1, // 0 = no nav; 1 = single nav for month; 2 = dual nav for month and year
		offset: 0, // first day of the week: 0 = sunday, 1 = monday, etc..
		onHideStart: Class.empty,
		onHideComplete: Class.empty,
		onShowStart: Class.empty,
		onShowComplete: Class.empty,
		pad: 1, // padding between multiple calendars
		tweak: {x: 0, y: 0} // tweak calendar positioning
	},

	// initialize: calendar constructor
	// @param obj (obj) a js object containing the form elements and format strings { id: 'format', id: 'format' etc }
	// @param props (obj) optional properties

	initialize: function(obj, options) {
		// basic error checking
		if (!obj) { return false; }

		this.setOptions(options);

		// create our classes array
		var keys = ['calendar', 'prev', 'next', 'month', 'year', 'today', 'invalid', 'valid', 'inactive', 'active', 'hover', 'hilite'];

		var values = keys.map(function(key, i) {
			if (this.options.classes[i]) {
				if (this.options.classes[i].length) { key = this.options.classes[i]; }
			}
			return key;
		}, this);

		this.classes = values.associate(keys);

		// create cal element with css styles required for proper cal functioning
		this.calendar = new Element('div', { 
			'styles': { left: '-1000px', opacity: 0, position: 'absolute', top: '-1000px', zIndex: 1000 }
		}).addClass(this.classes.calendar).injectInside(document.body);

		this.calendar.coord = this.calendar.getCoordinates();

		// iex 6 needs a transparent iframe underneath the calendar in order to not allow select elements to render through
		if (window.ie6) {
			this.iframe = new Element('iframe', { 
				'styles': { height: this.calendar.coord.height + 'px', left: '-1000px', position: 'absolute', top: '-1000px', width: this.calendar.coord.width + 'px', zIndex: 999 }
			}).injectInside(document.body);
			this.iframe.style.filter = 'progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0)';
		}

		// initialize fade method
	//	this.fx = this.calendar.tween('opacity', { 
		this.fx = new Fx.Tween(this.calendar, {
			onStart: function() { 
				if (this.calendar.getStyle('opacity') == 0) { // show
					if (window.ie6) { this.iframe.setStyle('display', 'block'); }
					this.calendar.setStyle('display', 'block');
					this.fireEvent('onShowStart', this.element);
				}
				else { // hide
					this.fireEvent('onHideStart', this.element);
				}
			}.bind(this),
			onComplete: function() { 
				if (this.calendar.getStyle('opacity') == 0) { // hidden
					this.calendar.setStyle('display', 'none');
					if (window.ie6) { this.iframe.setStyle('display', 'none'); }
					this.fireEvent('onHideComplete', this.element);
				}
				else { // shown
					this.fireEvent('onShowComplete', this.element);
				}
			}.bind(this)
		});

		// initialize drag method
		if (window.Drag && this.options.draggable) {
			this.drag = new Drag.Move(this.calendar, { 
				onDrag: function() {
					if (window.ie6) { this.iframe.setStyles({ left: this.calendar.style.left, top: this.calendar.style.top }); } 
				}.bind(this) 
			}); 
		}
		
		// create calendars array
		this.calendars = [];

		var id = 0;
		var d = new Date(); // today

		d.setDate(d.getDate() + this.options.direction.toInt()); // correct today for directional offset

		for (var i in obj) {
			var cal = { 
				button: new Element('button', { 'type': 'button' }),
				el: $(i),
				els: [],
				id: id++,
				month: d.getMonth(),
				visible: false,
				year: d.getFullYear()
			};

			// fix for bad element (naughty, naughty element!)
			if (!this.element(i, obj[i], cal)) { continue; }
			
			cal.el.addClass(this.classes.calendar);

			// create cal button
			cal.button.addClass(this.classes.calendar).addEvent('click', function(cal) { this.toggle(cal); }.pass(cal, this)).injectAfter(cal.el);

			// read in default value
			cal.val = this.read(cal);

			$extend(cal, this.bounds(cal)); // abs bounds of calendar

			$extend(cal, this.values(cal)); // valid days, months, years

			this.rebuild(cal);

			this.calendars.push(cal); // add to cals array		
		}	
	},


	// blocked: returns an array of blocked days for the month / year
	// @param cal (obj)
	// @returns blocked days (array)

	blocked: function(cal) {
		var blocked = [];
		var offset = new Date(cal.year, cal.month, 1).getDay(); // day of the week (offset)
		var last = new Date(cal.year, cal.month + 1, 0).getDate(); // last day of this month
		
		this.options.blocked.each(function(date) {
			var values = date.split(' ');

			for (var i = 0; i < 3; i++) { 
				if (!values[i]) { values[i] = '*'; } // make sure blocked date contains values for at least d, m and y
				values[i] = values[i].contains(',') ? values[i].split(',') : new Array(values[i]); // split multiple values
			}

			if (values[2].contains(cal.year + '') || values[2].contains('*')) {
				if (values[1].contains(cal.month + 1 + '') || values[1].contains('*')) {
					values[0].each(function(val) { // if blocked value indicates this month / year
						if (val > 0) { blocked.push(val.toInt()); } // add date to blocked array
					});

					if (values[3]) { // optional value for day of week
						values[3] = values[3].contains(',') ? values[3].split(',') : new Array(values[3]);

						for (var i = 0; i < last; i++) {
								var day = (i + offset) % 7;
	
								if (values[3].contains(day + '')) { 
									blocked.push(i + 1); // add every date that corresponds to the blocked day of the week to the blocked array
								}
						}
					}
				}
			}
		}, this);

		return blocked;
	},


	// bounds: returns the start / end bounds of the calendar
	// @param cal (obj)
	// @returns obj	

	bounds: function(cal) {
		// 1. first we assume the calendar has no bounds (or a thousand years in either direction)
		
		// by default the calendar will accept a millennium in either direction
		var start = new Date(1000, 0, 1); // jan 1, 1000
		var end = new Date(2999, 11, 31); // dec 31, 2999

		// 2. but if the cal is one directional we adjust accordingly
		var date = new Date().getDate() + this.options.direction.toInt();

		if (this.options.direction > 0) {
			start = new Date();
			start.setDate(date + this.options.pad * cal.id);
		}
		
		if (this.options.direction < 0) {
			end = new Date();
			end.setDate(date - this.options.pad * (this.calendars.length - cal.id - 1));
		}

		// 3. then we can further filter the limits by using the pre-existing values in the selects
		cal.els.each(function(el) {	
			if (el.get('tag') == 'select') {		
				if (el.format.test('(y|Y)')) { // search for a year select
					var years = [];

					el.getChildren().each(function(option) { // get options
						var values = this.unformat(option.value, el.format);
	
						if (!years.contains(values[0])) { years.push(values[0]); } // add to years array
					}, this);
	
					years.sort(this.sort);
			
					if (years[0] > start.getFullYear()) { 
						d = new Date(years[0], start.getMonth() + 1, 0); // last day of new month
					
						if (start.getDate() > d.getDate()) { start.setDate(d.getDate()); }
	
						start.setYear(years[0]); 
					}
					
					if (years.getLast() < end.getFullYear()) { 
						d = new Date(years.getLast(), end.getMonth() + 1, 0); // last day of new month
					
						if (end.getDate() > d.getDate()) { end.setDate(d.getDate()); }
	
						end.setYear(years.getLast());
					}		
				}
	
				if (el.format.test('(F|m|M|n)')) { // search for a month select
					var months_start = [];
					var months_end = [];

					el.getChildren().each(function(option) { // get options
						var values = this.unformat(option.value, el.format);
	
						if ($type(values[0]) != 'number' || values[0] == years[0]) { // if it's a year / month combo for curr year, or simply a month select
							if (!months_start.contains(values[1])) { months_start.push(values[1]); } // add to months array
						}
	
						if ($type(values[0]) != 'number' || values[0] == years.getLast()) { // if it's a year / month combo for curr year, or simply a month select
							if (!months_end.contains(values[1])) { months_end.push(values[1]); } // add to months array
						}
					}, this);
	
					months_start.sort(this.sort);
					months_end.sort(this.sort);
					
					if (months_start[0] > start.getMonth()) { 
						d = new Date(start.getFullYear(), months_start[0] + 1, 0); // last day of new month
					
						if (start.getDate() > d.getDate()) { start.setDate(d.getDate()); }
	
						start.setMonth(months_start[0]); 
					}
					
					if (months_end.getLast() < end.getMonth()) { 
						d = new Date(start.getFullYear(), months_end.getLast() + 1, 0); // last day of new month
					
						if (end.getDate() > d.getDate()) { end.setDate(d.getDate()); }
	
						end.setMonth(months_end.getLast());
					}		
				}
			}
		}, this);
		
		return { 'start': start, 'end': end };
	},


	// caption: returns the caption element with header and navigation
	// @param cal (obj)
	// @returns caption (element)

	caption: function(cal) {
		// start by assuming navigation is allowed
		var navigation = {
			prev: { 'month': true, 'year': true },
			next: { 'month': true, 'year': true }
		};
		
		// if we're in an out of bounds year
		if (cal.year == cal.start.getFullYear()) { 
			navigation.prev.year = false; 
			if (cal.month == cal.start.getMonth() && this.options.navigation == 1) { 
				navigation.prev.month = false;
			}		
		}		
		if (cal.year == cal.end.getFullYear()) { 
			navigation.next.year = false; 
			if (cal.month == cal.end.getMonth() && this.options.navigation == 1) { 
				navigation.next.month = false;
			}
		}

		// special case of improved navigation but months array with only 1 month we can disable all month navigation
		if ($type(cal.months) == 'array') {
			if (cal.months.length == 1 && this.options.navigation == 2) {
				navigation.prev.month = navigation.next.month = false;
			}
		}

		var caption = new Element('caption');

		var prev = new Element('a').addClass(this.classes.prev).appendText('\x3c'); // <		
		var next = new Element('a').addClass(this.classes.next).appendText('\x3e'); // >

		if (this.options.navigation == 2) {
			var month = new Element('span').addClass(this.classes.month).injectInside(caption);
			
			if (navigation.prev.month) { prev.clone().addEvent('click', function(cal) { this.navigate(cal, 'm', -1); }.pass(cal, this)).injectInside(month); }
			
			month.adopt(new Element('span').appendText(this.options.months[cal.month]));

			if (navigation.next.month) { next.clone().addEvent('click', function(cal) { this.navigate(cal, 'm', 1); }.pass(cal, this)).injectInside(month); }

			var year = new Element('span').addClass(this.classes.year).injectInside(caption);

			if (navigation.prev.year) { prev.clone().addEvent('click', function(cal) { this.navigate(cal, 'y', -1); }.pass(cal, this)).injectInside(year); }
			
			year.adopt(new Element('span').appendText(cal.year));

			if (navigation.next.year) { next.clone().addEvent('click', function(cal) { this.navigate(cal, 'y', 1); }.pass(cal, this)).injectInside(year); }
		}
		else { // 1 or 0
			if (navigation.prev.month && this.options.navigation) { prev.clone().addEvent('click', function(cal) { this.navigate(cal, 'm', -1); }.pass(cal, this)).injectInside(caption); }

			caption.adopt(new Element('span').addClass(this.classes.month).appendText(this.options.months[cal.month]));
			
			caption.adopt(new Element('span').addClass(this.classes.year).appendText(cal.year));
			
			if (navigation.next.month && this.options.navigation) { next.clone().addEvent('click', function(cal) { this.navigate(cal, 'm', 1); }.pass(cal, this)).injectInside(caption); }

		}

		return caption;
	},


	// changed: run when a select value is changed
	// @param cal (obj)

	changed: function(cal) {
		cal.val = this.read(cal); // update calendar val from inputs	

		$extend(cal, this.values(cal)); // update bounds - based on curr month

		this.rebuild(cal); // rebuild days select

		if (!cal.val) { return; } // in case the same date was clicked the cal has no set date we should exit		

		if (cal.val.getDate() < cal.days[0]) { cal.val.setDate(cal.days[0]); }
		if (cal.val.getDate() > cal.days.getLast()) { cal.val.setDate(cal.days.getLast()); }
		
		cal.els.each(function(el) {	// then we can set the value to the field
			el.value = this.format(cal.val, el.format); 		
		}, this);
		
		this.check(cal); // checks other cals

		this.calendars.each(function(kal) { // update cal graphic if visible
			if (kal.visible) { this.display(kal); }
		}, this);
	},


	// check: checks other calendars to make sure no overlapping values
	// @param cal (obj)

	check: function(cal) {
		this.calendars.each(function(kal, i) {
			if (kal.val) { // if calendar has value set
				var change = false;
			
				if (i < cal.id) { // preceding calendar
					var bound = new Date(Date.parse(cal.val));
					
					bound.setDate(bound.getDate() - (this.options.pad * (cal.id - i)));

					if (bound < kal.val) { change = true; }
				}
				if (i > cal.id) { // following calendar
					var bound = new Date(Date.parse(cal.val));
					
					bound.setDate(bound.getDate() + (this.options.pad * (i - cal.id)));
					
					if (bound > kal.val) { change = true; }
				}

				if (change) {
					if (kal.start > bound) { bound = kal.start; }
					if (kal.end < bound) { bound = kal.end; }

					kal.month = bound.getMonth();
					kal.year = bound.getFullYear();		

					$extend(kal, this.values(kal));			

					// TODO - IN THE CASE OF SELECT MOVE TO NEAREST VALID VALUE
					// IN THE CASE OF INPUT DISABLE

					// if new date is not valid better unset cal value
					// otherwise it would mean incrementally checking to find the nearest valid date which could be months / years away
					kal.val = kal.days.contains(bound.getDate()) ? bound : null;

					this.write(kal);

					if (kal.visible) { this.display(kal); } // update cal graphic if visible
				}
			}
		}, this);
	},
	

	// clicked: run when a valid day is clicked in the calendar
	// @param cal (obj)

	clicked: function(td, day, cal) {
		cal.val = (this.value(cal) == day) ? null : new Date(cal.year, cal.month, day); // set new value - if same then disable

		this.write(cal); 

		// ok - in the special case that it's all selects and there's always a date no matter what (at least as far as the form is concerned)
		// we can't let the calendar undo a date selection - it's just not possible!!
		if (!cal.val) { cal.val = this.read(cal); }

		if (cal.val) {
			this.check(cal); // checks other cals						
			this.toggle(cal); // hide cal
		} 
		else { // remove active class and replace with valid
			td.addClass(this.classes.valid);
			td.removeClass(this.classes.active);
		}
	},
	

	// display: create calendar element
	// @param cal (obj)

	display: function(cal) {
		// 1. header and navigation
		this.calendar.empty(); // init div

		this.calendar.className = this.classes.calendar + ' ' + this.options.months[cal.month].toLowerCase();

		var div = new Element('div').injectInside(this.calendar); // a wrapper div to help correct browser css problems with the caption element

		var table = new Element('table').injectInside(div).adopt(this.caption(cal));
				
		// 2. day names		
		var thead = new Element('thead').injectInside(table);

		var tr = new Element('tr').injectInside(thead);
		
		for (var i = 0; i <= 6; i++) {
			var th = this.options.days[(i + this.options.offset) % 7];
			
			tr.adopt(new Element('th', { 'title': th }).appendText(th.substr(0, 1)));
		}

		// 3. day numbers
		var tbody = new Element('tbody').injectInside(table);
		var tr = new Element('tr').injectInside(tbody);

		var d = new Date(cal.year, cal.month, 1);
		var offset = ((d.getDay() - this.options.offset) + 7) % 7; // day of the week (offset)
		var last = new Date(cal.year, cal.month + 1, 0).getDate(); // last day of this month
		var prev = new Date(cal.year, cal.month, 0).getDate(); // last day of previous month
		var active = this.value(cal); // active date (if set and within curr month)
		var valid = cal.days; // valid days for curr month
		var inactive = []; // active dates set by other calendars
		var hilited = [];
		this.calendars.each(function(kal, i) {
			if (kal != cal && kal.val) {
				if (cal.year == kal.val.getFullYear() && cal.month == kal.val.getMonth()) { inactive.push(kal.val.getDate()); }

				if (cal.val) {
					for (var day = 1; day <= last; day++) {
						d.setDate(day);
						
						if ((i < cal.id && d > kal.val && d < cal.val) || (i > cal.id && d > cal.val && d < kal.val)) { 
							if (!hilited.contains(day)) { hilited.push(day); }
						}
					}
				}
			}
		}, this);
		var d = new Date();
		var today = new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime(); // today obv 
		
		for (var i = 1; i < 43; i++) { // 1 to 42 (6 x 7 or 6 weeks)
			if ((i - 1) % 7 == 0) { tr = new Element('tr').injectInside(tbody); } // each week is it's own table row

			var td = new Element('td').injectInside(tr);
						
			var day = i - offset;
			var date = new Date(cal.year, cal.month, day);
			
			var cls = '';
			
			if (day === active) { cls = this.classes.active; } // active
			else if (inactive.contains(day)) { cls = this.classes.inactive; } // inactive
			else if (valid.contains(day)) { cls = this.classes.valid; } // valid
			else if (day >= 1 && day <= last) { cls = this.classes.invalid; } // invalid

			if (date.getTime() == today) { cls = cls + ' ' + this.classes.today; } // adds class for today

			if (hilited.contains(day)) { cls = cls + ' ' + this.classes.hilite; } // adds class if hilited

			td.addClass(cls);

			if (valid.contains(day)) { // if it's a valid - clickable - day we add interaction
				td.setProperty('title', this.format(date, 'D M jS Y'));
				
				td.addEvents({
					'click': function(td, day, cal) { 
						this.clicked(td, day, cal); 
					}.pass([td, day, cal], this),
					'mouseover': function(td, cls) { 
						td.addClass(cls); 
					}.pass([td, this.classes.hover]),
					'mouseout': function(td, cls) { 
						td.removeClass(cls); 
					}.pass([td, this.classes.hover])
				});
			}

			// pad calendar with last days of prev month and first days of next month
			if (day < 1) { day = prev + day; }
			else if (day > last) { day = day - last; }

			td.appendText(day);
		}
	},


	// element: helper function
	// @param el (string) element id
	// @param f (string) format string
	// @param cal (obj)

	element: function(el, f, cal) {
		if ($type(f) == 'object') { // in the case of multiple inputs per calendar
			for (var i in f) { 
				if (!this.element(i, f[i], cal)) { return false; }		
			}
			
			return true;
		}

		el = $(el);

		if (!el) { return false; }
		
		el.format = f;
		
		if (el.get('tag') == 'select') { // select elements allow the user to manually set the date via select option
			//el.addEvent('change', function(cal) { this.changed(cal); }.pass(cal, this));
		}
		else { // input (type text) elements restrict the user to only setting the date via the calendar
			//el.readOnly = true;
			//el.addEvent('focus', function(cal) { this.toggle(cal); }.pass(cal, this));
		}

		cal.els.push(el);

		return true;
	},


	// format: formats a date object according to passed in instructions
	// @param date (obj)
	// @param f (string) any combination of punctuation / separators and d, j, D, l, S, m, n, F, M, y, Y
	// @returns string

	format: function(date, f) {
		var g = '';
		
		if (date) {
			var d = date.getDate(); // 1 - 31
			var day = this.options.days[date.getDay()]; // Sunday - Saturday
			var m = date.getMonth() + 1; // 1 - 12
			var month = this.options.months[date.getMonth()]; // January - December
			var y = date.getFullYear() + ''; // 19xx - 20xx
			
			for (var i = 0; i < f.length; i++) {
				var c = f.charAt(i); // format char
				
				switch(c) {
					// year cases
					case 'y': // xx - xx
						y = y.substr(2);
					case 'Y': // 19xx - 20xx
						g += y;
						break;
	
					// month cases
					case 'm': // 01 - 12
						if (m < 10) { m = '0' + m; }
					case 'n': // 1 - 12
						g += m;
						break;
	
					case 'M': // Jan - Dec
						month = month.substr(0, 3);
					case 'F': // January - December
						g += month;
						break;
	
					// day cases
					case 'd': // 01 - 31
						if (d < 10) { d = '0' + d; }
					case 'j': // 1 - 31
						g += d;
						break;
	
					case 'D': // Sun - Sat
						day = day.substr(0, 3);
					case 'l': // Sunday - Saturday
						g += day;
						break;
	
					case 'S': // st, nd, rd or th (works well with j)
						if (d % 10 == 1 && d != '11') { g += 'st'; }
						else if (d % 10 == 2 && d != '12') { g += 'nd'; }
						else if (d % 10 == 3 && d != '13') { g += 'rd'; }
						else { g += 'th'; }
						break;
	
					default:
						g += c;
				}
			}
		}

	  return g; //  return format with values replaced
	},


	// navigate: calendar navigation
	// @param cal (obj)
	// @param type (str) m or y for month or year
	// @param n (int) + or - for next or prev

	navigate: function(cal, type, n) {
		switch (type) {
			case 'm': // month
					if ($type(cal.months) == 'array') {
						var i = cal.months.indexOf(cal.month) + n; // index of current month
						
						if (i < 0 || i == cal.months.length) { // out of range
							if (this.options.navigation == 1) { // if type 1 nav we'll need to increment the year
								this.navigate(cal, 'y', n);		
							}
		
							i = (i < 0) ? cal.months.length - 1 : 0;
						}

						cal.month = cal.months[i];
					}
					else { 
						var i = cal.month + n;
		
						if (i < 0 || i == 12) {
							if (this.options.navigation == 1) {
								this.navigate(cal, 'y', n);	
							}
		
							i = (i < 0) ? 11 : 0;
						}
						
						cal.month = i;
					}		
					break;

				case 'y': // year
					if ($type(cal.years) == 'array') {
						var i = cal.years.indexOf(cal.year) + n;

						cal.year = cal.years[i]; 
					}
					else { 
						cal.year += n;
					}						
					break;		
		}

		$extend(cal, this.values(cal));

		if ($type(cal.months) == 'array') { // if the calendar has a months select
			var i = cal.months.indexOf(cal.month); // and make sure the curr months exists for the new year

			if (i < 0) { cal.month = cal.months[0]; } // otherwise we'll reset the month
		}


		this.display(cal);
	},


	// read: compiles cal value based on array of inputs passed in
	// @param cal (obj)
	// @returns date (obj) or (null)

	read: function(cal) {
		var arr = [null, null, null];

		cal.els.each(function(el) {
			// returns an array which may contain empty values
			var values = this.unformat(el.value, el.format);
			
			values.each(function(val, i) { 
				if ($type(val) == 'number') { arr[i] = val; }
			}); 
		}, this);

		// we can update the cals month and year values
		if ($type(arr[0]) == 'number') { cal.year = arr[0]; }
		if ($type(arr[1]) == 'number') { cal.month = arr[1]; }

		var val = null;

		if (arr.every(function(i) { return $type(i) == 'number'; })) { // if valid date
			var last = new Date(arr[0], arr[1] + 1, 0).getDate(); // last day of month

			if (arr[2] > last) { arr[2] = last; } // make sure we stay within the month (ex in case default day of select is 31 and month is feb)
			
			val = new Date(arr[0], arr[1], arr[2]);
		}

		return (cal.val == val) ? null : val; // if new date matches old return null (same date clicked twice = disable)
	},

	
	// rebuild: rebuilds days + months selects
	// @param cal (obj)

	rebuild: function(cal) {
		cal.els.each(function(el) {			
			/*
			if (el.get('tag') == 'select' && el.format.test('^(F|m|M|n)$')) { // special case for months-only select
				if (!cal.options) { cal.options = el.clone(); } // clone a copy of months select
			
				var val = (cal.val) ? cal.val.getMonth() : el.value.toInt();

				el.empty(); // initialize select

				cal.months.each(function(month) {
					// create an option element
					var option = new Element('option', {
						'selected': (val == month),
						'value': this.format(new Date(1, month, 1), el.format);
					}).appendText(day).injectInside(el);
				}, this);
			}
			*/

			if (el.get('tag') == 'select' && el.format.test('^(d|j)$')) { // special case for days-only select
				var d = this.value(cal);

				if (!d) { d = el.value.toInt(); } // if the calendar doesn't have a set value, try to use value from select

				el.empty(); // initialize select

				cal.days.each(function(day) {
					// create an option element
					var option = new Element('option', {
						'selected': (d == day),
						'value': ((el.format == 'd' && day < 10) ? '0' + day : day)
					}).appendText(day).injectInside(el);
				}, this);
			}
		}, this); 
	},


	// sort: helper function for numerical sorting

	sort: function(a, b) {
		return a - b;
	},


	// toggle: show / hide calendar 
	// @param cal (obj)

	toggle: function(cal) {
		document.removeEvent('mousedown', this.fn); // always remove the current mousedown script first
			
		if (cal.visible) { // simply hide curr cal						
			cal.visible = false;
			cal.button.removeClass(this.classes.active); // active
			
			this.fx.start('opacity', 1, 0);
		}
		else { // otherwise show (may have to hide others)
			// hide cal on out-of-bounds click
			this.fn = function(e, cal) { 
				var e = new Event(e);
			
				var el = e.target;

				var stop = false;
				
				while (el != document.body && el.nodeType == 1) {
					if (el == this.calendar) { stop = true; }
					this.calendars.each(function(kal) {
						if (kal.button == el || kal.els.contains(el)) { stop = true; }
					});

					if (stop) { 
						e.stop();
						return false;
					}
					else { el = el.parentNode; }
				}
				
				this.toggle(cal);
			}.create({ 'arguments': cal, 'bind': this, 'event': true });				

			document.addEvent('mousedown', this.fn);

			this.calendars.each(function(kal) {
				if (kal == cal) {
					kal.visible = true;
					kal.button.addClass(this.classes.active); // css c-icon-active
				}
				else {
					kal.visible = false;
					kal.button.removeClass(this.classes.active); // css c-icon-active
				}
			}, this);
			
			var size = window.getScrollSize();
			
			var coord = cal.button.getCoordinates();

			var x = coord.right + this.options.tweak.x;
			var y = coord.top + this.options.tweak.y;

			// make sure the calendar doesn't open off screen (does't work in safari!?)
			if (x + this.calendar.coord.width > size.x) { x -= (x + this.calendar.coord.width - size.x); }
			if (y + this.calendar.coord.height > size.y) { y -= (y + this.calendar.coord.height - size.y); }
			
			this.calendar.setStyles({ left: x + 'px', top: y + 'px' });

			if (window.ie6) { this.iframe.setStyles({ left: x + 'px', top: y + 'px' }); }

			this.display(cal);
			//console.log(this.fx)
			this.fx.start('opacity', 0, 1);
		}
	},


	// unformat: takes a value from an input and parses the d, m and y elements
	// @param val (string)
	// @param f (string) any combination of punctuation / separators and d, j, D, l, S, m, n, F, M, y, Y
	// @returns array
	
	unformat: function(val, f) {
		f = f.escapeRegExp();
		
		var re = {
			d: '([0-9]{2})',
			j: '([0-9]{1,2})',
			D: '(' + this.options.days.map(function(day) { return day.substr(0, 3); }).join('|') + ')',					
			l: '(' + this.options.days.join('|') + ')',
			S: '(st|nd|rd|th)',
			F: '(' + this.options.months.join('|') + ')',
			m: '([0-9]{2})',
			M: '(' + this.options.months.map(function(month) { return month.substr(0, 3); }).join('|') + ')',					
			n: '([0-9]{1,2})',
			Y: '([0-9]{4})',
			y: '([0-9]{2})'
		}

		var arr = []; // array of indexes

		var g = '';

		// convert our format string to regexp
		for (var i = 0; i < f.length; i++) {
			var c = f.charAt(i);
			
			if (re[c]) {
				arr.push(c);

				g += re[c];
			}
			else {
				g += c;
			}
		}

		// match against date
		var matches = val.match('^' + g + '$');
		
		var dates = new Array(3);

		if (matches) {
			matches = matches.slice(1); // remove first match which is the date

			arr.each(function(c, i) {
				i = matches[i];
				
				switch(c) {
					// year cases
					case 'y':
						i = '19' + i; // 2 digit year assumes 19th century (same as JS)
					case 'Y':
						dates[0] = i.toInt();
						break;

					// month cases
					case 'F':
						i = i.substr(0, 3);
					case 'M':
						i = this.options.months.map(function(month) { return month.substr(0, 3); }).indexOf(i) + 1;
					case 'm':
					case 'n':
						dates[1] = i.toInt() - 1;
						break;

					// day cases
					case 'd':
					case 'j':
						dates[2] = i.toInt();
						break;
				}
			}, this);
		}

		return dates;
	},


	// value: returns day value of calendar if set
	// @param cal (obj)
	// @returns day (int) or null

	value: function(cal) {
		var day = null;

		if (cal.val) {
			if (cal.year == cal.val.getFullYear() && cal.month == cal.val.getMonth()) { day = cal.val.getDate(); }
		}

		return day;
	},
	

	// values: returns the years, months (for curr year) and days (for curr month and year) for the calendar
	// @param cal (obj)
	// @returns obj	

	values: function(cal) {
		var years, months, days;

		cal.els.each(function(el) {	
			if (el.get('tag') == 'select') {		
				if (el.format.test('(y|Y)')) { // search for a year select
					years = [];

					el.getChildren().each(function(option) { // get options
						var values = this.unformat(option.value, el.format);
	
						if (!years.contains(values[0])) { years.push(values[0]); } // add to years array
					}, this);
	
					years.sort(this.sort);
				}
	
				if (el.format.test('(F|m|M|n)')) { // search for a month select
					months = []; // 0 - 11 should be

					el.getChildren().each(function(option) { // get options
						var values = this.unformat(option.value, el.format);
	
						if ($type(values[0]) != 'number' || values[0] == cal.year) { // if it's a year / month combo for curr year, or simply a month select
							if (!months.contains(values[1])) { months.push(values[1]); } // add to months array
						}
					}, this);
	
					months.sort(this.sort);
				}
				
				if (el.format.test('(d|j)') && !el.format.test('^(d|j)$')) { // search for a day select, but NOT a days only select
					days = []; // 1 - 31
					
					el.getChildren().each(function(option) { // get options
						var values = this.unformat(option.value, el.format);

						// in the special case of days we dont want the value if its a days only select
						// otherwise that will screw up the options rebuilding
						// we will take the values if they are exact dates though
						if (values[0] == cal.year && values[1] == cal.month) {
							if (!days.contains(values[2])) { days.push(values[2]); } // add to days array
						}
					}, this);
				}
			}
		}, this);
		
		// we start with what would be the first and last days were there no restrictions
		var first = 1;
		var last = new Date(cal.year, cal.month + 1, 0).getDate(); // last day of the month
		
		// if we're in an out of bounds year
		if (cal.year == cal.start.getFullYear()) {
			// in the special case of improved navigation but no months array, we'll need to construct one
			if (months == null && this.options.navigation == 2) {
				months = [];
				
				for (var i = 0; i < 12; i ++) { 
					if (i >= cal.start.getMonth()) { months.push(i); } 
				}
			}
			
			// if we're in an out of bounds month
			if (cal.month == cal.start.getMonth()) { 
				first = cal.start.getDate(); // first day equals day of bound
			}
		}		
		if (cal.year == cal.end.getFullYear()) {
			// in the special case of improved navigation but no months array, we'll need to construct one
			if (months == null && this.options.navigation == 2) {
				months = [];
				
				for (var i = 0; i < 12; i ++) { 
					if (i <= cal.end.getMonth()) { months.push(i); } 
				}
			}

			if (cal.month == cal.end.getMonth()) { 
				last = cal.end.getDate(); // last day equals day of bound
			}
		}

		// let's get our invalid days
		var blocked = this.blocked(cal);

		// finally we can prepare all the valid days in a neat little array
		if ($type(days) == 'array') { // somewhere there was a days select
			days = days.filter(function(day) {
				if (day >= first && day <= last && !blocked.contains(day)) { return day; }
			});
		}
		else { // no days select we'll need to construct a valid days array
			days = [];
			
			for (var i = first; i <= last; i++) { 
				if (!blocked.contains(i)) { days.push(i); }
			}
		}		

		days.sort(this.sort); // sorting our days will give us first and last of month

		return { 'days': days, 'months': months, 'years': years };
	},


	// write: sets calendars value to form elements
	// @param cal (obj)

	write: function(cal) {
		this.rebuild(cal);	 // in the case of options, we'll need to make sure we have the correct number of days available
		
		cal.els.each(function(el) {	// then we can set the value to the field
			el.value = this.format(cal.val, el.format); 		
		}, this);
	}
});

Calendar.implement(new Events, new Options);

/*************************************************************/
/* End of Calendar functions
/*************************************************************/




Fx.Elements = new Class({

	Extends: Fx.CSS,

	initialize: function(elements, options){
		this.elements = this.subject = $$(elements);
		this.parent(options);
	},

	compute: function(from, to, delta){
		var now = {};
		for (var i in from){
			var iFrom = from[i], iTo = to[i], iNow = now[i] = {};
			for (var p in iFrom) iNow[p] = this.parent(iFrom[p], iTo[p], delta);
		}
		return now;
	},

	set: function(now){
		for (var i in now){
			var iNow = now[i];
			for (var p in iNow) this.render(this.elements[i], p, iNow[p], this.options.unit);
		}
		return this;
	},

	start: function(obj){
		if (!this.check(arguments.callee, obj)) return this;
		var from = {}, to = {};
		for (var i in obj){
			var iProps = obj[i], iFrom = from[i] = {}, iTo = to[i] = {};
			for (var p in iProps){
				var parsed = this.prepare(this.elements[i], p, iProps[p]);
				iFrom[p] = parsed.from;
				iTo[p] = parsed.to;
			}
		}
		return this.parent(from, to);
	}

});


/*
Script: Accordion.js
	An Fx.Elements extension which allows you to easily create accordion type controls.

License:
	MIT-style license.
*/

var Accordion = new Class({

	Extends: Fx.Elements,

	options: {/*
		onActive: $empty,
		onBackground: $empty,*/
		display: 0,
		show: false,
		height: true,
		width: false,
		opacity: true,
		fixedHeight: false,
		fixedWidth: false,
		wait: false,
		alwaysHide: false
	},

	initialize: function(){
		var params = Array.link(arguments, {'container': Element.type, 'options': Object.type, 'togglers': $defined, 'elements': $defined});
		this.parent(params.elements, params.options);
		this.togglers = $$(params.togglers);
		this.container = $(params.container);
		this.previous = -1;
		if (this.options.alwaysHide) this.options.wait = true;
		if ($chk(this.options.show)){
			this.options.display = false;
			this.previous = this.options.show;
		}
		if (this.options.start){
			this.options.display = false;
			this.options.show = false;
		}
		this.effects = {};
		if (this.options.opacity) this.effects.opacity = 'fullOpacity';
		if (this.options.width) this.effects.width = this.options.fixedWidth ? 'fullWidth' : 'offsetWidth';
		if (this.options.height) this.effects.height = this.options.fixedHeight ? 'fullHeight' : 'scrollHeight';
		for (var i = 0, l = this.togglers.length; i < l; i++) this.addSection(this.togglers[i], this.elements[i]);
		this.elements.each(function(el, i){
			if (this.options.show === i){
				this.fireEvent('active', [this.togglers[i], el]);
			} else {
				for (var fx in this.effects) el.setStyle(fx, 0);
			}
		}, this);
		if ($chk(this.options.display)) this.display(this.options.display);
	},

	addSection: function(toggler, element, pos){
		toggler = $(toggler);
		element = $(element);
		var test = this.togglers.contains(toggler);
		var len = this.togglers.length;
		this.togglers.include(toggler);
		this.elements.include(element);
		if (len && (!test || pos)){
			pos = $pick(pos, len - 1);
			toggler.inject(this.togglers[pos], 'before');
			element.inject(toggler, 'after');
		} else if (this.container && !test){
			toggler.inject(this.container);
			element.inject(this.container);
		}
		var idx = this.togglers.indexOf(toggler);
		toggler.addEvent('click', this.display.bind(this, idx));
		if (this.options.height) element.setStyles({'padding-top': 0, 'border-top': 'none', 'padding-bottom': 0, 'border-bottom': 'none'});
		if (this.options.width) element.setStyles({'padding-left': 0, 'border-left': 'none', 'padding-right': 0, 'border-right': 'none'});
		element.fullOpacity = 1;
		if (this.options.fixedWidth) element.fullWidth = this.options.fixedWidth;
		if (this.options.fixedHeight) element.fullHeight = this.options.fixedHeight;
		element.setStyle('overflow', 'hidden');
		if (!test){
			for (var fx in this.effects) element.setStyle(fx, 0);
		}
		return this;
	},

	display: function(index){
		index = ($type(index) == 'element') ? this.elements.indexOf(index) : index;
		if ((this.timer && this.options.wait) || (index === this.previous && !this.options.alwaysHide)) return this;
		this.previous = index;
		var obj = {};
		this.elements.each(function(el, i){
			obj[i] = {};
			var hide = (i != index) || (this.options.alwaysHide && (el.offsetHeight > 0));
			this.fireEvent(hide ? 'background' : 'active', [this.togglers[i], el]);
			for (var fx in this.effects) obj[i][fx] = hide ? 0 : el[this.effects[fx]];
		}, this);
		return this.start(obj);
	}

});




/**************************************************************

	Script		: overlay
	Version		: 1.2
	Authors		: Samuel birch
	Desc		: Covers the window with a semi-transparent layer.
	Licence		: Open Source MIT Licence

**************************************************************/

var overlay = new Class({
	
	getOptions: function(){
		return {
			colour: '#000',
			opacity: 0.7,
			zIndex: 1,
			container: document.body,
			_onClick: $empty
		};
	},

	initialize: function(options){
		this.setOptions(this.getOptions(), options);
		
		this.options.container = $(this.options.container);
		
		this.container = new Element('div').setProperty('id', 'OverlayContainer').setStyles({
			position: 'absolute',
			left: '0px',
			top: '0px',
			width: '100%',
			zIndex: this.options.zIndex
		}).injectInside(this.options.container);
		
		this.iframe = new Element('iframe').setProperties({
			'id': 'OverlayIframe',
			'name': 'OverlayIframe',
			'src': 'javascript:void(0);',
			'frameborder': 0,
			'scrolling': 'no'
		}).setStyles({
			'position': 'absolute',
			'top': 0,
			'left': 0,
			'width': '100%',
			'height': '100%',
			'filter': 'progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0)',
			'opacity': 0,
			'zIndex': 1
		}).injectInside(this.container);
		
		this.overlay = new Element('div').setProperty('id', 'Overlay').setStyles({
			position: 'absolute',
			left: '0px',
			top: '0px',
			width: '100%',
			height: '100%',
			zIndex: 2,
			backgroundColor: this.options.colour
		}).injectInside(this.container);
		
		if(this.options._onClick){
			this.container.addEvent('click', function(){
				this.options._onClick.call(this)
			}.bind(this));
		}
		
		//this.fade = new Fx.Tween(this.container).set('opacity', 0);
		this.container.fade('hide');
		this.position();
		
		window.addEvent('resize', this.position.bind(this));
	},
	
	setOnClick: function(func){
		this.container.addEvent('click', func);
	},
	
	position: function(){ 
		if(this.options.container == document.body){ 
			var h = window.getScrollHeight()+'px'; 
			this.container.setStyles({top: '0px', height: h}); 
		}else{ 
			var myCoords = this.options.container.getCoordinates(); 
			this.container.setStyles({
				top: myCoords.top+'px', 
				height: myCoords.height+'px', 
				left: myCoords.left+'px', 
				width: myCoords.width+'px'
			}); 
		} 
	},
	
	show: function(){
		//this.fade.start(0,this.options.opacity);
		this.container.fade(this.options.opacity);
	},
	
	hide: function(){
		//this.fade.start(this.options.opacity,0);
		this.container.fade('out');
	}
	
});
overlay.implement(new Options);



/**************************************************************

	Script		: multiBox
	Version		: 1.4
	Authors		: Samuel Birch
	Desc		: Supports jpg, gif, png, flash, flv, mov, wmv, mp3, html, iframe
	Licence		: Open Source MIT Licence


**************************************************************/

var multiBox = new Class({
	
	getOptions: function(){
		return {
			initialWidth: 250,
			initialHeight: 250,
			container: document.body, //this will need to be setup to the box open in relation to this.
			overlay: false, //this will be a reference to an overlay instance. - TODO: implement below.
			contentColor: '#FFF',
			showNumbers: true,
			showControls: true,
			//showThumbnails: false,
			//autoPlay: false,
			//waitDuration: 2000,
			descClassName: false,
			descMinWidth: 400,
			descMaxWidth: 600,
			movieWidth: 400,
			movieHeight: 300,
			offset: {x:0, y:0},
			fixedTop: false,
			path: 'files/',
			_onOpen: $empty,
			_onClose: $empty,
			openFromLink: true
			//relativeToWindow: true
		};
	},

	initialize: function(className, options){
		this.setOptions(this.getOptions(), options);
		
		this.openClosePos = {};
		this.timer = 0;
		this.contentToLoad = {};
		this.index = 0;
		this.opened = false;
		this.contentObj = {};
		this.containerDefaults = {};
		this.createArray = [];
		
		if(this.options.useOverlay){
			this.overlay = new Overlay({container: this.options.container, onClick:this.close.bind(this)});
		}
		this.overlay = this.options.overlay;
		if(this.overlay){
			this.overlay.setOnClick(this.close.bind(this));
		}
		
		this.content = $$('.'+className);
		if(this.options.descClassName){
			this.descriptions = $$('.'+this.options.descClassName);
			this.descriptions.each(function(el){
				el.setStyle('display', 'none');
			});
		}
		
		this.container = new Element('div').addClass('MultiBoxContainer').injectInside(this.options.container);
		this.iframe = new Element('iframe').setProperties({
			'id': 'multiBoxIframe',
			'name': 'mulitBoxIframe',
			'src': 'javascript:void(0);',
			'frameborder': 0,
			'scrolling': 'no'
		}).setStyles({
			'position': 'absolute',
			'top': -20,
			'left': -20,
			'filter': 'progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0)',
			'opacity': 0
		}).inject(this.container);
		this.box = new Element('div').addClass('MultiBoxContent').inject(this.container);
		
		this.closeButton = new Element('div').addClass('MultiBoxClose').inject(this.container).addEvent('click', this.close.bind(this));
		
		this.controlsContainer = new Element('div').addClass('MultiBoxControlsContainer').inject(this.container);
		this.controls = new Element('div').addClass('MultiBoxControls').inject(this.controlsContainer);
		
		this.previousButton = new Element('div').addClass('MultiBoxPrevious').inject(this.controls).addEvent('click', this.previous.bind(this));
		this.nextButton = new Element('div').addClass('MultiBoxNext').inject(this.controls).addEvent('click', this.next.bind(this));
		
		this.title = new Element('div').addClass('MultiBoxTitle').inject(this.controls);
		this.titleMargin = this.title.getStyle('margin-left');
		this.number = new Element('div').addClass('MultiBoxNumber').inject(this.controls);
		this.description = new Element('div').addClass('MultiBoxDescription').inject(this.controls);
		
		
		
		if(this.content.length == 1){
			this.title.setStyles({
				'margin-left': 0
			});
			this.description.setStyles({
				'margin-left': 0
			});
			this.previousButton.setStyle('display', 'none');
			this.nextButton.setStyle('display', 'none');
			this.number.setStyle('display', 'none');
		}
		
		new Element('div').setStyle('clear', 'both').inject(this.controls);
		
		this.content.each(function(el,i){
			el.index = i;
			el.addEvent('click', function(e){
				new Event(e).stop();
				this.open(el);
			}.bind(this));
			if(el.href.indexOf('#') > -1){
				el.content = $(el.href.substr(el.href.indexOf('#')+1));
				if(el.content){el.content.setStyle('display','none');}
			}
		}, this);
		
		this.containerEffects = new Fx.Morph(this.container, {duration: 400, transition: Fx.Transitions.Sine.easeInOut});
		this.iframeEffects = new Fx.Morph(this.iframe, {duration: 400, transition: Fx.Transitions.Sine.easeInOut});
		this.controlEffects = new Fx.Morph(this.controlsContainer, {duration: 300, transition: Fx.Transitions.Sine.easeInOut});
		
		this.reset();
	},
	
	setContentType: function(link){
		var str = link.href.substr(link.href.lastIndexOf('.')+1).toLowerCase();
		var contentOptions = {};
		if($chk(link.rel)){
			var optArr = link.rel.split(',');
			optArr.each(function(el){
				var ta = el.split(':');
				contentOptions[ta[0]] = ta[1];
			});
		}
		
		if(contentOptions.type != undefined){
			str = contentOptions.type;
		}
		
		this.contentObj = {};
		this.contentObj.url = link.href;
		this.contentObj.src = link.href;
		this.contentObj.xH = 0;
		
		if(contentOptions.width){
			this.contentObj.width = contentOptions.width;
		}else{
			this.contentObj.width = this.options.movieWidth;
		}
		if(contentOptions.height){
			this.contentObj.height = contentOptions.height;	
		}else{
			this.contentObj.height = this.options.movieHeight;
		}
		if(contentOptions.panel){
			this.panelPosition = contentOptions.panel;
		}else{
			this.panelPosition = this.options.panel;
		}
		
		switch(str){
			case 'jpg':
			case 'image':
			case 'gif':
			case 'png':
				this.type = 'image';
				break;
			case 'swf':
				this.type = 'flash';
				break;
			case 'youtube':
				this.type = 'youtube';
				break;
			case 'flv':
				this.type = 'flashVideo';
				this.contentObj.xH = 70;
				break;
			case 'mov':
				this.type = 'quicktime';
				break;
			case 'wmv':
				this.type = 'windowsMedia';
				break;
			case 'rv':
			case 'rm':
			case 'rmvb':
				this.type = 'real';
				break;
			case 'mp3':
				this.type = 'flashMp3';
				this.contentObj.width = 320;
				this.contentObj.height = 70;
				break;
			case 'element':
				this.type = 'htmlelement';
				this.elementContent = link.content;
				this.elementContent.setStyles({
					display: 'block',
					opacity: 0
				})
	
				if(this.elementContent.getStyle('width') != 'auto'){
					this.contentObj.width = this.elementContent.getStyle('width');
				}
				
				this.contentObj.height = this.elementContent.getSize().y;
				this.elementContent.setStyles({
					display: 'none',
					opacity: 1
				})
				break;
				
			default:
				
				this.type = 'iframe';
				if(contentOptions.ajax){
					this.type = 'ajax';
				}
				break;
		}
	},
	
	reset: function(){
		this.container.setStyles({
			'opacity': 0,
			'display': 'none'
		});
		this.controlsContainer.setStyles({
			'height': 0
		});
		this.removeContent();
		this.previousButton.removeClass('MultiBoxButtonDisabled');
		this.nextButton.removeClass('MultiBoxButtonDisabled');
		this.opened = false;
	},
	
	getOpenClosePos: function(el){
		if (this.options.openFromLink) {
			if (el.getFirst()) {
				var w = el.getFirst().getCoordinates().width - (this.container.getStyle('border').toInt() * 2);
				if (w < 0) {
					w = 0
				}
				var h = el.getFirst().getCoordinates().height - (this.container.getStyle('border').toInt() * 2);
				if (h < 0) {
					h = 0
				}
				this.openClosePos = {
					width: w,
					height: h,
					top: el.getFirst().getCoordinates().top,
					left: el.getFirst().getCoordinates().left
				};
			}
			else {
				var w = el.getCoordinates().width - (this.container.getStyle('border').toInt() * 2);
				if (w < 0) {
					w = 0
				}
				var h = el.getCoordinates().height - (this.container.getStyle('border').toInt() * 2);
				if (h < 0) {
					h = 0
				}
				this.openClosePos = {
					width: w,
					height: h,
					top: el.getCoordinates().top,
					left: el.getCoordinates().left
				};
			}
		}else{
			var border = this.container.getStyle('border').toInt();
			
			if(this.options.fixedTop){
				var top = this.options.fixedTop;
			}else{
				var top = ((window.getHeight()/2)-(this.options.initialHeight/2) - border)+this.options.offset.y;
			}
			this.openClosePos = {
				width: this.options.initialWidth,
				height: this.options.initialHeight,
				top: top,
				left: ((window.getWidth()/2)-(this.options.initialWidth/2)-border)+this.options.offset.x
			};
		}
		return this.openClosePos;
	},
	
	open: function(el){
		this.options._onOpen();
	
		this.index = this.content.indexOf(el);
		
		this.openId = el.getProperty('id');
		
		var border = this.container.getStyle('border').toInt();
		
		if(!this.opened){
			this.opened = true;
			
			if(this.options.overlay){
				this.overlay.show();
			}

			this.container.setStyles(this.getOpenClosePos(el));
			this.container.setStyles({
				opacity: 0,
				display: 'block'
			});
			
			if(this.options.fixedTop){
				var top = this.options.fixedTop;
			}else{
				var top = ((window.getHeight()/2)-(this.options.initialHeight/2) - border)+this.options.offset.y;
			}
			
			
			this.containerEffects.start({
				width: this.options.initialWidth,
				height: this.options.initialHeight,
				top: top,
				left: ((window.getWidth()/2)-(this.options.initialWidth/2)-border)+this.options.offset.x,
				opacity: [0, 1]
			});
			
			this.load(this.index);
		
		}else{
			if (this.options.showControls) {
				this.hideControls();
			}
			this.getOpenClosePos(this.content[this.index]);
			this.timer = this.hideContent.bind(this).delay(500);
			this.timer = this.load.pass(this.index, this).delay(1100);
			
		}
		
	},
	
	create: function(obj){
		/*
		obj = {
			url: 'myurl',  *
			title: 'my title',
			description: 'my description',
			type: 'image',
			width: 400,
			height: 300
		}
		*/
		if(this.createArray.contains(obj.url)){
			var index = this.createArray.indexOf(obj.url);
			var a = this.content[index];
		}else{
			
			var id = 'mbDirect_' + $time();
			var rel = [];
			if(obj.type){rel.push('type:'+obj.type)}
			if(obj.width){rel.push('width:'+obj.width)}
			if(obj.height){rel.push('height:'+obj.height)}
			
			var a = new Element('a', {
				'href': obj.url,
				'id': id,
				'title': obj.title || '',
				'rel': rel.join(',')
			});
			var desc = new Element('div', {
				'class': id,
				'html': obj.description || ''
			})
		
			this.createArray.push(obj.url);
			this.content.push(a);
			var index = this.content.length-1;
			
			if(this.options.descClassName){
				this.descriptions.include(desc);
			}
		}
		this.open(a);
	},
	
	getContent: function(index){
		this.setContentType(this.content[index]);
		var desc = false;
		if(this.options.descClassName){
		this.descriptions.each(function(el,i){
			if(el.hasClass(this.openId)){
				desc = el.clone();
			}
		},this);
		}
		this.contentToLoad = {
			title: this.content[index].title || '&nbsp;',
			desc: desc,
			number: index+1
		};
	},
	
	close: function(){
		if(this.options.overlay){
			this.overlay.hide();
		}
		if (this.options.showControls) {
			this.hideControls();
		}
		this.hideContent();
		this.containerEffects.cancel();
		this.zoomOut.bind(this).delay(500);
		this.options._onClose();
	},
	
	zoomOut: function(){
		this.iframeEffects.start({
			width: this.openClosePos.width,
			height: this.openClosePos.height
		});
		this.containerEffects.start({
			width: this.openClosePos.width,
			height: this.openClosePos.height,
			top: this.openClosePos.top,
			left: this.openClosePos.left,
			opacity: 0
		});
		this.reset.bind(this).delay(500);
	},
	
	load: function(index){
		this.box.addClass('MultiBoxLoading');
		this.getContent(index);
		if(this.type == 'image'){
			var xH = this.contentObj.xH;
			this.contentObj = new Asset.image(this.content[index].href, {onload: this.resize.bind(this)});
			this.contentObj.xH = xH;
		}else{
			this.resize();
		}
	},
	
	resize: function(){
		if(this.tempSRC != this.contentObj.src){
			
			var border = this.container.getStyle('border').toInt();
			
			if (this.options.fixedTop) {
				var top = this.options.fixedTop;
			}
			else {
				var top = ((window.getHeight() / 2) - ((Number(this.contentObj.height) + this.contentObj.xH) / 2) - border + window.getScrollTop()) + this.options.offset.y;
			}
			var left = ((window.getWidth() / 2) - (this.contentObj.width.toInt() / 2) - border) + this.options.offset.x;
			if (top < 0) {
				top = 0
			}
			if (left < 0) {
				left = 0
			}
			
			this.containerEffects.cancel();
			this.containerEffects.start({
				width: this.contentObj.width,
				height: Number(this.contentObj.height) + this.contentObj.xH,
				top: top,
				left: left,
				opacity: 1
			});
			this.iframeEffects.start({
				width: Number(this.contentObj.width) + (border*2),
				height: Number(this.contentObj.height) + this.contentObj.xH + (border*2)
			});
			this.timer = this.showContent.bind(this).delay(500);
			this.tempSRC = this.contentObj.src;
		}
	},
	
	showContent: function(){
		this.tempSRC = '';
		this.box.removeClass('MultiBoxLoading');
		this.removeContent();
		
		this.contentContainer = new Element('div').setProperties({id: 'MultiBoxContentContainer'}).setStyles({opacity: 0, width: this.contentObj.width+'px', height: (Number(this.contentObj.height)+this.contentObj.xH)+'px'}).injectInside(this.box);
		
		if(this.type == 'image'){
			this.contentObj.injectInside(this.contentContainer);
			
		}else if(this.type == 'iframe'){
			new Element('iframe').setProperties({
				id: 'iFrame'+new Date().getTime(), 
				width: this.contentObj.width,
				height: this.contentObj.height,
				src: this.contentObj.url,
				frameborder: 0,
				scrolling: 'auto'
			}).injectInside(this.contentContainer);
			
		}else if(this.type == 'htmlelement'){
			this.elementContent.clone().setStyle('display','block').injectInside(this.contentContainer);
			
		}else if(this.type == 'ajax'){
			new Request.HTML({
				update: $('MultiBoxContentContainer'),
				autoCancel: true
			}).get(this.contentObj.url);
			
		}else{
			var obj = this.createEmbedObject().injectInside(this.contentContainer);
			if(this.str != ''){
				$('MultiBoxMediaObject').innerHTML = this.str;
			}
		}
		
		this.contentEffects = new Fx.Morph(this.contentContainer, {duration: 500, transition: Fx.Transitions.linear});
		this.contentEffects.start({
			opacity: 1
		});
		
		this.title.set('html', this.contentToLoad.title);
		if(this.content.length > 1){
			this.number.set('html', this.contentToLoad.number+' of '+this.content.length);
		}else{
			this.number.set('html','');
		}
		if (this.options.descClassName) {
			if (this.description.getFirst()) {
				this.description.getFirst().destroy();
			}
			if(this.contentToLoad.desc){
				this.contentToLoad.desc.inject(this.description).setStyles({
					display: 'block'
				});
			}
		}
		//this.removeContent.bind(this).delay(500);
		if (this.options.showControls) {
			if(this.contentToLoad.title != '&nbsp;' || this.content.length > 1){
				this.timer = this.showControls.bind(this).delay(800);
			}
		}
	},
	
	hideContent: function(){
		this.box.addClass('MultiBoxLoading');
		this.contentEffects.start({
			opacity: 0
		});
		this.removeContent.bind(this).delay(500);
	},
	
	removeContent: function(){
		if($('MultiBoxMediaObject')){
			$('MultiBoxMediaObject').empty();
			$('MultiBoxMediaObject').destroy();
		}
		if($('MultiBoxContentContainer')){
			//$('MultiBoxContentContainer').empty();
			$('MultiBoxContentContainer').destroy();	
		}
	},
	
	showControls: function(){
		this.clicked = false;
		
		if(this.container.getStyle('height') != 'auto'){
			this.containerDefaults.height = this.container.getStyle('height')
			this.containerDefaults.backgroundColor = this.options.contentColor;
		}
		
		this.container.setStyles({
			//'backgroundColor': this.controls.getStyle('backgroundColor'),
			'height': 'auto'
		});
		
		if(this.content.length > 1){
			this.previousButton.setStyle('visibility', 'visible');
			this.nextButton.setStyle('visibility', 'visible');
			this.title.setStyle('margin-left', this.titleMargin);
			
			if(this.contentToLoad.number == 1){
				this.previousButton.addClass('MultiBoxPreviousDisabled');
			}else{
				this.previousButton.removeClass('MultiBoxPreviousDisabled');
			}
			if(this.contentToLoad.number == this.content.length){
				this.nextButton.addClass('MultiBoxNextDisabled');
			}else{
				this.nextButton.removeClass('MultiBoxNextDisabled');
			}
		}else{
			this.previousButton.setStyle('visibility', 'hidden');
			this.nextButton.setStyle('visibility', 'hidden');
			this.title.setStyle('margin-left', 0);
		}
		
		this.controlEffects.start({'height': this.controls.getCoordinates().height});
		this.iframeEffects.start({'height': this.iframe.getStyle('height').toInt()+this.controls.getStyle('height').toInt()});
		
		if(this.options.overlay){
			this.options.overlay.position();
		}

	},
	
	hideControls: function(num){
		this.iframeEffects.start({'height': this.iframe.getStyle('height').toInt()-this.controls.getStyle('height').toInt()});
		this.controlEffects.start({'height': 0}).chain(function(){
			this.container.setStyles(this.containerDefaults);
		}.bind(this));
	},
	
	showThumbnails: function(){
		
	},
	
	next: function(){
		if(this.index < this.content.length-1){
			this.index++;
			this.openId = this.content[this.index].getProperty('id');
			if (this.options.showControls) {
				this.hideControls();
			}
			this.getOpenClosePos(this.content[this.index]);
			//this.getContent(this.index);
			this.timer = this.hideContent.bind(this).delay(500);
			this.timer = this.load.pass(this.index, this).delay(1100);
		}
	},
	
	previous: function(){
		if(this.index > 0){
			this.index--;
			this.openId = this.content[this.index].getProperty('id');
			if (this.options.showControls) {
				this.hideControls();
			}
			this.getOpenClosePos(this.content[this.index]);
			//this.getContent(this.index);
			this.timer = this.hideContent.bind(this).delay(500);
			this.timer = this.load.pass(this.index, this).delay(1000);
		}
	},
	
	createEmbedObject: function(){
		if(this.type == 'flash'){
			var url = this.contentObj.url;
			
			var obj = new Element('div').setProperties({id: 'MultiBoxMediaObject'});
			this.str = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,28,0" '
			this.str += 'width="'+this.contentObj.width+'" ';
			this.str += 'height="'+this.contentObj.height+'" ';
			this.str += 'title="MultiBoxMedia">';
  			this.str += '<param name="movie" value="'+url+'" />'
  			this.str += '<param name="quality" value="high" />';
  			this.str += '<embed src="'+url+'" ';
  			this.str += 'quality="high" pluginspage="http://www.adobe.com/shockwave/download/download.cgi?P1_Prod_Version=ShockwaveFlash" type="application/x-shockwave-flash" ';
  			this.str += 'width="'+this.contentObj.width+'" ';
  			this.str += 'height="'+this.contentObj.height+'"></embed>';
			this.str += '</object>';
			
		}
		
		if(this.type == 'youtube'){
			var url = this.contentObj.url;
			
			var s = url.indexOf('v=')+2;
			var e = url.indexOf('&', s);
			url = url.substring(s,e);
			url = 'http://www.youtube.com/v/'+url+'&h1=en&fs=1';
			//console.log(url)
			
			var obj = new Element('div').setProperties({id: 'MultiBoxMediaObject'});
			this.str = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,28,0" '
			this.str += 'width="'+this.contentObj.width+'" ';
			this.str += 'height="'+this.contentObj.height+'" ';
			this.str += 'title="MultiBoxMedia">';
  			this.str += '<param name="movie" value="'+url+'" />'
  			this.str += '<param name="quality" value="high" />';
  			this.str += '<param name="allowFullScreen" value="true"></param>';
  			this.str += '<embed src="'+url+'" ';
  			this.str += 'quality="high" pluginspage="http://www.adobe.com/shockwave/download/download.cgi?P1_Prod_Version=ShockwaveFlash" type="application/x-shockwave-flash" ';
  			this.str += 'allowfullscreen="true" ';
  			this.str += 'width="'+this.contentObj.width+'" ';
  			this.str += 'height="'+this.contentObj.height+'"></embed>';
			this.str += '</object>';
			
		}
		
		if(this.type == 'flashVideo'){
			//var url = this.contentObj.url.substring(0, this.contentObj.url.lastIndexOf('.'));
			var url = this.contentObj.url;
			
			var obj = new Element('div').setProperties({id: 'MultiBoxMediaObject'});
			this.str = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,28,0" '
			this.str += 'width="'+this.contentObj.width+'" ';
			this.str += 'height="'+(Number(this.contentObj.height)+this.contentObj.xH)+'" ';
			this.str += 'title="MultiBoxMedia">';
  			this.str += '<param name="movie" value="'+this.options.path+'flvplayer.swf" />'
  			this.str += '<param name="quality" value="high" />';
  			this.str += '<param name="salign" value="TL" />';
  			this.str += '<param name="scale" value="noScale" />';
  			this.str += '<param name="FlashVars" value="path='+url+'" />';
  			this.str += '<embed src="'+this.options.path+'flvplayer.swf" ';
  			this.str += 'quality="high" pluginspage="http://www.adobe.com/shockwave/download/download.cgi?P1_Prod_Version=ShockwaveFlash" type="application/x-shockwave-flash" ';
  			this.str += 'width="'+this.contentObj.width+'" ';
  			this.str += 'height="'+(Number(this.contentObj.height)+this.contentObj.xH)+'"';
  			this.str += 'salign="TL" ';
  			this.str += 'scale="noScale" ';
  			this.str += 'FlashVars="path='+url+'"';
  			this.str += '></embed>';
			this.str += '</object>';
			
		}
		
		if(this.type == 'flashMp3'){
			var url = this.contentObj.url;
			
			var obj = new Element('div').setProperties({id: 'MultiBoxMediaObject'});
			this.str = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,28,0" '
			this.str += 'width="'+this.contentObj.width+'" ';
			this.str += 'height="'+this.contentObj.height+'" ';
			this.str += 'title="MultiBoxMedia">';
  			this.str += '<param name="movie" value="'+this.options.path+'mp3player.swf" />'
  			this.str += '<param name="quality" value="high" />';
  			this.str += '<param name="salign" value="TL" />';
  			this.str += '<param name="scale" value="noScale" />';
  			this.str += '<param name="FlashVars" value="path='+url+'" />';
  			this.str += '<embed src="'+this.options.path+'mp3player.swf" ';
  			this.str += 'quality="high" pluginspage="http://www.adobe.com/shockwave/download/download.cgi?P1_Prod_Version=ShockwaveFlash" type="application/x-shockwave-flash" ';
  			this.str += 'width="'+this.contentObj.width+'" ';
  			this.str += 'height="'+this.contentObj.height+'"';
  			this.str += 'salign="TL" ';
  			this.str += 'scale="noScale" ';
  			this.str += 'FlashVars="path='+url+'"';
  			this.str += '></embed>';
			this.str += '</object>';
		}
		
		if(this.type == 'quicktime'){
			var obj = new Element('div').setProperties({id: 'MultiBoxMediaObject'});
			this.str = '<object  type="video/quicktime" classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B" codebase="http://www.apple.com/qtactivex/qtplugin.cab"';
			this.str += ' width="'+this.contentObj.width+'" height="'+this.contentObj.height+'">';
			this.str += '<param name="src" value="'+this.contentObj.url+'" />';
			this.str += '<param name="autoplay" value="true" />';
			this.str += '<param name="controller" value="true" />';
			this.str += '<param name="enablejavascript" value="true" />';
			this.str += '<embed src="'+this.contentObj.url+'" autoplay="true" pluginspage="http://www.apple.com/quicktime/download/" width="'+this.contentObj.width+'" height="'+this.contentObj.height+'"></embed>';
			this.str += '<object/>';
			
		}
		
		if(this.type == 'windowsMedia'){
			var obj = new Element('div').setProperties({id: 'MultiBoxMediaObject'});
			this.str = '<object  type="application/x-oleobject" classid="CLSID:22D6f312-B0F6-11D0-94AB-0080C74C7E95" codebase="http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=6,4,7,1112"';
			this.str += ' width="'+this.contentObj.width+'" height="'+this.contentObj.height+'">';
			this.str += '<param name="filename" value="'+this.contentObj.url+'" />';
			this.str += '<param name="Showcontrols" value="true" />';
			this.str += '<param name="autoStart" value="true" />';
			this.str += '<embed type="application/x-mplayer2" src="'+this.contentObj.url+'" Showcontrols="true" autoStart="true" width="'+this.contentObj.width+'" height="'+this.contentObj.height+'"></embed>';
			this.str += '<object/>';
			
		}
		
		if(this.type == 'real'){
			var obj = new Element('div').setProperties({id: 'MultiBoxMediaObject'});
			this.str = '<object classid="clsid:CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA"';
			this.str += ' width="'+this.contentObj.width+'" height="'+this.contentObj.height+'">';
			this.str += '<param name="src" value="'+this.contentObj.url+'" />';
			this.str += '<param name="controls" value="ImageWindow" />';
			this.str += '<param name="autostart" value="true" />';
			this.str += '<embed src="'+this.contentObj.url+'" controls="ImageWindow" autostart="true" width="'+this.contentObj.width+'" height="'+this.contentObj.height+'"></embed>';
			this.str += '<object/>';
			
		}
		
		return obj;
	}
	
});
multiBox.implement(new Options);
multiBox.implement(new Events);

/*
Script: Drag.js
	The base Drag Class. Can be used to drag and resize Elements using mouse events.

	License:
		MIT-style license.

	Authors:
		Valerio Proietti
		Tom Occhinno
		Jan Kassens
*/

var mDrag = new Class({

	Implements: [Events, Options],

	options: {/*
		onBeforeStart: $empty(thisElement),
		onStart: $empty(thisElement, event),
		onSnap: $empty(thisElement)
		onDrag: $empty(thisElement, event),
		onCancel: $empty(thisElement),
		onComplete: $empty(thisElement, event),*/
		snap: 6,
		unit: 'px',
		grid: false,
		style: true,
		limit: false,
		handle: false,
		invert: false,
		preventDefault: false,
		modifiers: {x: 'left', y: 'top'}
	},

	initialize: function(){
		var params = Array.link(arguments, {'options': Object.type, 'element': $defined});
		this.element = $(params.element);
		this.document = this.element.getDocument();
		this.setOptions(params.options || {});
		var htype = $type(this.options.handle);
		this.handles = ((htype == 'array' || htype == 'collection') ? $$(this.options.handle) : $(this.options.handle)) || this.element;
		this.mouse = {'now': {}, 'pos': {}};
		this.value = {'start': {}, 'now': {}};

		this.selection = (Browser.Engine.trident) ? 'selectstart' : 'mousedown';

		this.bound = {
			start: this.start.bind(this),
			check: this.check.bind(this),
			drag: this.drag.bind(this),
			stop: this.stop.bind(this),
			cancel: this.cancel.bind(this),
			eventStop: $lambda(false)
		};
		this.attach();
	},

	attach: function(){
		this.handles.addEvent('mousedown', this.bound.start);
		return this;
	},

	detach: function(){
		this.handles.removeEvent('mousedown', this.bound.start);
		return this;
	},

	start: function(event){
		if (this.options.preventDefault) event.preventDefault();
		this.mouse.start = event.page;
		this.fireEvent('beforeStart', this.element);
		var limit = this.options.limit;
		this.limit = {x: [], y: []};
		for (var z in this.options.modifiers){
			if (!this.options.modifiers[z]) continue;
			if (this.options.style) this.value.now[z] = this.element.getStyle(this.options.modifiers[z]).toInt();
			else this.value.now[z] = this.element[this.options.modifiers[z]];
			if (this.options.invert) this.value.now[z] *= -1;
			this.mouse.pos[z] = event.page[z] - this.value.now[z];
			if (limit && limit[z]){
				for (var i = 2; i--; i){
					if ($chk(limit[z][i])) this.limit[z][i] = $lambda(limit[z][i])();
				}
			}
		}
		if ($type(this.options.grid) == 'number') this.options.grid = {x: this.options.grid, y: this.options.grid};
		this.document.addEvents({mousemove: this.bound.check, mouseup: this.bound.cancel});
		this.document.addEvent(this.selection, this.bound.eventStop);
	},

	check: function(event){
		if (this.options.preventDefault) event.preventDefault();
		var distance = Math.round(Math.sqrt(Math.pow(event.page.x - this.mouse.start.x, 2) + Math.pow(event.page.y - this.mouse.start.y, 2)));
		if (distance > this.options.snap){
			this.cancel();
			this.document.addEvents({
				mousemove: this.bound.drag,
				mouseup: this.bound.stop
			});
			this.fireEvent('start', [this.element, event]).fireEvent('snap', this.element);
		}
	},

	drag: function(event){
		if (this.options.preventDefault) event.preventDefault();
		this.mouse.now = event.page;
		for (var z in this.options.modifiers){
			if (!this.options.modifiers[z]) continue;
			this.value.now[z] = this.mouse.now[z] - this.mouse.pos[z];
			if (this.options.invert) this.value.now[z] *= -1;
			if (this.options.limit && this.limit[z]){
				if ($chk(this.limit[z][1]) && (this.value.now[z] > this.limit[z][1])){
					this.value.now[z] = this.limit[z][1];
				} else if ($chk(this.limit[z][0]) && (this.value.now[z] < this.limit[z][0])){
					this.value.now[z] = this.limit[z][0];
				}
			}
			if (this.options.grid[z]) this.value.now[z] -= ((this.value.now[z] - this.limit[z][0]) % this.options.grid[z]);
			if (this.options.style) this.element.setStyle(this.options.modifiers[z], this.value.now[z] + this.options.unit);
			else this.element[this.options.modifiers[z]] = this.value.now[z];
		}
		this.fireEvent('drag', [this.element, event]);
	},

	cancel: function(event){
		this.document.removeEvent('mousemove', this.bound.check);
		this.document.removeEvent('mouseup', this.bound.cancel);
		if (event){
			this.document.removeEvent(this.selection, this.bound.eventStop);
			this.fireEvent('cancel', this.element);
		}
	},

	stop: function(event){
		this.document.removeEvent(this.selection, this.bound.eventStop);
		this.document.removeEvent('mousemove', this.bound.drag);
		this.document.removeEvent('mouseup', this.bound.stop);
		if (event) this.fireEvent('complete', [this.element, event]);
	}

});

Element.implement({

	makeResizable: function(options){
		var drag = new mDrag(this, $merge({modifiers: {x: 'width', y: 'height'}}, options));
		this.store('resizer', drag);
		return drag.addEvent('drag', function(){
			this.fireEvent('resize', drag);
		}.bind(this));
	}

});


/*
Script: Drag.Move.js
	A Drag extension that provides support for the constraining of draggables to containers and droppables.

	License:
		MIT-style license.

	Authors:
		Valerio Proietti
		Tom Occhinno
		Jan Kassens*/

mDrag.Move = new Class({

	Extends: mDrag,

	options: {/*
		onEnter: $empty(thisElement, overed),
		onLeave: $empty(thisElement, overed),
		onDrop: $empty(thisElement, overed, event),*/
		droppables: [],
		container: false,
		precalculate: false,
		includeMargins: true,
		checkDroppables: true
	},

	initialize: function(element, options){
		this.parent(element, options);
		this.droppables = $$(this.options.droppables);
		this.container = $(this.options.container);
		if (this.container && $type(this.container) != 'element') this.container = $(this.container.getDocument().body);

		var position = this.element.getStyle('position');
		if (position=='static') position = 'absolute';
		if ([this.element.getStyle('left'), this.element.getStyle('top')].contains('auto')) this.element.position(this.element.getPosition(this.element.offsetParent));
		this.element.setStyle('position', position);

		this.addEvent('start', this.checkDroppables, true);

		this.overed = null;
	},

	start: function(event){
		if (this.container){
			var ccoo = this.container.getCoordinates(this.element.getOffsetParent()), cbs = {}, ems = {};

			['top', 'right', 'bottom', 'left'].each(function(pad){
				cbs[pad] = this.container.getStyle('border-' + pad).toInt();
				ems[pad] = this.element.getStyle('margin-' + pad).toInt();
			}, this);

			var width = this.element.offsetWidth + ems.left + ems.right;
			var height = this.element.offsetHeight + ems.top + ems.bottom;

			if (this.options.includeMargins) {
				$each(ems, function(value, key) {
					ems[key] = 0;
				});
			}
			if (this.container == this.element.getOffsetParent()) {
				this.options.limit = {
					x: [0 - ems.left, ccoo.right - cbs.left - cbs.right - width + ems.right],
					y: [0 - ems.top, ccoo.bottom - cbs.top - cbs.bottom - height + ems.bottom]
				};
			} else {
				this.options.limit = {
					x: [ccoo.left + cbs.left - ems.left, ccoo.right - cbs.right - width + ems.right],
					y: [ccoo.top + cbs.top - ems.top, ccoo.bottom - cbs.bottom - height + ems.bottom]
				};
			}

		}
		if (this.options.precalculate){
			this.positions = this.droppables.map(function(el) {
				return el.getCoordinates();
			});
		}
		this.parent(event);
	},

	checkAgainst: function(el, i){
		el = (this.positions) ? this.positions[i] : el.getCoordinates();
		var now = this.mouse.now;
		return (now.x > el.left && now.x < el.right && now.y < el.bottom && now.y > el.top);
	},

	checkDroppables: function(){
		var overed = this.droppables.filter(this.checkAgainst, this).getLast();
		if (this.overed != overed){
			if (this.overed) this.fireEvent('leave', [this.element, this.overed]);
			if (overed) this.fireEvent('enter', [this.element, overed]);
			this.overed = overed;
		}
	},

	drag: function(event){
		this.parent(event);
		if (this.options.checkDroppables && this.droppables.length) this.checkDroppables();
	},

	stop: function(event){
		this.checkDroppables();
		this.fireEvent('drop', [this.element, this.overed, event]);
		this.overed = null;
		return this.parent(event);
	}

});

Element.implement({

	makeDraggable: function(options){
		var drag = new mDrag.Move(this, options);
		this.store('dragger', drag);
		return drag;
	}

});


/*************************************************************
	Class:		widgets
	Version:	1.0
	Author:		Samuel Birch
*************************************************************/
var widgets = new Class({
	
	Implements: [Options,Events],
	
	getOptions: function(){
		return {
			ghost: 'ghost',
			zIndex: 1,
			handle: null,
			url: null
		};
	},
	
	initialize: function(widgets, containers, options){
		this.setOptions(this.getOptions(), options);
		this.options.widgets = widgets;
		this.widgets = $$(containers+' '+widgets);
		this.containers = $$(containers);
		
		equalise();
		
		this.ghost = new Element('div', {
			'class': this.options.ghost
		});
		
		this.defaults = this.getLayout();
		
		this.widgets.each(function(el,i){
			this.createHandle(el);
			el.store('container', new Element('div'));
			this.createDrag(el);
		}, this);
		
		this.request = new Request({
			url: this.options.url,
			method: 'get',
			link: 'cancel'
		});
		
		this.mousePos = {};
		
		document.addEvent('mousemove', function(e){
			e = new Event(e);
			this.mousePos = e.page;
		}.bind(this))
	},
	
	createHandle: function(el){
		if(this.options.handle){
			if(!el.getElement(this.options.handle)){
			if (el.getElement('span.ms-rteCustom-ArticleHeadLine'))
			{
				var span = el.getElement('span.ms-rteCustom-ArticleHeadLine').setStyle('cursor', 'move');
				//new Element('h2').setStyle('cursor', 'move').wraps(span);
				/*new Element('h2', {
					'class': this.options.handle.replace('.',''),
					'styles': {
						'width': '100%',
						'height': '3em',
						'cursor': 'move',
						'position': 'absolute',
						'z-index': 10,
						'background': '#FFFFFF',
						'opacity': 0.01,
						'top': 30,
						'left': 0
					}
				}).inject(el);*/
			}
			}else{
				el.getElement(this.options.handle).setStyle('cursor', 'move');
			}
		}
	},
	
	getHandle: function(el){
		if(this.options.handle){
			if(!el.getElement(this.options.handle)){
				return el.getElement('span.ms-rteCustom-ArticleHeadLine');
			}else{
				return el.getElement(this.options.handle);
			}
		}
	},
	
	createDrag: function(element){
		var elDrag = element.makeDraggable({
			droppables: this.containers,
			handle: this.getHandle(element),//element.getElement(this.options.handle),
			onStart: function(el, container){
				el.setStyles({
					zIndex: this.options.zIndex+1,
					top: 0,
					left: 0
				})
				var coords = el.getCoordinates();
				var container = el.retrieve('container').setStyles({
					position: 'absolute',
					top: coords.top,
					left: coords.left,
					width: coords.width,
					height: coords.height,
					zIndex: this.options.zIndex+1
				}).inject(document.body);
				this.ghost.setStyles({
					height: coords.height
				}).inject(el, 'after');
				el.inject(container);
				equalise();
			}.bind(this),
			
			onDrag: function(element){
				if(this.reorder){
					this.reorder.each(function(el, i){
						var coords = el.getCoordinates();
						//console.log(this.mousePos.y)
						if(i>0){
							var pCoords = this.reorder[i-1].getCoordinates();
							if(this.mousePos.y > pCoords.bottom-50 && this.mousePos.y < coords.top+50){
								this.ghost.inject(el, 'before');
							}else if(this.mousePos.y > coords.bottom-50 && this.mousePos.y < coords.bottom){
								this.ghost.inject(el, 'after');
							}
						}else{
							if(this.mousePos.y < coords.top+50){
								this.ghost.inject(el, 'before');
							}
						}
					}, this);
				}
			}.bind(this),
			
			onEnter: function(el, container){
				if(this.ghost.getParent() == null){
					this.ghost.inject(container);
					equalise();
				}
				this.reorder = container.getElements(this.options.widgets);
				container.setStyle('padding-bottom', 0);
			}.bind(this),
			
			onLeave: function(el, container){
				this.reorder = false;
				this.ghost.dispose();
				if(container.getChildren().length < 2){
					container.setStyle('padding-bottom', 200);
				}
				container.getChildren().inject(container);
			}.bind(this),
			
			onDrop: function(el, container){
				el.setStyles({
					top: 0,
					left: 0,
					position: 'relative'
				});
				if(container){
					el.inject(this.ghost, 'after');
					this.ghost.dispose();
					this.defaults = this.getLayout();
					this.serialize(this.getLayout());
				}else{
					this.defaults.each(function(c, i){
						c.widgets.each(function(w, j){
							var id = el.get('id') || el.getElement('input[type=hidden]').get('value');
							var wid = w.get('id') || w.getElement('input[type=hidden]').get('value');
							if(id == wid){
								if(j>0){
									el.inject(c.widgets[j-1], 'after');
								}else{
									el.inject($(c.id), 'top');
								}
							}
						});
					});
				}
				el.retrieve('container').dispose();
				clearEqualise();
			}.bind(this)
		});
		element.setStyles({
			width: 'auto',
			top: 0,
			left: 0,
			zIndex: this.options.zIndex,
			position: 'relative'
		});
	},
	
	add: function(el){
		var el = $(el);
		this.widgets.push(el);
		this.createHandle(el)
		el.store('container', new Element('div'));
		this.createDrag(el);
	},
	
	remove: function(index){
		this.widgets.splice(index, 1);
	},
	
	getLayout: function(){
		var layout = new Hash();
		this.containers.each(function(el,i){
			var widgets = el.getElements(this.options.widgets);
			layout[i] = {
				id: el.get('id'),
				widgets: []
			}
			widgets.each(function(w){
				layout[i].widgets.push(w);
			});
		}, this);
		return layout;
	},
	
	serialize: function(layout){
		var str = '';
		var keys = layout.getKeys();
		layout.each(function(el){
			var ids = [];
			el.widgets.each(function(e){
				ids.push(e.get('id') || e.getElement('input[type=hidden]').get('value'));
			});
			str += el.id+'='+ids.join(',')+'&';
		});
		str += 'saveWidgets=true';
		//alert(str);
		
		if(this.options.url){
			this.request.send(str);
		}
	}
});

/**************************************************************

	Script		: Tree
	Version		: 2.0 //BLNW
	Authors		: Samuel Birch
	Desc		: Opening & closing of nested list items.

**************************************************************/

var tree = new Class({
							  
	getOptions: function(){
		return {
			clsOpened: 'opened',
			clsClosed: 'closed',
			trigger: 'span',
			open: null,
			_onClick: $lambda(false)
		};
	},

	initialize: function(tree, options){
		this.setOptions(this.getOptions(), options);
		
		this.tree = $(tree);
		this.elements = this.tree.getElements('ul').getParent();
		this.elements.each(function(el,i){
			el.getElement('ul').setStyle('display', 'none');
			el.addClass(this.options.clsClosed);
			el.getElement(this.options.trigger).addEvent('click',this.openClose.bind(this, el));
		}, this);
		
		//auto open
		if(this.options.open != null){
			this.toggle($(this.options.open));
		}
		
		//console.log(this.tree.getElements('input[type=checkbox]'))
		this.tree.getElements('input[type=checkbox]').each(function(el){
			if(el.get('checked')){
				//console.log(el.get('value'));
				//el.getParent('li')
				this.toggle(el.getParent('ul'), true);			}
		}, this);
	},
	
	openClose: function(el, open){
		var ul = el.getElement('ul');
		var status = '';
		if(ul){
			if(ul.getStyle('display') == 'none' || open == true){
				ul.setStyle('display','');
				el.removeClass(this.options.clsClosed);
				el.addClass(this.options.clsOpened);
				status = 'open';
			}else{
				ul.setStyle('display','none');
				el.removeClass(this.options.clsOpened);
				el.addClass(this.options.clsClosed);
				status = 'closed';
			}
			this.options._onClick(el, status);
		}
	},
	
	toggle: function(id, open){
		var el = $(id);
		if(el != this.tree){
			if(el.get('tag') == 'li'){
				this.openClose(el, open);
			}
			this.toggle(el.getParent(), open);
		}
	}

});
tree.implement(new Events);
tree.implement(new Options);

/*************************************************************/

/*
Script: Tips.js
	Class for creating nice tips that follow the mouse cursor when hovering an element.

License:
	MIT-style license.
*/

var Tips = new Class({

	Implements: [Events, Options],

	options: {
		onShow: function(tip){
			tip.setStyle('visibility', 'visible');
		},
		onHide: function(tip){
			tip.setStyle('visibility', 'hidden');
		},
		showDelay: 100,
		hideDelay: 100,
		className: null,
		offsets: {x: 16, y: 16},
		fixed: false
	},

	initialize: function(){
		var params = Array.link(arguments, {options: Object.type, elements: $defined});
		this.setOptions(params.options || null);
		
		this.tip = new Element('div').inject(document.body);
		
		if (this.options.className) this.tip.addClass(this.options.className);
		
		var top = new Element('div', {'class': 'tip-top'}).inject(this.tip);
		this.container = new Element('div', {'class': 'tip'}).inject(this.tip);
		var bottom = new Element('div', {'class': 'tip-bottom'}).inject(this.tip);

		this.tip.setStyles({position: 'absolute', top: 0, left: 0, visibility: 'hidden'});
		
		if (params.elements) this.attach(params.elements);
	},
	
	attach: function(elements){
		$$(elements).each(function(element){
			var title = element.retrieve('tip:title', element.get('title'));
			var text = element.retrieve('tip:text', element.get('rel') || element.get('href'));
			var enter = element.retrieve('tip:enter', this.elementEnter.bindWithEvent(this, element));
			var leave = element.retrieve('tip:leave', this.elementLeave.bindWithEvent(this, element));
			element.addEvents({mouseenter: enter, mouseleave: leave});
			if (!this.options.fixed){
				var move = element.retrieve('tip:move', this.elementMove.bindWithEvent(this, element));
				element.addEvent('mousemove', move);
			}
			element.store('tip:native', element.get('title'));
			element.erase('title');
		}, this);
		return this;
	},
	
	detach: function(elements){
		$$(elements).each(function(element){
			element.removeEvent('mouseenter', element.retrieve('tip:enter') || $empty);
			element.removeEvent('mouseleave', element.retrieve('tip:leave') || $empty);
			element.removeEvent('mousemove', element.retrieve('tip:move') || $empty);
			element.eliminate('tip:enter').eliminate('tip:leave').eliminate('tip:move');
			var original = element.retrieve('tip:native');
			if (original) element.set('title', original);
		});
		return this;
	},
	
	elementEnter: function(event, element){
		
		$A(this.container.childNodes).each(Element.dispose);
		
		var title = element.retrieve('tip:title');
		
		if (title){
			this.titleElement = new Element('div', {'class': 'tip-title'}).inject(this.container);
			this.fill(this.titleElement, title);
		}
		
		var text = element.retrieve('tip:text');
		if (text){
			this.textElement = new Element('div', {'class': 'tip-text'}).inject(this.container);
			this.fill(this.textElement, text);
		}
		
		this.timer = $clear(this.timer);
		this.timer = this.show.delay(this.options.showDelay, this);

		this.position((!this.options.fixed) ? event : {page: element.getPosition()});
	},
	
	elementLeave: function(event){
		$clear(this.timer);
		this.timer = this.hide.delay(this.options.hideDelay, this);
	},
	
	elementMove: function(event){
		this.position(event);
	},
	
	position: function(event){
		var size = window.getSize(), scroll = window.getScroll();
		var tip = {x: this.tip.offsetWidth, y: this.tip.offsetHeight};
		var props = {x: 'left', y: 'top'};
		for (var z in props){
			var pos = event.page[z] + this.options.offsets[z];
			if ((pos + tip[z] - scroll[z]) > size[z]) pos = event.page[z] - this.options.offsets[z] - tip[z];
			this.tip.setStyle(props[z], pos);
		}
	},
	
	fill: function(element, contents){
		(typeof contents == 'string') ? element.set('html', contents) : element.adopt(contents);
	},

	show: function(){
		this.fireEvent('show', this.tip);
	},

	hide: function(){
		this.fireEvent('hide', this.tip);
	}

});


/*
Script: Fx.Scroll.js
	Effect to smoothly scroll any element, including the window.

License:
	MIT-style license.
*/

Fx.Scroll = new Class({

	Extends: Fx,

	options: {
		offset: {'x': 0, 'y': 0},
		wheelStops: true
	},

	initialize: function(element, options){
		this.element = this.subject = $(element);
		this.parent(options);
		var cancel = this.cancel.bind(this, false);

		if ($type(this.element) != 'element') this.element = $(this.element.getDocument().body);

		var stopper = this.element;

		if (this.options.wheelStops){
			this.addEvent('start', function(){
				stopper.addEvent('mousewheel', cancel);
			}, true);
			this.addEvent('complete', function(){
				stopper.removeEvent('mousewheel', cancel);
			}, true);
		}
	},

	set: function(){
		var now = Array.flatten(arguments);
		this.element.scrollTo(now[0], now[1]);
	},

	compute: function(from, to, delta){
		var now = [];
		var x = 2;
		x.times(function(i){
			now.push(Fx.compute(from[i], to[i], delta));
		});
		return now;
	},

	start: function(x, y){
		if (!this.check(arguments.callee, x, y)) return this;
		var offsetSize = this.element.getSize(), scrollSize = this.element.getScrollSize();
		var scroll = this.element.getScroll(), values = {x: x, y: y};
		for (var z in values){
			var max = scrollSize[z] - offsetSize[z];
			if ($chk(values[z])) values[z] = ($type(values[z]) == 'number') ? values[z].limit(0, max) : max;
			else values[z] = scroll[z];
			values[z] += this.options.offset[z];
		}
		return this.parent([scroll.x, scroll.y], [values.x, values.y]);
	},

	toTop: function(){
		return this.start(false, 0);
	},

	toLeft: function(){
		return this.start(0, false);
	},

	toRight: function(){
		return this.start('right', false);
	},

	toBottom: function(){
		return this.start(false, 'bottom');
	},

	toElement: function(el){
		var position = $(el).getPosition(this.element);
		return this.start(position.x, position.y);
	}

});




/*
---

script: Calendar.js

description: A calendar control

license: MIT-style license

authors:
- Samuel Birch

requires:
- core:1.2.4
- /Native/Date.Extras

provides: [Calendar]

...
*/

var mkCalendar = new Class({

	selectedValues: [],

    Implements: [Options, Events],

    options: {
            classname: 'mkCalendar',
            format: 'yyyy/mm/dd', //  dd/mm/yyyy  yyyy/mm/dd  dd-mm-yyyy  yyyy-mm-dd  dd/mm/yy  dd-mm-yy  mm/dd/yyyy  mm-dd-yyyy
            range: null, // [min, max]
            blockedDates: null, // []
            blockedDays: null, // ['sat', 'sun']
            toggleClear: true,
            input: null,
            container: null,
            width: 255,
            height: 162,
            headerHeight: 22,
            OnSelect: $empty,
            position: 'right',
            multiSelect: false,
            selectDayType: false,
            selectRange: false,
            hideInput: true,
            data: null
    },

    initialize: function(options) {
        this.setOptions(options);
        
        this.container = new Element('div', { 'class': this.options.classname + 'Container' });

        this.header = new Element('div', { 'class': this.options.classname + 'Header' }).inject(this.container);

        this.prevArrow = new Element('span', { 'class': 'left' }).inject(this.header);
        this.prevArrow.addEvent('click', this.previous.bind(this));

        this.titleHolder = new Element('span', { 'class': 'title' }).inject(this.header);
        this.titleHolder.addEvent('click', this.showPanel.bind(this));

        this.nextArrow = new Element('span', { 'class': 'right' }).inject(this.header);
        this.nextArrow.addEvent('click', this.next.bind(this));

        this.headerHeight = this.options.headerHeight;
        
        if(this.options.data){
        	
        	this.data = [];
        	this.options.data.each(function(el){
        		this.data.push({
        			date: new Date().parse(el.date, this.options.format).getTime(),
        			url: el.url
        		});
        	}, this);
        }
        
        this.input = $(this.options.input);

        if (this.input && this.options.hideInput) {
        	this.newInput = new Element('input', {type: 'hidden'});
        	this.newInput.set('value', this.input.get('value'));
        	this.newInput.set('name', this.input.get('name'));
        	this.newInput.set('id', this.input.get('id'));
        	this.newInput.inject(this.input, 'after');
        	this.input.destroy();
        	this.input = this.newInput;
        }
        
        if(this.options.container){
        	$(this.options.container).empty();
        	this.container.inject($(this.options.container) || document.body);
    	}

        this.today = new Date();
        this.currentDate = this.today.getFirstDay();

        if (this.options.blockedDates) {
            this.options.blockedDates.each(function(el, i) {
                this.options.blockedDates[i] = this.today.parse(el, this.options.format).format('yyyy/mm/dd');
            }, this);
        }
        if (this.options.range) {
            this.options.range.each(function(el, i) {
                this.options.range[i] = this.today.parse(el, this.options.format);
            }, this);
        }
        
        if (this.options.container) {
            this.show();
        }
    },

    createCalendarDates: function(date) {
		//console.log(date);
        date = date.clearTime();
        var firstDay = date.getFirstDay();
        var monthName = firstDay.getFullMonthName();
        var fullYear = firstDay.getFullYear();
        var startDate = firstDay.getPreviousDay('mon');

        this.title = monthName + ' ' + fullYear;
        this.shownDate = date;
        this.panel = 'month';

        var div = new Element('div', { 'class': this.options.classname });
        var table = new Element('table', { 'cellspacing': 1, 'class': 'date' }).inject(div);

        var body = new Element('tbody').inject(table);

        var head = new Element('tr').inject(body);
        var mon = new Element('th', { 'text': 'Mon', 'scope': 'col' }).inject(head);
        var tue = new Element('th', { 'text': 'Tue', 'scope': 'col' }).inject(head);
        var wed = new Element('th', { 'text': 'Wed', 'scope': 'col' }).inject(head);
        var thu = new Element('th', { 'text': 'Thu', 'scope': 'col' }).inject(head);
        var fri = new Element('th', { 'text': 'Fri', 'scope': 'col' }).inject(head);
        var sat = new Element('th', { 'text': 'Sat', 'scope': 'col' }).inject(head);
        var sun = new Element('th', { 'text': 'Sun', 'scope': 'col' }).inject(head);
        
        if(this.options.selectDayType){
        	mon.addEvent('click', this.selectDay.bindWithEvent(this, 'mon')).setStyle('cursor', 'pointer');
        	tue.addEvent('click', this.selectDay.bindWithEvent(this, 'tue')).setStyle('cursor', 'pointer');
        	wed.addEvent('click', this.selectDay.bindWithEvent(this, 'wed')).setStyle('cursor', 'pointer');
        	thu.addEvent('click', this.selectDay.bindWithEvent(this, 'thu')).setStyle('cursor', 'pointer');
        	fri.addEvent('click', this.selectDay.bindWithEvent(this, 'fri')).setStyle('cursor', 'pointer');
        	sat.addEvent('click', this.selectDay.bindWithEvent(this, 'sat')).setStyle('cursor', 'pointer');
        	sun.addEvent('click', this.selectDay.bindWithEvent(this, 'sun')).setStyle('cursor', 'pointer');
        }

        //var body = new Element('tbody').inject(table);
        //console.log(date);
        var count = 0;
        var row = 1;
        for (var i = 0; i < 6; i++) {
            var tr = new Element('tr', { 'class': 'row' + row }).inject(body);
            for (var j = 0; j < 7; j++) {
                var classname = '';

                if (startDate.isBeforeMonth(date)) {
                    classname += ' past';
                }
                if (startDate.isAfterMonth(date)) {
                    classname += ' future';
                }
                if (startDate.isSame(startDate.today())) {
                    classname += ' today';
                }
                if (this.options.blockedDates) {
                    if (this.options.blockedDates.contains(startDate.format(this.options.format))) {
                        classname += ' blocked';
                    }
                }
                if (this.options.range) {
                    if (startDate.isBefore(this.options.range[0]) || startDate.isAfter(this.options.range[1])) {
                        classname += ' blocked';
                    }
                }
                if (this.options.blockedDays) {
                    if (this.options.blockedDays.contains(startDate.getShortDayName().toLowerCase())) {
                        classname += ' blocked';
                    }
                }
                
                if (this.selectedValues.contains(startDate.getTime()) && !classname.contains('blocked')) {
                    classname += ' selected';
                }
                
                var url = '';
                if(this.data){
                	this.data.each(function(el){
                		if(el.date == startDate.getTime()){
                			classname += ' selected';
                			url = el.url;
                		}
            		});
                }

                var el = new Element('td', {
                    'text': startDate.getDate(),
                    'class': classname
                }).inject(tr);
                el.store('date', startDate);
                el.store('url', url);
                //el.addEvent('click', this.selectDate.bind(this, startDate));
                if (!el.hasClass('blocked')) {
                	if(this.data){
                		if(url){
                			el.addEvent('click', function(){document.location = this.retrieve('url')});
            			}
                	}else{
                		el.addEvent('click', this.selectDate.bindWithEvent(this, [startDate, el]));
                	}
                }
                
                if(this.selectedValues.contains(startDate.format(this.options.format))){
                	this.selectedElements.include(el);
            	}

                startDate = startDate.addDay();
            }
            row++;
        }
        return div;
    },

    createCalendarMonths: function(date) {

        date = date.clearTime();
        var fullYear = date.getFullYear();

        this.title = fullYear;
        this.shownDate = date;
        this.panel = 'year';

        var div = new Element('div', { 'class': this.options.classname });
        var table = new Element('table', { 'cellspacing': 1, 'class': 'month' }).inject(div);
        var body = new Element('tbody').inject(table);

        //
        var count = 0;
        var row = 1;
        for (var i = 0; i < 3; i++) {
            var tr = new Element('tr', { 'class': 'row' + row }).inject(body);
            for (var j = 0; j < 4; j++) {
                var classname = '';

                if (this.selectedMonth) {
                    if (this.selectedYear == date.getFullYear()) {
                        if (this.selectedMonth == count) {
                            classname = 'selected';
                        }
                    }
                }
                var el = new Element('td', {
                    'text': date.shortMonthNames[count].capitalize(),
                    'class': classname
                }).inject(tr);
                el.addEvent('click', this.selectMonth.bind(this, count));
                count++;
            }
            row++;
        }
        return div;
    },

    createCalendarYears: function(date) {

        date = date.clearTime();

        var y = date.getFullYear() - new Date().getFullYear();
        var num = Math.floor(y / 12);

        startDate = new Date().addYears((num * 12)).addYears(-2);

        this.title = 'Years:';
        this.shownDate = date;
        this.panel = 'years';

        var div = new Element('div', { 'class': this.options.classname });
        var table = new Element('table', { 'cellspacing': 1, 'class': 'month' }).inject(div);

        var body = new Element('tbody').inject(table);
        var count = 0;
        var row = 1;
        for (var i = 0; i < 3; i++) {
            var tr = new Element('tr', { 'class': 'row' + row }).inject(body);
            for (var j = 0; j < 4; j++) {
                var classname = '';

                if (this.selectedYear) {
                    if (startDate.getFullYear() == this.selectedYear) {
                        classname = 'selected';
                    }
                }
                var el = new Element('td', {
                    'text': startDate.getFullYear(),
                    'class': classname
                }).inject(tr);
                el.addEvent('click', this.selectYear.bind(this, startDate.getFullYear()));
                startDate = startDate.addYear();
            }
            row++;
        }
        return div;
    },

    showMonth: function(date) {
    	//console.log(date);
        this.month = this.createCalendarDates(date).setStyles({
            'position': 'absolute',
            'top': this.headerHeight,
            'left': 0,
            'zIndex': 0
        }).inject(this.container);
        this.titleHolder.set('html', this.title);
    },

    showMonths: function(date, slide) {
        this.months = this.createCalendarMonths(date).setStyles({
            'position': 'absolute',
            'top': -(this.options.height),
            'left': 0,
            'zIndex': 2
        }).inject(this.container);
        this.titleHolder.set('html', this.title);

        if (slide) {
            new Fx.Tween(this.months, {
                onComplete: function() { this.month.setStyle('display', 'none'); } .bind(this)
            }).start('top', -(this.options.height), this.headerHeight);
        } else {
            this.months.setStyle('top', this.headerHeight);
        }
    },

    showYears: function(date) {
        this.years = this.createCalendarYears(date).setStyles({
            'position': 'absolute',
            'top': -(this.options.height),
            'left': 0,
            'zIndex': 3
        }).inject(this.container);
        this.titleHolder.set('html', this.title);

        new Fx.Tween(this.years, {
            onComplete: function() { this.months.setStyle('display', 'none'); } .bind(this)
        }).start('top', -(this.options.height), this.headerHeight);
    },

    hideMonths: function() {
        this.month.setStyle('display', 'block');
        new Fx.Tween(this.months, {
            onComplete: function() {
                this.months.destroy();
            } .bind(this)
        }).start('top', this.headerHeight, -(this.options.height));
    },

    hideYears: function() {
        this.months.setStyle('display', 'block');
        new Fx.Tween(this.years, {
            onComplete: function() {
                this.years.destroy();
            } .bind(this)
        }).start('top', this.headerHeight, -(this.options.height));
    },

    toggle: function(date) {
        if (this.showing) {
            this.hide();
        } else {
            this.show(date);
        }
    },

    show: function(date) {
        this.showing = true;
        if (this.months) {
            this.months.destroy();
        }
        if (this.years) {
            this.years.destroy();
        }

        if (!date && this.input) {
            date = this.input.get('value');
            var dates = date.split(',');
            date = dates[0];
            dates.erase('');
            dates.each(function(d){
            	this.selectedValues.push(new Date().parse(d, this.options.format).getTime());
            }, this);
        }
        //console.log(date);
        if (date) {
            if ($type(date) == 'string') {
                date = new Date().parse(date, this.options.format);
            }
            this.selected = date.clearTime();
            this.selectedMonth = this.selected.getMonth();
            this.selectedYear = this.selected.getFullYear();
        } else {
            date = new Date().today();
        }
        
       this.currentDate = date.getFirstDay();
        this.showMonth(date);

    },

    hide: function() {
        this.showing = false;
        if (this.input) {
            //layers.hide(this.container);
        }
    },

    next: function() {
        if (this.panel == 'month') {
            this.nextMonth();
        }
        if (this.panel == 'year') {
            this.nextYear();
        }
        if (this.panel == 'years') {
            this.nextYears();
        }
    },

    previous: function() {
        if (this.panel == 'month') {
            this.previousMonth();
        }
        if (this.panel == 'year') {
            this.previousYear();
        }
        if (this.panel == 'years') {
            this.previousYears();
        }
    },

    showPanel: function() {
        if (this.panel == 'month') {
            this.showMonths(this.shownDate, true);
        } else if (this.panel == 'year') {
            this.showYears(this.shownDate);
        }
    },

    nextMonth: function() {
        this.currentDate = this.currentDate.addMonths(1);
        var newCal = this.createCalendarDates(this.currentDate).setStyles({
            'position': 'absolute',
            'top': this.headerHeight,
            'left': this.options.width,
            'zIndex': 0
        }).inject(this.container);
        this.titleHolder.set('html', this.title);

        new Fx.Tween(this.month, {
            onComplete: function() {
                this.month.destroy();
            } .bind(this)
        }).start('left', 0, -(this.options.width));
        new Fx.Tween(newCal, {
            onComplete: function() {
                this.month = newCal;
            } .delay(600, this)
        }).start('left', this.options.width, 0);
    },

    previousMonth: function() {
        this.currentDate = this.currentDate.addMonths(-1);
        var newCal = this.createCalendarDates(this.currentDate).setStyles({
            'position': 'absolute',
            'top': this.headerHeight,
            'left': -(this.options.width),
            'zIndex': 0
        }).inject(this.container);
        this.titleHolder.set('html', this.title);

        new Fx.Tween(this.month, {
            onComplete: function() {
                this.month.destroy();
            } .bind(this)
        }).start('left', 0, this.options.width);
        new Fx.Tween(newCal, {
            onComplete: function() {
                this.month = newCal;
            } .delay(600, this)
        }).start('left', -(this.options.width), 0);
    },

    nextYear: function() {
        this.currentDate = this.currentDate.addYears(1);
        var newCal = this.createCalendarMonths(this.currentDate).setStyles({
            'position': 'absolute',
            'top': this.headerHeight,
            'left': this.options.width,
            'zIndex': 2
        }).inject(this.container);
        this.titleHolder.set('html', this.title);

        new Fx.Tween(this.months, {
            onComplete: function() {
                this.months.destroy();
            } .bind(this)
        }).start('left', 0, -(this.options.width));
        new Fx.Tween(newCal, {
            onComplete: function() {
                this.months = newCal;
            } .delay(600, this)
        }).start('left', this.options.width, 0);
    },

    previousYear: function() {
        this.currentDate = this.currentDate.addYears(-1);
        var newCal = this.createCalendarMonths(this.currentDate).setStyles({
            'position': 'absolute',
            'top': this.headerHeight,
            'left': -(this.options.width),
            'zIndex': 2
        }).inject(this.container);
        this.titleHolder.set('html', this.title);

        new Fx.Tween(this.months, {
            onComplete: function() {
                this.months.destroy();
            } .bind(this)
        }).start('left', 0, this.options.width);
        new Fx.Tween(newCal, {
            onComplete: function() {
                this.months = newCal;
            } .delay(600, this)
        }).start('left', -(this.options.width), 0);
    },

    nextYears: function() {
        this.currentDate = this.currentDate.addYears(12);
        var newCal = this.createCalendarYears(this.currentDate).setStyles({
            'position': 'absolute',
            'top': this.headerHeight,
            'left': this.options.width,
            'zIndex': 3
        }).inject(this.container);

        new Fx.Tween(this.years, {
            onComplete: function() {
                this.years.destroy();
            } .bind(this)
        }).start('left', 0, -(this.options.width));
        new Fx.Tween(newCal, {
            onComplete: function() {
                this.years = newCal;
            } .delay(600, this)
        }).start('left', this.options.width, 0);
    },

    previousYears: function() {
        this.currentDate = this.currentDate.addYears(-12);
        var newCal = this.createCalendarYears(this.currentDate).setStyles({
            'position': 'absolute',
            'top': this.headerHeight,
            'left': -(this.options.width),
            'zIndex': 3
        }).inject(this.container);

        new Fx.Tween(this.years, {
            onComplete: function() {
                this.years.destroy();
            } .bind(this)
        }).start('left', 0, this.options.width);
        new Fx.Tween(newCal, {
            onComplete: function() {
                this.years = newCal;
            } .delay(600, this)
        }).start('left', -(this.options.width), 0);
    },
    
    selectDay: function(e, day){
    	//console.log(day);
    	e = new Event(e);
    	
    	var num;
    	num = new Date().getDayFromName(day)-1;
    	if(num < 0) num = 6;
    	
    	this.container.getElements('tr').each(function(tr, i){
    		if(i>0){
    			var d = tr.getElements('td')[num];
    			if(!d.hasClass('blocked')){
    				this.selectedValues.include(d.retrieve('date').getTime());
    				d.addClass('selected');
				}
    		}
    	}, this);
    	
    	if(e.shift){
    		//select every for a year
    		var allDays = this.currentDate.getEveryDay(day);
    		var temp = [];
    		allDays.each(function(d){temp.push(d.getTime());});
    		this.selectedValues.combine(temp);
    	}
    	
    	this.outputValues();
    },

    selectDate: function(e, date, el) {
        e = new Event(e);
        
        var dte = date.format(this.options.format);
        
        this.selectedValues.erase('');
        
        if (this.options.toggleClear) {
        	el.toggleClass('selected');
        	if(this.selectedValues.contains(date.getTime())){
        		this.selectedValues.erase(date.getTime());
        		this.selected = null;
        	}else{
        		this.selectedValues.include(date.getTime());
        	}
    	}else{
    		this.selectedValues.include(date.getTime());
    		el.addClass('selected');
    	}
    	
    	if(this.options.selectRange && this.selectedValues.length > 1){
    		if(e.shift){
	    		var d = date;
	    		var amount = date > this.previousSelectedDate ? -1 : 1;
	    		do{
	    			d = d.addDays(amount);
	    			this.selectedValues.include(d.getTime());
	    		}while(!d.isSame(this.previousSelectedDate));
	    		
	    		this.container.getElements('td').each(function(td){
	    			if(this.selectedValues.contains(td.retrieve('date').getTime())){
	    				if(!td.hasClass('blocked')){
	    					td.addClass('selected');
    					}else{
    						this.selectedValues.erase(td.retrieve('date').getTime());
    					}
	    			}
	    		}, this);
			}
    	}
    	
    	this.outputValues();
    	
        
		this.previousSelectedDate = date;
        
        this.hide();
        if (this.options.OnSelect) {
            this.options.OnSelect();
        }
        
    },

    selectMonth: function(date) {
        //console.log(date);
        this.month.destroy();
        this.currentDate.setMonth(date);
        this.selectedMonth = date;
        this.showMonth(this.currentDate);
        this.hideMonths();
    },

    selectYear: function(date) {
        //console.log(date);
        this.months.destroy();
        this.currentDate.setFullYear(date);
        this.selectedMonth = null;
        this.selectedYear = date;
        this.showMonths(this.currentDate);
        this.hideYears();
    },
    
    outputValues: function(){
    	var temp = [];
    	this.selectedValues.each(function(d){
    		temp.push(new Date(d).format(this.options.format));
    	}, this);
    	
    	if(this.options.multiSelect){
    		this.input.set('value', temp.toString());
		}else{
			this.input.set('value', temp.pop());
			this.selectedValues.empty();
		}
    }

});


/*
---

script: Date.Extras.js

description: Date helpers

license: MIT-style license

authors:
- Samuel Birch

requires:
- core:1.2.4

provides: [Date.Extras]

...
*/

Date.implement({
    'parse': function(str, format) {
    	
    	var s = '-';
    	
    	if(format.indexOf('/') > 0){
    		s = '/';
    	}
    	
    	var f = format.split(s);
    	var d = str.split(s);
    	
    	var dd;
    	var mm;
    	var yy;
    	
    	for(var i=0; i<f.length; i++){
    		var el = f[i].substr(0,1);
    		if(el == 'd'){
    			dd = d[i];
    		}
    		if(el == 'm'){
    			mm = d[i];
    		}
    		if(el == 'y'){
    			yy = d[i];
    		}
    	}
    	
    	var date = new Date(yy+'/'+mm+'/'+dd);
    	
       // var date = new Date(str);
        var valid = false;
        this.dateFormats.each(function(el) {
            if (str == date.format(el)) {
                //console.log('match: '+el);
                valid = true;
            }
        });
        if (!valid) {
            var sep = '';
            if (str.contains('/')) {
                sep = '/';
            }
            if (str.contains('-')) {
                sep = '-';
            }

            var a = str.split(sep);
            if (a[0].length == 4) {
                return new Date(a[0] + '/' + a[1] + '/' + a[2]);
            } else {
                if (a[2].length == 2) {
                    a[2] = '20' + a[2];
                }
                return new Date(a[2] + '/' + a[1] + '/' + a[0]);
            }
        } else {
            return date;
        }
    },
    'format': function(format) {
        var dd = this.getDate().toString();
        var mm = (this.getMonth() + 1).toString();
        var yyyy = this.getFullYear().toString();
        var yy = yyyy.substr(2);

        if (dd.length == 1) { dd = '0' + dd }
        if (mm.length == 1) { mm = '0' + mm }

        //console.log(yy);

        format = format.replace('dd', dd);
        format = format.replace('mm', mm);
        format = format.replace('yyyy', yyyy);
        format = format.replace('yy', yy);

        return format;
    },
    'today': function() {
        return new Date().clearTime();
    },
    'getFirstDay': function() {
        var d = new Date(this);
        	d.setDate(1);
        return d;
    },
    'clone': function() {
        return new Date(this);
    },
    'addDay': function() {
        return this.addDays(1);
    },
    'addDays': function(num) {
        if (!num) { num = 0 }
        var d = new Date(this);
        	d.setDate(this.getDate() + num);
        return d;
    },
    'addMonth': function() {
        return this.addMonths(1);
    },
    'addMonths': function(num) {
        if (!num) { num = 0 }
        var d = new Date(this);
        	d.setMonth(this.getMonth() + num);
        return d;
    },
    'addYear': function() {
        return this.addYears(1);
    },
    'addYears': function(num) {
        if (!num) { num = 0 }
        var d = new Date(this);
       		d.setFullYear(this.getFullYear() + num);
        return d;
    },
    'isBeforeMonth': function(date) {
        if (this.getFirstDay() < date.getFirstDay()) {
            return true;
        } else {
            return false;
        }
    },
    'isAfterMonth': function(date) {
        if (this.getFirstDay() > date.getFirstDay()) {
            return true;
        } else {
            return false;
        }
    },
    'isBefore': function(date) {
    	//console.log(date);
        if (this.getTime() < date.getTime()) {
            return true;
        } else {
            return false;
        }
    },
    'isAfter': function(date) {
        if (this.getTime() > date.getTime()) {
            return true;
        } else {
            return false;
        }
    },
    'isSame': function(date) {
        if (this.getTime() == date.getTime()) {
            return true;
        } else {
            return false;
        }
    },
    'getEveryDay': function(day, amount) {
    	if(day){
    		if(!amount){
    			amount = 52;
    		}
    		var dates = [];
    		var startDate = this.getNextDay(day);
    		for(var i=0; i<52; i++){
    			dates.push(startDate.addDays(i*7));
    		}
    		return dates;
    	}else{
    		return this;
    	}
    },
    'getNextDay': function(day) {
    	if(day){
    		day = this.getDayFromName(day);
    		var date = this;
            if (date.getDay() != day) {
                do {
                    date = date.addDays(1);
                } while (date.getDay() != day);
            }
            return date;
		}else{
			return this.addDays(1);
		}
    },
    'getPreviousDay': function(day) {
        if (day) {
            day = this.getDayFromName(day);
            var date = this;
            if (date.getDay() != day) {
                do {
                    date = date.addDays(-1);
                } while (date.getDay() != day);
            }
            return date;
        } else {
            return this.addDays(-1);
        }
    },
    'getDayFromName': function(name) {
        name = name.toLowerCase();
        if (this.fullDayNames.contains(name)) {
            return this.fullDayNames.indexOf(name);
        }
        if (this.shortDayNames.contains(name)) {
            return this.shortDayNames.indexOf(name);
        }
    },
    'getFullDayName': function() {
        return this.fullDayNames[this.getDay()].capitalize();
    },
    'getShortDayName': function() {
        return this.shortDayNames[this.getDay()].capitalize();
    },
    'getFullMonthName': function() {
        return this.fullMonthNames[this.getMonth()].capitalize();
    },
    'getShortMonthName': function() {
        return this.shortMonthNames[this.getMonth()].capitalize();
    },
    'clearTime': function() {
        return new Date(this.getFullYear() + '/' + (this.getMonth() + 1) + '/' + this.getDate());
    },
    'fullDayNames': ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'],
    'shortDayNames': ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'],
    'fullMonthNames': ['january', 'febuary', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december'],
    'shortMonthNames': ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec'],
    'dateFormats': ['dd/mm/yyyy', 'dd/mm/yy', 'yyyy/mm/dd', 'dd-mm-yyyy', 'dd-mm-yy', 'yyyy-mm-dd', 'mm/dd/yyyy', 'mm-dd-yyyy']
});

