function buttonlink(thislink) { 
	if ((thislink != '') && (thislink != null)) { 
		window.location.href = thislink; 
	}
}
// http://gist.github.com/91436
Element.Events.outerClick = {
	
	base : 'click',
	
	condition : function(event){
		event.stopPropagation();
		return false;
	},
	
	onAdd : function(fn){
		this.getDocument().addEvent('click', fn);
	},
	
	onRemove : function(fn){
		this.getDocument().removeEvent('click', fn);
	}
	
};

//MooTools More, <http://mootools.net/more>. Copyright (c) 2006-2009 Aaron Newton <http://clientcide.com/>, Valerio Proietti <http://mad4milk.net> & the MooTools team <http://mootools.net/developers>, MIT Style License.

MooTools.More = {
	'version': '1.2.3.1'
};

/*
Script: Class.Binds.js
	Automagically binds specified methods in a class to the instance of the class.

	License:
		MIT-style license.

	Authors:
		Aaron Newton
*/

Class.Mutators.Binds = function(binds){
    return binds;
};

Class.Mutators.initialize = function(initialize){
	return function(){
		$splat(this.Binds).each(function(name){
			var original = this[name];
			if (original) this[name] = original.bind(this);
		}, this);
		return initialize.apply(this, arguments);
	};
};

/*
Script: Class.Occlude.js
	Prevents a class from being applied to a DOM element twice.

	License:
		MIT-style license.

	Authors:
		Aaron Newton
*/

Class.Occlude = new Class({

	occlude: function(property, element){
		element = document.id(element || this.element);
		var instance = element.retrieve(property || this.property);
		if (instance && !$defined(this.occluded)){
			this.occluded = instance;
		} else {
			this.occluded = false;
			element.store(property || this.property, this);
		}
		return this.occluded;
	}

});

/*
Script: Element.Measure.js
	Extends the Element native object to include methods useful in measuring dimensions.

	Element.measure / .expose methods by Daniel Steigerwald
	License: MIT-style license.
	Copyright: Copyright (c) 2008 Daniel Steigerwald, daniel.steigerwald.cz

	License:
		MIT-style license.

	Authors:
		Aaron Newton

*/

Element.implement({

	measure: function(fn){
		var vis = function(el) {
			return !!(!el || el.offsetHeight || el.offsetWidth);
		};
		if (vis(this)) return fn.apply(this);
		var parent = this.getParent(),
			toMeasure = [], 
			restorers = [];
		while (!vis(parent) && parent != document.body) {
			toMeasure.push(parent.expose());
			parent = parent.getParent();
		}
		var restore = this.expose();
		var result = fn.apply(this);
		restore();
		toMeasure.each(function(restore){
			restore();
		});
		return result;
	},

	expose: function(){
		if (this.getStyle('display') != 'none') return $empty;
		var before = this.style.cssText;
		this.setStyles({
			display: 'block',
			position: 'absolute',
			visibility: 'hidden'
		});
		return function(){
			this.style.cssText = before;
		}.bind(this);
	},

	getDimensions: function(options){
		options = $merge({computeSize: false},options);
		var dim = {};
		var getSize = function(el, options){
			return (options.computeSize)?el.getComputedSize(options):el.getSize();
		};
		if (this.getStyle('display') == 'none'){
			dim = this.measure(function(){
				return getSize(this, options);
			});
		} else {
			try { //safari sometimes crashes here, so catch it
				dim = getSize(this, options);
			}catch(e){}
		}
		return $chk(dim.x) ? $extend(dim, {width: dim.x, height: dim.y}) : $extend(dim, {x: dim.width, y: dim.height});
	},

	getComputedSize: function(options){
		options = $merge({
			styles: ['padding','border'],
			plains: {
				height: ['top','bottom'],
				width: ['left','right']
			},
			mode: 'both'
		}, options);
		var size = {width: 0,height: 0};
		switch (options.mode){
			case 'vertical':
				delete size.width;
				delete options.plains.width;
				break;
			case 'horizontal':
				delete size.height;
				delete options.plains.height;
				break;
		}
		var getStyles = [];
		//this function might be useful in other places; perhaps it should be outside this function?
		$each(options.plains, function(plain, key){
			plain.each(function(edge){
				options.styles.each(function(style){
					getStyles.push((style == 'border') ? style + '-' + edge + '-' + 'width' : style + '-' + edge);
				});
			});
		});
		var styles = {};
		getStyles.each(function(style){ styles[style] = this.getComputedStyle(style); }, this);
		var subtracted = [];
		$each(options.plains, function(plain, key){ //keys: width, height, plains: ['left', 'right'], ['top','bottom']
			var capitalized = key.capitalize();
			size['total' + capitalized] = 0;
			size['computed' + capitalized] = 0;
			plain.each(function(edge){ //top, left, right, bottom
				size['computed' + edge.capitalize()] = 0;
				getStyles.each(function(style, i){ //padding, border, etc.
					//'padding-left'.test('left') size['totalWidth'] = size['width'] + [padding-left]
					if (style.test(edge)){
						styles[style] = styles[style].toInt() || 0; //styles['padding-left'] = 5;
						size['total' + capitalized] = size['total' + capitalized] + styles[style];
						size['computed' + edge.capitalize()] = size['computed' + edge.capitalize()] + styles[style];
					}
					//if width != width (so, padding-left, for instance), then subtract that from the total
					if (style.test(edge) && key != style &&
						(style.test('border') || style.test('padding')) && !subtracted.contains(style)){
						subtracted.push(style);
						size['computed' + capitalized] = size['computed' + capitalized]-styles[style];
					}
				});
			});
		});

		['Width', 'Height'].each(function(value){
			var lower = value.toLowerCase();
			if(!$chk(size[lower])) return;

			size[lower] = size[lower] + this['offset' + value] + size['computed' + value];
			size['total' + value] = size[lower] + size['total' + value];
			delete size['computed' + value];
		}, this);

		return $extend(styles, size);
	}

});

/*
Script: Element.Position.js
	Extends the Element native object to include methods useful positioning elements relative to others.

	License:
		MIT-style license.

	Authors:
		Aaron Newton
*/

(function(){

var original = Element.prototype.position;

Element.implement({

	position: function(options){
		//call original position if the options are x/y values
		if (options && ($defined(options.x) || $defined(options.y))) return original ? original.apply(this, arguments) : this;
		$each(options||{}, function(v, k){ if (!$defined(v)) delete options[k]; });
		options = $merge({
			relativeTo: document.body,
			position: {
				x: 'center', //left, center, right
				y: 'center' //top, center, bottom
			},
			edge: false,
			offset: {x: 0, y: 0},
			returnPos: false,
			relFixedPosition: false,
			ignoreMargins: false,
			allowNegative: false
		}, options);
		//compute the offset of the parent positioned element if this element is in one
		var parentOffset = {x: 0, y: 0};
		var parentPositioned = false;
		/* dollar around getOffsetParent should not be necessary, but as it does not return
		 * a mootools extended element in IE, an error occurs on the call to expose. See:
		 * http://mootools.lighthouseapp.com/projects/2706/tickets/333-element-getoffsetparent-inconsistency-between-ie-and-other-browsers */
		var offsetParent = this.measure(function(){
			return document.id(this.getOffsetParent());
		});
		if (offsetParent && offsetParent != this.getDocument().body){
			parentOffset = offsetParent.measure(function(){
				return this.getPosition();
			});
			parentPositioned = true;
			options.offset.x = options.offset.x - parentOffset.x;
			options.offset.y = options.offset.y - parentOffset.y;
		}
		//upperRight, bottomRight, centerRight, upperLeft, bottomLeft, centerLeft
		//topRight, topLeft, centerTop, centerBottom, center
		var fixValue = function(option){
			if ($type(option) != 'string') return option;
			option = option.toLowerCase();
			var val = {};
			if (option.test('left')) val.x = 'left';
			else if (option.test('right')) val.x = 'right';
			else val.x = 'center';
			if (option.test('upper') || option.test('top')) val.y = 'top';
			else if (option.test('bottom')) val.y = 'bottom';
			else val.y = 'center';
			return val;
		};
		options.edge = fixValue(options.edge);
		options.position = fixValue(options.position);
		if (!options.edge){
			if (options.position.x == 'center' && options.position.y == 'center') options.edge = {x:'center', y:'center'};
			else options.edge = {x:'left', y:'top'};
		}

		this.setStyle('position', 'absolute');
		var rel = document.id(options.relativeTo) || document.body;
		var calc = rel == document.body ? window.getScroll() : rel.getPosition();
		var top = calc.y;
		var left = calc.x;

		if (Browser.Engine.trident){
			var scrolls = rel.getScrolls();
			top += scrolls.y;
			left += scrolls.x;
		}

		var dim = this.getDimensions({computeSize: true, styles:['padding', 'border','margin']});
		if (options.ignoreMargins){
			options.offset.x = options.offset.x - dim['margin-left'];
			options.offset.y = options.offset.y - dim['margin-top'];
		}
		var pos = {};
		var prefY = options.offset.y;
		var prefX = options.offset.x;
		var winSize = window.getSize();
		switch(options.position.x){
			case 'left':
				pos.x = left + prefX;
				break;
			case 'right':
				pos.x = left + prefX + rel.offsetWidth;
				break;
			default: //center
				pos.x = left + ((rel == document.body ? winSize.x : rel.offsetWidth)/2) + prefX;
				break;
		}
		switch(options.position.y){
			case 'top':
				pos.y = top + prefY;
				break;
			case 'bottom':
				pos.y = top + prefY + rel.offsetHeight;
				break;
			default: //center
				pos.y = top + ((rel == document.body ? winSize.y : rel.offsetHeight)/2) + prefY;
				break;
		}

		if (options.edge){
			var edgeOffset = {};

			switch(options.edge.x){
				case 'left':
					edgeOffset.x = 0;
					break;
				case 'right':
					edgeOffset.x = -dim.x-dim.computedRight-dim.computedLeft;
					break;
				default: //center
					edgeOffset.x = -(dim.x/2);
					break;
			}
			switch(options.edge.y){
				case 'top':
					edgeOffset.y = 0;
					break;
				case 'bottom':
					edgeOffset.y = -dim.y-dim.computedTop-dim.computedBottom;
					break;
				default: //center
					edgeOffset.y = -(dim.y/2);
					break;
			}
			pos.x = pos.x + edgeOffset.x;
			pos.y = pos.y + edgeOffset.y;
		}
		pos = {
			left: ((pos.x >= 0 || parentPositioned || options.allowNegative) ? pos.x : 0).toInt(),
			top: ((pos.y >= 0 || parentPositioned || options.allowNegative) ? pos.y : 0).toInt()
		};
		if (rel.getStyle('position') == 'fixed' || options.relFixedPosition){
			var winScroll = window.getScroll();
			pos.top = pos.top.toInt() + winScroll.y;
			pos.left = pos.left.toInt() + winScroll.x;
		}

		if (options.returnPos) return pos;
		else this.setStyles(pos);
		return this;
	}

});

})();

/*
Script: Element.Shortcuts.js
	Extends the Element native object to include some shortcut methods.

	License:
		MIT-style license.

	Authors:
		Aaron Newton

*/

Element.implement({

	isDisplayed: function(){
		return this.getStyle('display') != 'none';
	},

	toggle: function(){
		return this[this.isDisplayed() ? 'hide' : 'show']();
	},

	hide: function(){
		var d;
		try {
			//IE fails here if the element is not in the dom
			if ('none' != this.getStyle('display')) d = this.getStyle('display');
		} catch(e){}

		return this.store('originalDisplay', d || 'block').setStyle('display', 'none');
	},

	show: function(display){
		return this.setStyle('display', display || this.retrieve('originalDisplay') || 'block');
	},

	swapClass: function(remove, add){
		return this.removeClass(remove).addClass(add);
	}

});


/*
Script: OverText.js
	Shows text over an input that disappears when the user clicks into it. The text remains hidden if the user adds a value.

	License:
		MIT-style license.

	Authors:
		Aaron Newton
*/

var OverText = new Class({

	Implements: [Options, Events, Class.Occlude],

	Binds: ['reposition', 'assert', 'focus'],

	options: {/*
		textOverride: null,
		onFocus: $empty()
		onTextHide: $empty(textEl, inputEl),
		onTextShow: $empty(textEl, inputEl), */
		element: 'label',
		positionOptions: {
			position: 'upperLeft',
			edge: 'upperLeft',
			offset: {
				x: 4,
				y: 2
			}
		},
		poll: false,
		pollInterval: 250
	},

	property: 'OverText',

	initialize: function(element, options){
		this.element = document.id(element);
		if (this.occlude()) return this.occluded;
		this.setOptions(options);
		this.attach(this.element);
		OverText.instances.push(this);
		if (this.options.poll) this.poll();
		return this;
	},

	toElement: function(){
		return this.element;
	},

	attach: function(){
		var val = this.options.textOverride || this.element.get('alt') || this.element.get('title');
		if (!val) return;
		this.text = new Element(this.options.element, {
			'class': 'overTxtLabel',
			styles: {
				lineHeight: 'normal',
				position: 'absolute'
			},
			html: val,
			events: {
				click: this.hide.pass(true, this)
			}
		}).inject(this.element, 'after');
		if (this.options.element == 'label') this.text.set('for', this.element.get('id'));
		this.element.addEvents({
			focus: this.focus,
			blur: this.assert,
			change: this.assert
		}).store('OverTextDiv', this.text);
		window.addEvent('resize', this.reposition.bind(this));
		this.assert(true);
		this.reposition();
	},

	startPolling: function(){
		this.pollingPaused = false;
		return this.poll();
	},

	poll: function(stop){
		//start immediately
		//pause on focus
		//resumeon blur
		if (this.poller && !stop) return this;
		var test = function(){
			if (!this.pollingPaused) this.assert(true);
		}.bind(this);
		if (stop) $clear(this.poller);
		else this.poller = test.periodical(this.options.pollInterval, this);
		return this;
	},

	stopPolling: function(){
		this.pollingPaused = true;
		return this.poll(true);
	},

	focus: function(){
		if (!this.text.isDisplayed() || this.element.get('disabled')) return;
		this.hide();
	},

	hide: function(suppressFocus){
		if (this.text.isDisplayed() && !this.element.get('disabled')){
			this.text.hide();
			this.fireEvent('textHide', [this.text, this.element]);
			this.pollingPaused = true;
			try {
				if (!suppressFocus) this.element.fireEvent('focus').focus();
			} catch(e){} //IE barfs if you call focus on hidden elements
		}
		return this;
	},

	show: function(){
		if (!this.text.isDisplayed()){
			this.text.show();
			this.reposition();
			this.fireEvent('textShow', [this.text, this.element]);
			this.pollingPaused = false;
		}
		return this;
	},

	assert: function(suppressFocus){
		this[this.test() ? 'show' : 'hide'](suppressFocus);
	},

	test: function(){
		var v = this.element.get('value');
		return !v;
	},

	reposition: function(){
		this.assert(true);
		if (!this.element.getParent() || !this.element.offsetHeight) return this.stopPolling().hide();
		if (this.test()) this.text.position($merge(this.options.positionOptions, {relativeTo: this.element}));
		return this;
	}

});

OverText.instances = [];

OverText.update = function(){

	return OverText.instances.map(function(ot){
		if (ot.element && ot.text) return ot.reposition();
		return null; //the input or the text was destroyed
	});

};

if (window.Fx && Fx.Reveal) {
	Fx.Reveal.implement({
		hideInputs: Browser.Engine.trident ? 'select, input, textarea, object, embed, .overTxtLabel' : false
	});
}

/*
Script: Fx.Elements.js
	Effect to change any number of CSS properties of any number of Elements.

	License:
		MIT-style license.

	Authors:
		Valerio Proietti
*/

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(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: Fx.Scroll.js
	Effect to smoothly scroll any element, including the window.

	License:
		MIT-style license.

	Authors:
		Valerio Proietti
*/

Fx.Scroll = new Class({

	Extends: Fx,

	options: {
		offset: {x: 0, y: 0},
		wheelStops: true
	},

	initialize: function(element, options){
		this.element = this.subject = document.id(element);
		this.parent(options);
		var cancel = this.cancel.bind(this, false);

		if ($type(this.element) != 'element') this.element = document.id(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){
		return [0, 1].map(function(i){
			return Fx.compute(from[i], to[i], delta);
		});
	},

	start: function(x, y){
		if (!this.check(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 = document.id(el).getPosition(this.element);
		return this.start(position.x, position.y);
	},

	scrollIntoView: function(el, axes, offset){
		axes = axes ? $splat(axes) : ['x','y'];
		var to = {};
		el = document.id(el);
		var pos = el.getPosition(this.element);
		var size = el.getSize();
		var scroll = this.element.getScroll();
		var containerSize = this.element.getSize();
		var edge = {
			x: pos.x + size.x,
			y: pos.y + size.y
		};
		['x','y'].each(function(axis) {
			if (axes.contains(axis)) {
				if (edge[axis] > scroll[axis] + containerSize[axis]) to[axis] = edge[axis] - containerSize[axis];
				if (pos[axis] < scroll[axis]) to[axis] = pos[axis];
			}
			if (to[axis] == null) to[axis] = scroll[axis];
			if (offset && offset[axis]) to[axis] = to[axis] + offset[axis];
		}, this);
		if (to.x != scroll.x || to.y != scroll.y) this.start(to.x, to.y);
		return this;
	}

});


/*
Script: Fx.Slide.js
	Effect to slide an element in and out of view.

	License:
		MIT-style license.

	Authors:
		Valerio Proietti
*/

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 = document.id(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){
		return [0, 1].map(function(i){
			return Fx.compute(from[i], to[i], delta);
		});
	},

	start: function(how, mode){
		if (!this.check(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 = (layout == 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;
	}

});


/*
Script: Fx.SmoothScroll.js
	Class for creating a smooth scrolling effect to all internal links on the page.

	License:
		MIT-style license.

	Authors:
		Valerio Proietti
*/

var SmoothScroll = Fx.SmoothScroll = new Class({

	Extends: Fx.Scroll,

	initialize: function(options, context){
		context = context || document;
		this.doc = context.getDocument();
		var win = context.getWindow();
		this.parent(this.doc, options);
		this.links = this.options.links ? $$(this.options.links) : $$(this.doc.links);
		var location = win.location.href.match(/^[^#]*/)[0] + '#';
		this.links.each(function(link){
			if (link.href.indexOf(location) != 0) {return;}
			var anchor = link.href.substr(location.length);
			if (anchor) this.useLink(link, anchor);
		}, this);
		if (!Browser.Engine.webkit419) {
			this.addEvent('complete', function(){
				win.location.hash = this.anchor;
			}, true);
		}
	},

	useLink: function(link, anchor){
		var el;
		link.addEvent('click', function(event){
			if (el !== false && !el) el = document.id(anchor) || this.doc.getElement('a[name=' + anchor + ']');
			if (el) {
				event.preventDefault();
				this.anchor = anchor;
				this.toElement(el);
				link.blur();
			}
		}.bind(this));
	}

});

/*
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 Drag = 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 = document.id(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) : document.id(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]||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 Drag(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*/

Drag.Move = new Class({

	Extends: Drag,

	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 = document.id(this.options.container);
		if (this.container && $type(this.container) != 'element') this.container = document.id(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 Drag.Move(this, options);
		this.store('dragger', drag);
		return drag;
	}

});


/*
Script: Slider.js
	Class for creating horizontal and vertical slider controls.

	License:
		MIT-style license.

	Authors:
		Valerio Proietti
*/

var Slider = new Class({

	Implements: [Events, Options],

	Binds: ['clickedElement', 'draggedKnob', 'scrolledElement'],

	options: {/*
		onTick: $empty(intPosition),
		onChange: $empty(intStep),
		onComplete: $empty(strStep),*/
		onTick: function(position){
			if (this.options.snap) position = this.toPosition(this.step);
			this.knob.setStyle(this.property, position);
		},
		snap: false,
		offset: 0,
		range: false,
		wheel: false,
		steps: 100,
		mode: 'horizontal'
	},

	initialize: function(element, knob, options){
		this.setOptions(options);
		this.element = document.id(element);
		this.knob = document.id(knob);
		this.previousChange = this.previousEnd = this.step = -1;
		var offset, limit = {}, modifiers = {'x': false, 'y': false};
		switch (this.options.mode){
			case 'vertical':
				this.axis = 'y';
				this.property = 'top';
				offset = 'offsetHeight';
				break;
			case 'horizontal':
				this.axis = 'x';
				this.property = 'left';
				offset = 'offsetWidth';
		}
		this.half = this.knob[offset] / 2;
		this.full = this.element[offset] - this.knob[offset] + (this.options.offset * 2);
		this.min = $chk(this.options.range[0]) ? this.options.range[0] : 0;
		this.max = $chk(this.options.range[1]) ? this.options.range[1] : this.options.steps;
		this.range = this.max - this.min;
		this.steps = this.options.steps || this.full;
		this.stepSize = Math.abs(this.range) / this.steps;
		this.stepWidth = this.stepSize * this.full / Math.abs(this.range) ;

		this.knob.setStyle('position', 'relative').setStyle(this.property, - this.options.offset);
		modifiers[this.axis] = this.property;
		limit[this.axis] = [- this.options.offset, this.full - this.options.offset];

		this.bound = {
			clickedElement: this.clickedElement.bind(this),
			scrolledElement: this.scrolledElement.bindWithEvent(this),
			draggedKnob: this.draggedKnob.bind(this)
		};

		var dragOptions = {
			snap: 0,
			limit: limit,
			modifiers: modifiers,
			onDrag: this.bound.draggedKnob,
			onStart: this.bound.draggedKnob,
			onBeforeStart: (function(){
				this.isDragging = true;
			}).bind(this),
			onComplete: function(){
				this.isDragging = false;
				this.draggedKnob();
				this.end();
			}.bind(this)
		};
		if (this.options.snap){
			dragOptions.grid = Math.ceil(this.stepWidth);
			dragOptions.limit[this.axis][1] = this.full;
		}

		this.drag = new Drag(this.knob, dragOptions);
		this.attach();
	},

	attach: function(){
		this.element.addEvent('mousedown', this.bound.clickedElement);
		if (this.options.wheel) this.element.addEvent('mousewheel', this.bound.scrolledElement);
		this.drag.attach();
		return this;
	},

	detach: function(){
		this.element.removeEvent('mousedown', this.bound.clickedElement);
		this.element.removeEvent('mousewheel', this.bound.scrolledElement);
		this.drag.detach();
		return this;
	},

	set: function(step){
		if (!((this.range > 0) ^ (step < this.min))) step = this.min;
		if (!((this.range > 0) ^ (step > this.max))) step = this.max;

		this.step = Math.round(step);
		this.checkStep();
		this.fireEvent('tick', this.toPosition(this.step));
		this.end();
		return this;
	},

	clickedElement: function(event){
		if (this.isDragging || event.target == this.knob) return;

		var dir = this.range < 0 ? -1 : 1;
		var position = event.page[this.axis] - this.element.getPosition()[this.axis] - this.half;
		position = position.limit(-this.options.offset, this.full -this.options.offset);

		this.step = Math.round(this.min + dir * this.toStep(position));
		this.checkStep();
		this.fireEvent('tick', position);
		this.end();
	},

	scrolledElement: function(event){
		var mode = (this.options.mode == 'horizontal') ? (event.wheel < 0) : (event.wheel > 0);
		this.set(mode ? this.step - this.stepSize : this.step + this.stepSize);
		event.stop();
	},

	draggedKnob: function(){
		var dir = this.range < 0 ? -1 : 1;
		var position = this.drag.value.now[this.axis];
		position = position.limit(-this.options.offset, this.full -this.options.offset);
		this.step = Math.round(this.min + dir * this.toStep(position));
		this.checkStep();
	},

	checkStep: function(){
		if (this.previousChange != this.step){
			this.previousChange = this.step;
			this.fireEvent('change', this.step);
		}
	},

	end: function(){
		if (this.previousEnd !== this.step){
			this.previousEnd = this.step;
			this.fireEvent('complete', this.step + '');
		}
	},

	toStep: function(position){
		var step = (position + this.options.offset) * this.stepSize / this.full * this.steps;
		return this.options.steps ? Math.round(step -= step % this.stepSize) : step;
	},

	toPosition: function(step){
		return (this.full * Math.abs(this.min - step)) / (this.steps * this.stepSize) - this.options.offset;
	}

});

/*
Script: Sortables.js
	Class for creating a drag and drop sorting interface for lists of items.

	License:
		MIT-style license.

	Authors:
		Tom Occhino
*/

var Sortables = new Class({

	Implements: [Events, Options],

	options: {/*
		onSort: $empty(element, clone),
		onStart: $empty(element, clone),
		onComplete: $empty(element),*/
		snap: 4,
		opacity: 1,
		clone: false,
		revert: false,
		handle: false,
		constrain: false
	},

	initialize: function(lists, options){
		this.setOptions(options);
		this.elements = [];
		this.lists = [];
		this.idle = true;

		this.addLists($$(document.id(lists) || lists));
		if (!this.options.clone) this.options.revert = false;
		if (this.options.revert) this.effect = new Fx.Morph(null, $merge({duration: 250, link: 'cancel'}, this.options.revert));
	},

	attach: function(){
		this.addLists(this.lists);
		return this;
	},

	detach: function(){
		this.lists = this.removeLists(this.lists);
		return this;
	},

	addItems: function(){
		Array.flatten(arguments).each(function(element){
			this.elements.push(element);
			var start = element.retrieve('sortables:start', this.start.bindWithEvent(this, element));
			(this.options.handle ? element.getElement(this.options.handle) || element : element).addEvent('mousedown', start);
		}, this);
		return this;
	},

	addLists: function(){
		Array.flatten(arguments).each(function(list){
			this.lists.push(list);
			this.addItems(list.getChildren());
		}, this);
		return this;
	},

	removeItems: function(){
		return $$(Array.flatten(arguments).map(function(element){
			this.elements.erase(element);
			var start = element.retrieve('sortables:start');
			(this.options.handle ? element.getElement(this.options.handle) || element : element).removeEvent('mousedown', start);
			
			return element;
		}, this));
	},

	removeLists: function(){
		return $$(Array.flatten(arguments).map(function(list){
			this.lists.erase(list);
			this.removeItems(list.getChildren());
			
			return list;
		}, this));
	},

	getClone: function(event, element){
		if (!this.options.clone) return new Element('div').inject(document.body);
		if ($type(this.options.clone) == 'function') return this.options.clone.call(this, event, element, this.list);
		return element.clone(true).setStyles({
			margin: '0px',
			position: 'absolute',
			visibility: 'hidden',
			'width': element.getStyle('width')
		}).inject(this.list).position(element.getPosition(element.getOffsetParent()));
	},

	getDroppables: function(){
		var droppables = this.list.getChildren();
		if (!this.options.constrain) droppables = this.lists.concat(droppables).erase(this.list);
		return droppables.erase(this.clone).erase(this.element);
	},

	insert: function(dragging, element){
		var where = 'inside';
		if (this.lists.contains(element)){
			this.list = element;
			this.drag.droppables = this.getDroppables();
		} else {
			where = this.element.getAllPrevious().contains(element) ? 'before' : 'after';
		}
		this.element.inject(element, where);
		this.fireEvent('sort', [this.element, this.clone]);
	},

	start: function(event, element){
		if (!this.idle) return;
		this.idle = false;
		this.element = element;
		this.opacity = element.get('opacity');
		this.list = element.getParent();
		this.clone = this.getClone(event, element);

		this.drag = new Drag.Move(this.clone, {
			snap: this.options.snap,
			container: this.options.constrain && this.element.getParent(),
			droppables: this.getDroppables(),
			onSnap: function(){
				event.stop();
				this.clone.setStyle('visibility', 'visible');
				this.element.set('opacity', this.options.opacity || 0);
				this.fireEvent('start', [this.element, this.clone]);
			}.bind(this),
			onEnter: this.insert.bind(this),
			onCancel: this.reset.bind(this),
			onComplete: this.end.bind(this)
		});

		this.clone.inject(this.element, 'before');
		this.drag.start(event);
	},

	end: function(){
		this.drag.detach();
		this.element.set('opacity', this.opacity);
		if (this.effect){
			var dim = this.element.getStyles('width', 'height');
			var pos = this.clone.computePosition(this.element.getPosition(this.clone.offsetParent));
			this.effect.element = this.clone;
			this.effect.start({
				top: pos.top,
				left: pos.left,
				width: dim.width,
				height: dim.height,
				opacity: 0.25
			}).chain(this.reset.bind(this));
		} else {
			this.reset();
		}
	},

	reset: function(){
		this.idle = true;
		this.clone.destroy();
		this.fireEvent('complete', this.element);
	},

	serialize: function(){
		var params = Array.link(arguments, {modifier: Function.type, index: $defined});
		var serial = this.lists.map(function(list){
			return list.getChildren().map(params.modifier || function(element){
				return element.get('id');
			}, this);
		}, this);

		var index = params.index;
		if (this.lists.length == 1) index = 0;
		return $chk(index) && index >= 0 && index < this.lists.length ? serial[index] : serial;
	}

});


/*
Script: Assets.js
	Provides methods to dynamically load JavaScript, CSS, and Image files into the document.

	License:
		MIT-style license.

	Authors:
		Valerio Proietti
*/

var Asset = {

	javascript: function(source, properties){
		properties = $extend({
			onload: $empty,
			document: document,
			check: $lambda(true)
		}, properties);

		var script = new Element('script', {src: source, type: 'text/javascript'});

		var load = properties.onload.bind(script), check = properties.check, doc = properties.document;
		delete properties.onload; delete properties.check; delete properties.document;

		script.addEvents({
			load: load,
			readystatechange: function(){
				if (['loaded', 'complete'].contains(this.readyState)) load();
			}
		}).set(properties);

		if (Browser.Engine.webkit419) var checker = (function(){
			if (!$try(check)) return;
			$clear(checker);
			load();
		}).periodical(50);

		return script.inject(doc.head);
	},

	css: function(source, properties){
		return new Element('link', $merge({
			rel: 'stylesheet', media: 'screen', type: 'text/css', href: source
		}, properties)).inject(document.head);
	},

	image: function(source, properties){
		properties = $merge({
			onload: $empty,
			onabort: $empty,
			onerror: $empty
		}, properties);
		var image = new Image();
		var element = document.id(image) || new Element('img');
		['load', 'abort', 'error'].each(function(name){
			var type = 'on' + name;
			var event = properties[type];
			delete properties[type];
			image[type] = function(){
				if (!image) return;
				if (!element.parentNode){
					element.width = image.width;
					element.height = image.height;
				}
				image = image.onload = image.onabort = image.onerror = null;
				event.delay(1, element, element);
				element.fireEvent(name, element, 1);
			};
		});
		image.src = element.src = source;
		if (image && image.complete) image.onload.delay(1);
		return element.set(properties);
	},

	images: function(sources, options){
		options = $merge({
			onComplete: $empty,
			onProgress: $empty,
			onError: $empty,
			properties: {}
		}, options);
		sources = $splat(sources);
		var images = [];
		var counter = 0;
		return new Elements(sources.map(function(source){
			return Asset.image(source, $extend(options.properties, {
				onload: function(){
					options.onProgress.call(this, counter, sources.indexOf(source));
					counter++;
					if (counter == sources.length) options.onComplete();
				},
				onerror: function(){
					options.onError.call(this, counter, sources.indexOf(source));
					counter++;
					if (counter == sources.length) options.onComplete();
				}
			}));
		}));
	}

};
/*
Script: Color.js
	Class for creating and manipulating colors in JavaScript. Supports HSB -> RGB Conversions and vice versa.

	License:
		MIT-style license.

	Authors:
		Valerio Proietti
*/

var Color = new Native({

	initialize: function(color, type){
		if (arguments.length >= 3){
			type = 'rgb'; color = Array.slice(arguments, 0, 3);
		} else if (typeof color == 'string'){
			if (color.match(/rgb/)) color = color.rgbToHex().hexToRgb(true);
			else if (color.match(/hsb/)) color = color.hsbToRgb();
			else color = color.hexToRgb(true);
		}
		type = type || 'rgb';
		switch (type){
			case 'hsb':
				var old = color;
				color = color.hsbToRgb();
				color.hsb = old;
			break;
			case 'hex': color = color.hexToRgb(true); break;
		}
		color.rgb = color.slice(0, 3);
		color.hsb = color.hsb || color.rgbToHsb();
		color.hex = color.rgbToHex();
		return $extend(color, this);
	}

});

Color.implement({

	mix: function(){
		var colors = Array.slice(arguments);
		var alpha = ($type(colors.getLast()) == 'number') ? colors.pop() : 50;
		var rgb = this.slice();
		colors.each(function(color){
			color = new Color(color);
			for (var i = 0; i < 3; i++) rgb[i] = Math.round((rgb[i] / 100 * (100 - alpha)) + (color[i] / 100 * alpha));
		});
		return new Color(rgb, 'rgb');
	},

	invert: function(){
		return new Color(this.map(function(value){
			return 255 - value;
		}));
	},

	setHue: function(value){
		return new Color([value, this.hsb[1], this.hsb[2]], 'hsb');
	},

	setSaturation: function(percent){
		return new Color([this.hsb[0], percent, this.hsb[2]], 'hsb');
	},

	setBrightness: function(percent){
		return new Color([this.hsb[0], this.hsb[1], percent], 'hsb');
	}

});

var $RGB = function(r, g, b){
	return new Color([r, g, b], 'rgb');
};

var $HSB = function(h, s, b){
	return new Color([h, s, b], 'hsb');
};

var $HEX = function(hex){
	return new Color(hex, 'hex');
};

Array.implement({

	rgbToHsb: function(){
		var red = this[0], green = this[1], blue = this[2];
		var hue, saturation, brightness;
		var max = Math.max(red, green, blue), min = Math.min(red, green, blue);
		var delta = max - min;
		brightness = max / 255;
		saturation = (max != 0) ? delta / max : 0;
		if (saturation == 0){
			hue = 0;
		} else {
			var rr = (max - red) / delta;
			var gr = (max - green) / delta;
			var br = (max - blue) / delta;
			if (red == max) hue = br - gr;
			else if (green == max) hue = 2 + rr - br;
			else hue = 4 + gr - rr;
			hue /= 6;
			if (hue < 0) hue++;
		}
		return [Math.round(hue * 360), Math.round(saturation * 100), Math.round(brightness * 100)];
	},

	hsbToRgb: function(){
		var br = Math.round(this[2] / 100 * 255);
		if (this[1] == 0){
			return [br, br, br];
		} else {
			var hue = this[0] % 360;
			var f = hue % 60;
			var p = Math.round((this[2] * (100 - this[1])) / 10000 * 255);
			var q = Math.round((this[2] * (6000 - this[1] * f)) / 600000 * 255);
			var t = Math.round((this[2] * (6000 - this[1] * (60 - f))) / 600000 * 255);
			switch (Math.floor(hue / 60)){
				case 0: return [br, t, p];
				case 1: return [q, br, p];
				case 2: return [p, br, t];
				case 3: return [p, q, br];
				case 4: return [t, p, br];
				case 5: return [br, p, q];
			}
		}
		return false;
	}

});

String.implement({

	rgbToHsb: function(){
		var rgb = this.match(/\d{1,3}/g);
		return (rgb) ? rgb.rgbToHsb() : null;
	},

	hsbToRgb: function(){
		var hsb = this.match(/\d{1,3}/g);
		return (hsb) ? hsb.hsbToRgb() : null;
	}

});

function translate_magic_quotes(str) {
	if ((typeof(str) != 'undefined') && (str != '')) {
		str = str.replace(/%%dblqt%%/g, '"');
		str = str.replace(/%%sglqt%%/g, "'");
	}
	return str;
}


var AscDialog = new Class({
	Implements: [Options,Events], 
	options: {
		strs: {
			'close': 'Click to close'
		},
		speed: 500,
		maskOpacity: 0.3,
		maskColor: '#000000',
		isModal: false,
		useArrows: false,
		addCloseBtn: true,
		popOpacity: 1,
		cornerRadius: 10,
		classPrefix: 'Asc',
		place: {
			'ss': { target:'window', io:1, align:'n', offset:0, margin:0 }, // show start
			'se': { trans:'fly', target:'window', io:-1, align:'c', offset:0, margin:0 }, // show end
			'he': { trans:'fly', target:'window', io:1, align:'n', offset:0, margin:0 } // hide end
		},
		posRelative: null,
		onHide: Class.empty,
		onShow: Class.empty,
		onFirstShow: Class.empty,
		transition: Fx.Transitions.Quad.easeInOut
	},
	initialize: function(options){
		this.setOptions(options);
		this.isShowing = false;
		this.shownOnce = false;
		this.mask = false;
		this.pop = false;
		this.event = window.event;

		this.isIE6 = false;
		if (Browser.Engine.trident && Browser.Platform.win && (Browser.Engine.version<=4)) {
			this.isIE6 = true;
		}
		if (Browser.Engine.trident && Browser.Platform.win) {
			this.options.useArrows = false;
		}		

		this.fx_dir = 0; // track whether showing/hiding
		this.fx_in_process = false;
		
		window.addEvents({
			'keyup': this.esc.bindWithEvent(this),
			'resize': function(e){ 
				this.update(e);
				if(this.isShowing){
					this.isShowing = false;
					this.show();
				}
			}.bind(this),
			'scroll': this.update.bindWithEvent(this)
		});
		this.init();
	},
	init: function(){
		if (this.pop) {
			this.pop.destroy();
		}
		this.add_pop();
		var fxels = [this.pop];

		if (this.options.isModal) {
			this.add_mask();
			fxels[1] = this.mask;
		} else if (this.isIE6) {
			this.options.maskColor = '#FFF';
			this.add_mask();
		}
		this.fx = new Fx.Elements(fxels, {
			wait: false, 
			duration: this.options.speed, 
			transition: this.options.transition,
			onStart: function() {
				this.fx_in_process = true;
			}.bind(this), 
			onComplete: function() {
				switch (this.fx_dir) {
					case 1:
						if (!this.shownOnce) {
							this.shownOnce = true;
							this.fireEvent('firstShow');
						}
						this.isShowing = true;
						if (this.options.isModal) {
							this.pop.fireEvent('focus', '', 200); // to activate pop close by ESC, the ESC keydown for window doesn't work in IE
						}
						this.fireEvent('show');
						break;
					case 0:
						this.isShowing = false;
						this.pop.setStyles({
							'visibility':'hidden',
							'display': 'none'
						});
						if (this.options.isModal) {
							this.mask.setStyle('display', 'none');
						}
						if (!this.options.isModal && this.mask) {
							this.mask.set('opacity',0);
						}
						this.fireEvent('hide');
						break;				
				}
				this.fx_in_process = false;
			}.bind(this)
		});
	},
	add_mask: function(){
		if (!this.mask)	{
			var mask_styles = {
				'position':'absolute',
				'top': 0,
				'left': 0,
				'opacity': 0,
				'z-index': 9999,
				'background-color':this.options.maskColor,
				'display': 'none'
			};
			if (this.isIE6){
				// need to use IFRAME for IE in order to cover SELECT elements
				this.mask = new Element('iframe', {
					'class':this.options.classPrefix+'Mask',
					'src':"about:blank",
					'frameborder':0,
					'src':"about:blank",
					styles: mask_styles
				}).inject(document.body);
			} else {
				// make mask a div for other browsers
				this.mask = new Element('div', {
					'class':this.options.classPrefix+'Mask',
					styles: mask_styles
				}).inject(document.body);
			}
		}
	},
	add_pop: function(){

		/*
		<div class="Pop">			
			<TABLE class="grid">
				<TR>
					<TD class="nw"></TD>
					<TD class="north"></TD>
					<TD class="ne"></TD>
				</TR>
				<TR>
					<TD class="sw"></TD>
					<TD class="s"></TD>
					<TD class="se"></TD>
				</TR>
			</TABLE>
		</div>
		*/

		this.pop = new Element('div', {
			'class':this.options.classPrefix+'Pop',
			'styles':{
				'position': 'absolute',
				'visibility': 'hidden',
				'top': -1000,
				'left': 0,
				'z-index': 10000,
				'display': 'none'
			}
		}).inject(document.body, 'bottom');

		this.pop.addEvent('keydown', function(e){ 
			this.esc(e);
		}.bind(this));

		// add table for pop with border graphics
		this.poptbl = new Element('table',{ 'class':'grid' }).inject(this.pop);
		this.poptbody = new Element('tbody').inject(this.poptbl);

		[['nw', 'north', 'ne'],['sw', 's', 'se']].each(function(tds) {
			this.insertPopTblRow(tds);
		}.bind(this));
		// assign td class "north" as contents block of pop
		this.popc = this.poptbl.getElement('td[class=north]');

		if (this.options.useArrows)	{
			this.addPopArrows();
		}

		if (this.options.addCloseBtn) {
			this.close = new Element('div',{
				'class':this.options.classPrefix+'Close'
			}).inject(this.pop);
			var close_a = new Element('a', {
				'href':'#',
				'title':this.options.strs.close,
				'events':{
					'click':this.hide.bindWithEvent(this)
				}
			}).inject(this.close);
			close_a.addEvent('click', function(e){ 
				if(e) e = new Event(e).stop();
				this.hide();
			}.bind(this));	
		}
	},
	cursor_pos: function(e) {
		if (!e) {e = window.event;}
		return {'x':e.page.x, 'y':e.page.y};
		return cursor;	
	},
	insertPopTblRow: function(tds){
		var tr = new Element('tr').inject(this.poptbody);
		tds.each(function(cls) {
			var td = new Element('td',{ 'class':cls }).inject(tr);
		});
	},
	addPopArrows: function(){
		// insert pop arrows into pop if they don't already exist
		var an = this.pop.getElement('div[class$=p]');
		if (!an) {
			['n','s','e','w'].each(function(d) {
				var arrw = new Element('div',{ 'class':'a'+d+' p', 'styles': { 'visibility':'hidden'} }).inject(this.pop);
				var styles = {};
				var h = arrw.getStyle('height');
				if (h) h = h.toInt();
				var w = arrw.getStyle('width');
				if (w) w = w.toInt();
				switch (d) {
					case 'n':
						styles.top='auto';
						if ($type(h)=='number') styles.bottom = 1 - h;
						break;
					case 's':
						if ($type(h)=='number') styles.top = 1 - h;
						break;
					case 'e':
						if ($type(w)=='number') styles.left = 1 - w;
						break;
					case 'w':
						if ($type(w)=='number') styles.right = 1 - w;
						break;				
				}
				arrw.setStyles(styles);
			}.bind(this));
		}
	},
	show_arrow: function(io, align) {
		if (!this.isIE6)	{
			var arrw,p={top:0,left:0},a={},nsew='';

			switch (io) {
				case 1:
					nsew = align.substr(0,1);
					break;
				case -1:				
					switch (align) {
						case 'n':
							nsew = 's';
							break;
						case 'w':
							nsew = 'e';
							break;
						case 'e':
							nsew = 'w';
							break;
						case 's':
							nsew = 'n';
							break;				
					}
					break;
			}
			this.pop.getElements('div[class$=p]').each(function(el) {
				if (el.hasClass('a'+nsew)) {
					el.set('opacity',1);
					el.setStyle('z-index',(this.pop.getStyle('z-index').toInt()+1));
					arrw = el;
				} else {
					el.set('opacity',0);
				}
			}.bind(this));

			if (arrw) {

				var axy = {
					'x':arrw.getStyle('width').toInt(),
					'y':arrw.getStyle('height').toInt()
				};

				switch (io) {
					case 1:
						// outside 
						switch (align) {
							case 'nw': 
							case 'sw':
								a = {
									'left': this.options.cornerRadius,
									'right': 'auto'
								};
								break;
							case 'n':
							case 's':
								a = {
									'left': this.popsize.x/2 - axy.x/2,
									'right': 'auto'
								};
								break;
							case 'ne':
							case 'se':
								a = {
									'left': 'auto',
									'right': this.options.cornerRadius
								};
								break;
							case 'wn':
							case 'en':
								a = {
									'top': this.options.cornerRadius,
									'bottom': 'auto'
								};
								break;
							case 'w':
							case 'e':
								a = {
									'top': this.popsize.y/2 - axy.y/2,
									'bottom': 'auto'
								};
								break;
							case 'ws':
							case 'es':
								a = {
									'top': 'auto',
									'bottom': this.options.cornerRadius
								};
								break;			
						}
						
						switch (align) {
							case 'nw': 
							case 'n':
							case 'ne':
								p.top = -axy.y;
								break;
							case 'wn':
							case 'w':
							case 'ws':
								p.left = -axy.x;
								break;
							case 'en':
							case 'e':
							case 'es':
								p.left = axy.x;
								break;
							case 'sw':
							case 's':
							case 'se':
								p.top = axy.y;
								break;		
						}
						break;
					case -1:
						// inside 
						switch (align) {
							case 'n':
							case 's':
								a = {
									'left': this.popsize.x/2 - axy.x/2,
									'right': 'auto'
								};
								break;
							case 'w':
							case 'e':
								a = {
									'top': this.popsize.y/2 - axy.y/2,
									'bottom': 'auto'
								};
								break;
						}					
						switch (align) {
							case 'n':
								p.top = axy.y;
								break;
							case 'w':
								p.left = axy.x;
								break;
							case 'e':
								p.left = -axy.x;
								break;
							case 's':
								p.top = -axy.y;
								break;				
						}						
						break;
				}

				arrw.setStyles(a);

				return {'p':p, 'a':axy};
			}
		}
	},
	set_contents: function(msg, cls, width) {
		this.shownOnce = false;

//		if (($type(cls)=='undefined') || (cls=='')) {
//			cls = 'n';
//		}
		if (this.popc) {
			this.popc.className = 'north ' + cls;
		}
		if (this.popc) {
			this.popc.empty();
			if (cls != '')	{
				var tipnote = new Element('div',{'class':'mi'}).inject(this.popc);

				switch($type(msg)) {
					case 'element':
						var msg_cl = msg.clone(true,true).cloneEvents(msg).inject(tipnote);
						break;
					case 'string':
						tipnote.set('html',msg);
						break;
				}
			} else {
				switch($type(msg)) {
					case 'element':
						var msg_cl = msg.clone(true,true).cloneEvents(msg).inject(this.popc);
						break;
					case 'string':
						this.popc.set('html',msg);
						break;
				}
			}
		}
		if (width) {
			if ((width != 'auto') && (width>0)) {
				width = width.toInt();
			}
			if (width) {
				this.poptbl.setStyle('width',width);
			}
		}

		// determine the width/height of the pop after adding new content to pop

		var was_dn = false;
		if (this.pop.getStyle('display') == 'none') {
			was_dn = true;
			this.pop.setStyle('display', 'block');
			this.pop.setStyle('visibility', 'visible');
//			console.log('pop display was none, now set to block')
		}
		this.popsize = this.pop.getSize();

//		console.log('pop width: ' + this.popsize.x)
		if (width && (this.popsize.x < width)) {
			this.popsize.x = width;
		}
		if (was_dn) {
			this.pop.setStyle('display', 'none');
		}
	},
	esc: function(e){
		if (this.isShowing && (e.key == 'esc'))	{
			this.hide();
		}
	},
	show: function() {
		if(!this.isShowing){

			// set the starting position of the pop
			var start = {
				'visibility':'visible',
				'display': 'block',
				'opacity': 0
			};

			// both fade and fly trans fades in
			var fx = {
				'0': { 
					'opacity': this.options.popOpacity
				}
			};

			var se = this.options.place.se;
			var ss = this.options.place.ss;

			var end_xy = this.coord(se.target, se.io, se.align, se.offset, true);

			if ((se.trans == 'fly')) {

				fx['0'].top = end_xy.top;
				fx['0'].left = end_xy.left;
				fx['0'].margin = se.margin;

				if (($type(ss) == 'object') && (ss.target !=='')) {

					var start_xy = this.coord(ss.target, ss.io, ss.align, ss.offset, false);
					if (start_xy) {
						fx['0'].top = [start_xy.top,end_xy.top];
						fx['0'].left = [start_xy.left,end_xy.left];
					}
				}


			} else {
				// just fade into the end coords
				start.top = end_xy.top;
				start.left = end_xy.left;
			}
			this.pop.setStyles(start);

			// show fx for pop

			if (this.options.isModal) {
				this.add_mask(); // only adds one if it doesn't exist
				this.mask.setStyles({
					'height': window.getScrollHeight(),
					'width': window.getScrollWidth(),
					'display': 'block'
				});
				// fx for mask
				fx['1'] = { 'opacity': this.options.maskOpacity };
			} else {
				if (!this.options.isModal && this.isIE6) {
					this.mask.setStyles({
						'height': this.popsize.y,
						'width': this.popsize.x,
						'display': 'block',
						'visibility':'visible',
						'top': end_xy.top,
						'left':end_xy.left
					});
				}
			}
			this.fx_dir = 1;
			this.fx.start(fx);
		}
	},
	hide: function(e) {
		if(this.pop.getStyle('opacity')>0) {
			this.fx.cancel();
			this.fx_dir = 0;
			// fx for pop
			var fx = {
				'0': { 
					'opacity': 0
				}
			};
			var he = this.options.place.he;

			if (he.trans == 'fly') {

				var se = this.options.place.se;
				var start_xy = this.coord(se.target, se.io, se.align, se.offset, false);

				var end_xy = this.coord(he.target, he.io, he.align, he.offset, false);

				fx['0'].top = [start_xy.top,end_xy.top];
				fx['0'].left = [start_xy.left,end_xy.left];
				fx['0'].margin = he.margin;
			}
			if (this.options.isModal) {
				// fx for mask
				fx['1'] = { 'opacity': 0 };
			}
		
			this.fx.start(fx);
		}
	},
	update: function(e) {
//		if(e) e = new Event(e).stop();
		if (this.isShowing) {
			if (this.options.isModal) {
				// resize the mask to the new size of the window
				var size = window.getSize();
				var scrollSize = window.getScrollSize();
				this.mask.setStyles({
					'height': (size.y > scrollSize.y)?size.y:scrollSize.y,
					'width': size.x
				});
			}
			var se = this.options.place.se;
			if ((se.target == 'window') && (se.io==-1)) {
				// if the pop is inside the window
				this.fx.cancel();

				var coord = this.coord('window', -1, se.align, se.offset, false);

				// move pop to the center of visible screen
				this.fx.start({
					'0': { 
						'top': coord.top,
						'left': coord.left,
						'margin': se.margin
					}
				});
			}
		}
	},
	movePop: function(target, io, align, offset, margin) {
		var coord = this.coord(target, io, align, offset, true);
		if (coord)
		{
			this.pop.setStyles({
				'top': coord.top,
				'left': coord.left,
				'margin': margin
			});
		}
	},
	max: function(obj) {
		var max;
		for (var z in obj){
			if (max) {
				if (obj[z] > obj[max]) {
					max = z;
				}
			} else {
				max = z;
			}
		};
		return max;
	},
	auto_align: function(el, default_align) {

		// auto target best align for display of tip depending on scroll, window size, target size, and pop size
		var win = {'x': window.getWidth(), 'y': window.getHeight()};
		var scroll = {'x': window.getScrollLeft(), 'y': window.getScrollTop()};
		var elpos = el.getPosition();
		var eldim = { 'x':el.offsetWidth, 'y':el.offsetHeight };
		var popdim = { 'x':this.pop.offsetWidth, 'y':this.pop.offsetHeight };
		var align='';

		// determine which side has the most visible space
		// visible space

		var vs = {
			'top': elpos.y - scroll.y,
			'right': (win.x + scroll.x) - (elpos.x + eldim.x),
			'bottom': (win.y + scroll.y) - (elpos.y + eldim.y),
			'left': elpos.x - scroll.x
		};
		var vista = this.max(vs);

		if ((typeof(default_align)!='undefined') && (default_align != 'auto') && (default_align!='')) {
			// if there was a default, check to see if it will work
			align = default_align;
			var nesw = align.substr(0,1);
			switch (nesw) {
				case 'n':
					if (vs.top < this.popsize.y) {
						align='';
					}
					break;
				case 'e':
					if (vs.right < this.popsize.w) {
						align='';
					}
					break;
				case 's':
					if (vs.bottom < this.popsize.y) {
						align='';
					}
					break;
				case 'w':
					if (vs.left < this.popsize.w) {
						align='';
					}
					break;
			
			}
		}
		
		if (align == '') {

			// by determining the side on which the mouse entered, we know that there is space on that side

			if ((vista=='top')||(vista=='bottom')) {
				switch (vista) {
					case 'top':
						align = 'n';
						break;
					case 'bottom':
						align = 's';
						break;
				}
				if ((vs.right < 0) && (vs.left < 0)) {
					// both sides are covered
					if (vs.right > vs.left)	{
						// right side covered less
						align += 'e';
//						op.se.margin = '0 ' + (-vs.right + op.se.offset) + 'px 0 0';
					} else {
						// left side covered less
						align += 'w';
//						op.se.margin = '0 0 0 ' + (-vs.left + op.se.offset) + 'px';
					}
				} else if (vs.right < 0) {
					// right side is covered, but not left
					align += 'w';
				} else if (vs.left < 0) {
					// left side is covered, but not right
					align += 'e';
				}
			} else {
				switch (vista) {
					case 'right':
						align = 'e';
						break;
					case 'left':
						align = 'w';
						break;
				}
				if ((vs.top < 0) && (vs.bottom < 0)) {
					// both top & bottom are covered
					if (vs.top > vs.bottom)	{
						// top side covered less
						align += 'n';
//						op.se.margin = (-vs.right + op.se.offset) + 'px 0 0 0';
					} else {
						// bottom side covered less
						align += 's';
//						op.se.margin = '0 0 ' + (-vs.left + op.se.offset) + 'px 0';
					}
				} else if (vs.top < 0) {
					// top side is covered, but not bottom
					align += 's';
				} else if (vs.bottom < 0) {
					// bottom side is covered, but not top
					align += 'n';
				}
			}
		}
		return align;
	},
	coord: function(target, io, align, offset, arr_mode) {
		var top=0,left=0,tdim=0;
		
		this.fireEvent('beforeCoord');
		
		if (target == 'window') {
			top = window.getScrollTop();
			left = window.getScrollLeft();
			tdim = { 'x':window.getWidth(), 'y':window.getHeight() };
		} else {
			if ($type(target)=='string') {
				var t = $(target);
			} else {
				var t = target;
			}
			if (t) {
				// figure out if the element is in the same window as the dialog
				var tpos = t.getPosition();
				if (!tpos && (t.getStyle('display')=='inline')) {
					var tpos = this.cursor_pos(this.event);
					top = tpos.y;
					left = tpos.x;
					tdim = { 'x':1, 'y':1 };
				} else {
					var tpos = t.getPosition();
					if (tpos) {
						top = tpos.y;
						left = tpos.x;
						tdim = { 'x':t.offsetWidth, 'y':t.offsetHeight };
					}
				}
				if (!$defined(align)) {
					align = this.auto_align(t,'auto');
				}
			}
		}
		if (tdim) {

			if ((arr_mode===true) && this.options.useArrows) {
				var pa = this.show_arrow(io, align);
			}

			var nesw = align.substr(0,1);
			switch (io) {
				case 1:
					// outside 
					switch (nesw) {
						case 'n':
							top -= (this.popsize.y + offset);
							break;
						case 'e':
							left += (tdim.x + offset);
							break;
						case 's':
							top += (tdim.y + offset);
							break;
						case 'w':
							left -= (this.popsize.x + offset);
							break;					
					}

					// move pop if the size of pop is bigger than the target
					switch (align) {
						case 'nw':
						case 'sw':
							if ((tdim.x < this.popsize.x) && pa) {
								left -= pa.a.x/2;
							}
							break;
						case 'ne':
						case 'se':
							if ((tdim.x < this.popsize.x) && pa) {
								left += pa.a.x/2;
							}
							break;
					}

					switch (align) {
						case 'n': // above target, centered
							left += (tdim.x/2 - this.popsize.x/2);
							break;
						case 'ne': // above target, right aligned
							left += (tdim.x - this.popsize.x);
							break;
						case 'w': // left of target, middle aligned
							top += (tdim.y/2 - this.popsize.y/2);
							break;
						case 'ws': // left of target, bottom aligned
							top += (tdim.y - this.popsize.y);
							break;
						case 'e': // right of target, middle aligned
							top += (tdim.y/2 - this.popsize.y/2);
							break;
						case 'es': // right of target, bottom aligned
							top += (tdim.y - this.popsize.y);
							break;
						case 's': // below target, middle aligned
							left += (tdim.x/2 - this.popsize.x/2);
							break;				
						case 'se': // below target, right aligned
							left += (tdim.x - this.popsize.x);
							break;				
					}
					break;
				case -1:
					// inside 
					switch (nesw) {
						case 'n':
							top += offset;
							break;
						case 's':
							top += (tdim.y - this.popsize.y - offset);
							break;
					}
					switch (align) {
						case 'nw':
							left += offset;
							break;
						case 'n':
							left += (tdim.x/2 - this.popsize.x/2);
							break;
						case 'ne':
							left += (tdim.x - this.popsize.x - offset);
							break;
						case 'w':
							top += (tdim.y/2 - this.popsize.y/2);
							left += offset;
							break;
						case 'c':
							top += (tdim.y/2 - this.popsize.y/2);
							left += (tdim.x/2 - this.popsize.x/2);
							break;
						case 'e':
							top += (tdim.y/2 - this.popsize.y/2);
							left += (tdim.x - this.popsize.x - offset);
							break;
						case 'sw':
							left += offset;
							break;				
						case 's':
							left += (tdim.x/2 - this.popsize.x/2);
							break;				
						case 'se':
							left += (tdim.x - this.popsize.x - offset);
							break;				
					}
					break;

			}
			if (pa) {
				top += pa.p.top;
				left += pa.p.left;
			}
			if (this.posRelative) {
				top += this.posRelative.y;
				left += this.posRelative.x;
			}
			return { 'top': top, 'left': left };
		}
		return false
	},
	destroy: function() {
		if (this.mask) {
			this.mask.remove();
		}
		this.pop.remove();
	}

});
var AscModal = new Class({
	Implements: [Options,Events], 
    Extends: AscDialog,
 	options: {
		isModal: true,
		addCloseBtn: true,
		popOpacity: .9,
		classPrefix: 'Modal',
		place: {
			'ss': { target:'window', io:1, align:'n'}, // show start
			'se': { trans:'fly', target:'window', io:-1, align:'c'}, // show end
			'he': { trans:'fly', target:'window', io:1, align:'n'} // hide end
		}
	},
	initialize: function(msg, cls, options){
        this.parent(options); 
		this.set_contents(msg, cls);
    }
});
var AscTip = new Class({
	Implements: [Options,Events], 
    Extends: AscDialog,
 	options: {
		addCloseBtn: false,
		speed: 200,
		useArrows: true,
		popOpacity: .9,
		actionDelay: 50,
		showDelay: 0,
		hideDelay: 0,
		default_align:'auto',
		classPrefix: 'Tip',
		place: {
			'ss': { 'io':1, offset:16 }, // show start
			'se': { 'io':1, offset:6 }, // show end
			'he': { trans:'fade' } // hide end
		}
	},
	initialize: function(el, msg, cls, options, width){
        this.parent(options);
		this.current_el;
		this.mousein = false;

		if ($type(el)=='element') {
			this.enable_tip(el, msg, cls, width);
		} 
    },
	enable_tip: function(el, msg, cls, width, align) {
		if (el) {
			el.addEvents({
				'mouseenter': function(e) {
					this.event = e;
					this.current_el = el;
					this.mousein = true;
					$clear(this.timer);
					this.timer = this.do_show.delay(this.options.showDelay, this, [el, msg, cls, width, align]);

				}.bind(this),	 
				'mouseleave': function(e) {
					this.mousein = false;
					$clear(this.timer);
					if (this.current_el == el) {
						this.current_el = '';
					}
					if (this.fx_in_process && (this.fx_dir == 1)) {
						this.isShowing = true;
						this.hide();
					} else {						
						this.timer = this.hide.delay(this.options.hideDelay, this);
					}
				}.bind(this),	 
				'outerClick': function() {
					this.mousein = false;
					this.hide();
				}.bind(this)
			});
		}
		return false;
	},
	do_show: function(el, msg, cls, width, align) {
		if (this.mousein && (this.current_el == el)) {

			var op = this.options.place;

			this.set_contents(msg, cls, width);

			if (!$chk(align)) {
				align = this.options.default_align;
			}

			var settings = {
				'target':el,
				'align':this.auto_align(el, align)
			};
			if (op.se.trans=='fly')	{
				$extend(op.ss, settings);
				op.ss.offset = 25;
			}
			if (this.isShowing || this.fx_in_process) {
				if (this.fx_in_process) {
					this.fx.cancel();
				}
				op.ss.target = '';
			}
			this.isShowing = false;
			$extend(op.se, settings);
			$extend(op.he, settings);

			this.show();
		}
	}
});
var AscTips = new Class({
	Implements: [Options,Events], 
    Extends: AscTip,
 	initialize: function(els, options){
        this.parent('', '', '', options);
		if ($type(els)=='array') {
			var i, ct=els.length,t;
			for (i=0;i<ct;i++ ) {
				if (els[i]) {
					t = $(els[i].id);
					if (t) {
						this.enable_tip(t, els[i].msg, els[i].cls, els[i].width, els[i].align);
					}
				}
			}
		}
    }
});


/*
 *	Ascribe Data Systems LLC
 *	www.ascribedata.com
 *
 *	by Truman Leung <tru@ascribedata.com>
 *	Honolulu, Hawaii, USA
 *
 *	"Ascribe greatness to our God, the Rock. 
 *	His works are perfect and all His ways are just."
 *							... glory to Jesus Christ
 *	4/28/2006
 *	3/31/2008 - make into moo class
 *  10/24/08 - convert to MooTools 1.2.1
 *	session_alert.2.1.js
 *	
 *	displays modal dialog to alert pending logout
 *	close dialog by clicking close icon or ESC
 *	plays clock sound when dialog shown, stop sound when dialog hidden
 *	continues to play sound in last logout sequence (30 sec) even if dialog is hidden
*/
var AscSessionAlert = new Class({
	Implements: Options, 
	options: {
		strs: {
			'auto_logout': 'Auto Sign Out',
			'move_or_save': "Please move to another page or submit any forms before then so you won't lose any inputted information.",
			'session_alert': "An automatic sign out occurs for security reasons if a page is still open after %d minutes.",
			'auto_sign_out_in': "You will be automatically signed out in:",
			'close': "Click to close"
		},
		lifetime: 90, // 90 minutes
		last_countdown: 30,
		duration: 10,
		alerts: [10,6,3,2],
		sm: ''
	},
	initialize: function(options){
		this.setOptions(options);
		var s;
		for (s in this.options.strs) {
			if (typeof(this.options.strs[s])=='string') {
				this.options.strs[s] = translate_magic_quotes(this.options.strs[s]);
			}
		}
		this.options.lifetime = this.options.lifetime.toInt();
		this.options.last_countdown = this.options.last_countdown.toInt();
		this.debug = false;
		this.secleft = this.options.lifetime * 60;

		this.enabled = true;

		// call this function every sec
		this.countdown.periodical(1000, this); 

		this.curr_alert_id = 0;
		this.timer_id;

		this.alerts_ct = this.options.alerts.length;
		this.alerts_sec = [];
		for(var i=0; i < this.alerts_ct; i++) {
			this.alerts_sec[i] = this.options.alerts[i].toInt() * 60;
		}

		this.alert_cancel_secs = [];

		var c = new Element('div');
		var h2 = new Element('h2').set('html', this.options.strs.auto_logout).inject(c);
		var p = new Element('p',{'class':'med'}).set('html', this.options.strs.session_alert).inject(c);
		var p2 = new Element('p',{'class':'sm'}).set('html', this.options.strs.move_or_save).inject(c);;
		var p3 = new Element('p',{'class':'alert'}).set('html', this.options.strs.auto_sign_out_in).inject(c);
//					alert('post p');
		var cd = new Element('div',{'id':'asc_modal_cd', 'class':'cd'}).inject(c);

		this.modal = new AscModal(c, 'n', {
			strs: { 'close': this.options.strs.close },
			classPrefix: 'Modal',
			onShow: function() {
//				soundManager.play('clocktick');
			}.bind(this),
			onHide: function() {
				if (this.secleft > this.options.last_countdown) {
//					soundManager.stop('clocktick');	
				} else {
					// if this is the last countdown and the user hides the modal, disable it so it doesn't auto-reappear
					this.enabled = false;
				}
				this.alert_cancel_secs[this.alert_cancel_secs.length] = this.secleft;
			}.bind(this)
		});

	},
 	countdown: function(){
		if (this.secleft == -1) {
			// send to logout
			window.location.href = 'ascribe.logout.php';
		} else {
			if (this.debug) {
				this.trash.set('html', "seconds until logout: " + this.secleft + ", curr_alert_id: " + this.curr_alert_id + ", next alert scheduled on: " + this.alerts_sec[this.curr_alert_id] + ", session_auto_logout_countdown: " + this.options.last_countdown);
			}
			var at = this.alert_type();
			if (at) {

				var cd_formatted = this.cd_str();
				if (!this.modal.isShowing && !this.modal.fx_in_process && this.enabled) {
//					alert('pre p '+ this.options.strs.session_alert);

					this.modal.popc.removeClass('n');
					this.modal.popc.removeClass('i');
					this.modal.popc.addClass(at);
					this.modal.show();
				}
				var cd_obj = $('asc_modal_cd');
				if (cd_obj) {
					cd_obj.set('html', cd_formatted);
				}
			} else {
				this.modal.hide();
			}
			this.secleft--;
		}
	},
	cd_str: function() {
		var m = Math.floor(this.secleft/60);
		var s = this.secleft % 60;
		if (s < 10) {
			s = '0' + s.toString();
		} else {
			s = s.toString();
		}
		return m.toString() + ':' + s;
	},
	within_alert_window: function(start_sec) {
		
		if (
			(this.secleft <= start_sec)
				&&
			(this.secleft > (start_sec - this.options.duration))
			)
		{
			return true;
		}
		return false;
	},
	alert_window_canceled: function(start_sec) {
		var acs_ct = this.alert_cancel_secs.length;
		if (acs_ct) {
			var i, cancel_sec;
			for(var i=0; i < acs_ct; i++) {
				cancel_sec = this.alert_cancel_secs[i];
				if (
					(cancel_sec <= start_sec)
						&&
					(cancel_sec > (start_sec - this.options.duration))
					)
				{
					return true;
				}
			}
		}
		return false;
	},
	alert_type: function() {
		if (this.secleft <= this.options.last_countdown) {
			return 'f'; // final
		} else {
			for(var i=0; i < this.alerts_ct; i++) {
				// if currently between when an alert should start and end
				if (this.within_alert_window(this.alerts_sec[i])) {
					if (!this.alert_window_canceled(this.alerts_sec[i])) {
						if (i == (this.alerts_ct-1)) {
							return 'i'; // important cause last normal alert
						} else {
							return 'n'; // normal
						}
					}
				}
			}
		}
		return false;
	}
});
var AscSessAlert;
//soundManager.url = sm_swf_path;
//soundManager.debugMode = false;

function init_salert() {
/*
	soundManager.onload = function() {
		soundManager.createSound({
			id: 'clocktick',
			url: sm_logout_mp3_path,
			autoLoad: true,
			autoPlay: false,
			volume: 25
		});
	}
*/
	if (typeof(sess_alert_strs)=='object') {
		AscSessAlert = new AscSessionAlert({
			'strs': sess_alert_strs,
			'lifetime': session_lifetime_min,
			'last_countdown': session_auto_logout_countdown,
			'duration': seconds_alert_duration,
			'alerts': session_auto_logout_alerts
		});
	}
}
window.addEvent('domready', init_salert);


/*
 *	Ascribe Data Systems LLC
 *	www.ascribedata.com
 *
 *	by Truman Leung <tru@ascribedata.com>
 *	Honolulu, Hawaii, USA
 *
 *	"Ascribe greatness to our God, the Rock. 
 *	His works are perfect and all His ways are just."
 *							... glory to Jesus Christ
 *	nav/intranet.js
 *
 *	9/24/2007
 *	2/15/2008 - optimize to use less memory
 *		- rewrite as a moo class
 *		- remove the gradient animation in the subnav
 *	8/5/08 2:44 PM - fix so that the subnavs donÕt disappear when they shouldnÕt
 *  10/24/08 - convert to MooTools 1.2.1
 *  3/24/2009 - optimize sub menu widths
 *
 *	mi - main item
 *	dd - drop down sub section 
*/
var AscIntranetNav = new Class({
	Implements: [Options,Events], 
	options: {
		debug: false,
		mi_height: 36,
		duration: 300,
		fly_offset: 30 
	},
	initialize: function(options){
		this.setOptions(options);

		this.mn = $('main-nav');
		if (this.mn) {
			this.sn = $('sub-nav');
			this.sn_m = $('sub-nav-m');
			var main_items = $$('#main-nav .mi');
			this.kwicks = $$('#kwick .kwick');
			this.dds = $$('#sub-nav .dd');
			this.kwick = $('kwick');
			this.mn_w = this.mn.getScrollSize().x;
			this.dd_showing = ''; // id of the dd currently visible
			this.mouseover_sub_nav = false; 
			this.mouseover_mi = ''; // id of current mi
			this.mi_clicked = ''; // id of the mi that was just clicked
			this.curr_sect = ''; // current section (mi or dd)
			this.sub_nav_visible = false;
			this.mi_mouseenter_active = false;
			this.bckgrnd_iframe = null;
			this.sn_snm_fx = null;

			this.isIE6 = false;
			if (Browser.Engine.trident && Browser.Platform.win && (Browser.Engine.version<=4)) {
				this.isIE6 = true;
			}

			window.addEvent('resize', this.sense_widths.bindWithEvent(this));
			this.sense_widths();

			if (this.options.debug) {
				this.debug_window = new Element('div', {
					'id':'mn_debug_window'
				}).inject('body_inner','top');
				this.debug_window.set('opacity',0.8);
				this.dln = 0; // debug line number
			}

			this.hide_sub_nav_fx = new Fx.Morph(this.sn, {
				duration:300, 
				wait:false, 
				transition: Fx.Transitions.Expo.easeInOut,
				onComplete: function() {
					this.adm('hide_sub_nav_fx has been completed');
					this.sn.set('opacity',0);
					this.sn.setStyles({
						visibility: 'hidden',
						display:'none'
					}); 
					this.sub_nav_visible = false;
					this.dd_showing = '';
					this.hide_other_dds(' ');
					main_items.each(function(mi){
						this.restore_mi(mi);
					}.bind(this));
					if (this.isIE6) {
						this.bckgrnd_iframe.setStyles({
							visibility:'hidden',
							display:'none'
						}); 
					}
				}.bind(this)
			});
			this.kwicks_fx_group = new Fx.Elements(this.kwicks, {
				wait: false, 
				duration: this.options.duration, 
				transition: Fx.Transitions.Expo.easeOut
			});

			this.mouseover_kwick = false; 
			this.kwick.addEvents({
				'mouseenter': function(e) {
					this.mouseover_kwick = true; 
					asc_tooltips.hide();
				}.bind(this),	 
				'mouseleave': function(e) {
					this.mouseover_kwick = false;
				}.bind(this)
			});
			
			$('mn_search_div').addEvent('click', function(e){ 
				$('navsearchterms').focus(); 
			});

			var pos = this.mn.getPosition();
			this.sn.setStyles({
				top: pos.y + this.options.mi_height.toInt(),
				left: pos.x + this.mn.scrollWidth/2
			}); 
			this.sn.addEvents({
				'mouseenter': function(e) {
					this.mouseover_sub_nav = true; 
					if (this.hide_sub_nav_fx) { this.hide_sub_nav_fx.cancel(); }
				}.bind(this),	 
				'mouseleave': function(e) {
					this.mouseover_sub_nav = false;
					this.adm('mouse out from sub nav');
					$clear(this.timer);
					this.timer = this.sn_mousegone.delay(500,this);
				}.bind(this)
			});

			// determine the scroll height width of each dd and the links within them
			this.dd_hw = {};
			this.dds.each(function(dd){ 
				var dd_cols = $$('#' + dd.id + ' div.col');
				var col_a_max_w = 0;
				var dd_width;
				if (dd_cols.length > 0) {
					// multi column dd
					dd_cols.each(function(col){ 
						col_a_max_w = this.set_width_of_link_array($$('#' + col.id + ' a'));
						col.setStyle('width', col_a_max_w + 25); 
					}.bind(this));
					dd_width = dd.scrollWidth.toInt();
				} else {
					// single column dd
					var anchors = dd.getElements('a');
					col_a_max_w = this.set_width_of_link_array(anchors);
					dd_width = col_a_max_w + 25;
				}

				// make sure the width doesn't extend past the right edge
				// only do this check for the middle main items
				var mi_id = dd.id.substr(0, (dd.id.length - 3));
				if (["mi-home","mi-admin"].contains(mi_id) === false) {
					var mn_right = pos.x + this.mn.scrollWidth;
					var mi = $(mi_id);
					if (mi) {
						var mi_pos = mi.getPosition();
						if (mi_pos) {
							var mi_left = mi_pos.x;
							if ((mi_pos.x + dd_width) > mn_right) {
								dd_width = mn_right - mi_pos.x - 16;
								// now that the dd has been shortened, need to shorten the links
								if (dd_cols.length === 0) {
									var new_a_width = dd_width - 25;
									$$('#' + dd.id + ' a').each(function(a_dd){ 
										a_dd.setStyle('width', new_a_width); 
									});
								}
							}

						}
					}
				}

				var dd_height = dd.scrollHeight.toInt();
				this.dd_hw[dd.id] = { 'height': dd_height, 'width': dd_width}; 
				dd.setStyles(this.dd_hw[dd.id]); 

				this.adm("<b>initializing dimensions</b> " + dd.id + ", num cols=" + dd_cols.length + ", h=" + dd_height + ", w=" + dd_width);
				this.hide_dd(dd);
			}.bind(this));
			this.kwicks.each(function(kw, i){
				kw.addEvent('mouseover', function(e){
					var obj = {};
					var this_w_start = kw.getStyle('width').toInt();
					obj[i] = {
						'width': [this_w_start, 100]
					};
					this.kwicks.each(function(other, j){
						if (other) {
							if (other != kw){
								var w = other.getStyle('width').toInt();
								if (w) {
									if (w != 67) { obj[j] = {'width': [w, 67]}; }
								}
							}
						}
					});
					this.kwicks_fx_group.start(obj);
				}.bind(this));
			}.bind(this));
			this.mi_bgx = {}; // an object to store all the background x positions for main items
			main_items.each(function(mi, i){
				// determine background x pos
				if (Browser.Engine.gecko) {
					var bp = mi.getStyle('background-position');
					if (bp) {
						var bpa = bp.split(' ');
						this.mi_bgx[mi.id] = bpa[0];	
					}
				}
				mi.addEvents({
					'click': function(e) {
						// save id of mi so that bg is not shifted on mouseleave
						this.mi_clicked = mi.id;
					}.bind(this),
					'mouseenter': function(e) {
						$clear(this.timer);
						this.timer = this.mi_mouseenter.delay(2, this, mi); 
					}.bind(this),	 
					'mouseleave': function(e) {
						$clear(this.timer);
						this.timer = this.mi_mouseleave.delay(5, this, mi); 
					}.bind(this)
				});
			}.bind(this));

		}
	
	},
	sense_widths: function() {
		/*
		2/16/2009 - if the page contains a table larger than the width of the defined user screen width, auto enlarge
		*/
		var sprdsht = $('sprdsht');
		var cDoc = $('custom-doc');
		if (sprdsht && cDoc) {
			var sprdsht_w = sprdsht.getScrollSize().x;
			if (cDoc.getStyle('width').toInt() < sprdsht_w) {
				cDoc.setStyle('width', sprdsht_w);
				this.mn_w = sprdsht_w;
			}

		}

		$('main-nav-back').setStyle('width', (this.mn_w - 40)); 
		if (Browser.Engine.trident) {
			this.kwick.setStyle('width', (this.mn_w - 40)); 
		}		
	},
	get_dd: function(mi) {
		return $(mi.id + '-dd');
	},
	hide_dd: function(dd) {
		dd.set('opacity',0); 
		dd.setStyles({
			visibility: 'hidden',
			display:'none'
		}); 
		if (dd.id == this.dd_showing) {
			this.dd_showing = '';
		}
	},
	show_dd: function(dd) {
		dd.setStyles({
			visibility: 'visible',
			display:'block'
		}); 
		this.dd_showing = dd.id;
		this.adm('this.show_dd(): ' + this.dd_showing);
	},
	set_width_of_link_array: function(as) {
		if (as) {
			var max_w = 0;
			var w = 0;
			as.each(function(a_el){ 
				w = a_el.getSize().x;
				if (w > max_w) {
					max_w = w;
				}
			});
			if (max_w > 200) { max_w = 200; }
			as.each(function(a_el){ 
				a_el.setStyles({
					width: max_w,
					display:'block'
				}); 
			});
			return max_w;
		}
	},
	mi_left_pos: function(mi, mn_left) {
		var target_mi_found = false;
		var sn_left_end = mn_left;
		this.kwicks.each(function(kw, j){
			if (kw != mi) {
				if (!target_mi_found) { sn_left_end += 68; }
			} else {
				target_mi_found = true;
			}
		});
		return sn_left_end;
	},
	mi_admin_left_pos: function(mi, mn_left, dd) { // 2/15/2008 this function may be deprecated
		var sn_left_end = mn_left;
		this.kwicks.each(function(kw, j){
			if (kw != mi) {
				sn_left_end += 68;
			} 
		});
		sn_left_end += 100;
		sn_left_end -= dd.getStyle('width').toInt();
		return sn_left_end;
	},
	sn_height: function() { 
		var sn_height_start = this.sn.getStyle('height').toInt();
		if (!sn_height_start) {	sn_height_start = this.sn.scrollHeight;	}
		if (!sn_height_start) {	sn_height_start = 100;}
		return sn_height_start;
	},
	hide_other_dds: function(dd_id) { 
		this.adm("<b>hide_other_dds(</b>" + dd_id + "<b>)</b>");
		this.dds.each(function(el){ 
			if (el.id != dd_id)	{
				this.hide_dd(el);					
			}
		}.bind(this));
	},
	make_background_layer: function() { 
		if (this.isIE6) {
			this.bckgrnd_iframe = new Element('iframe', {
				'id':'mn_iframe', 
				'src':'about:blank', 
				'scrolling':'no', 
				'frameborder':0, 
				'styles': { 
					'width':this.mn_w, 
					'top': this.sn.getStyle('top'),
					'left': this.sn.getStyle('top') 
				}
			}).inject(this.mn, 'after');
			this.bckgrnd_layer_made = true;
		}
	},
	/*
		animates three objects at once: this.sn, this.sn_m, dd
	*/
	anim_sn_dd_to_dd: function(dd, mi) {

		this.adm("<b>anim_sn_dd_to_dd</b> called from " + mi.id);
		
		asc_tooltips.hide();

		if (this.sn_snm_fx) { this.sn_snm_fx.cancel(); }
		if (this.hide_sub_nav_fx) { this.hide_sub_nav_fx.cancel(); }

		/*	
			3/24/2009 - if the sub nav is visible, animate from existing position otherwise start animation 40px to the left or right of target
		*/

		var sn_height_end = this.dd_hw[dd.id].height + 14;

		// width: make sure width doesn't extend past right edge of nav bar; width based on css style property
		var sn_m_end_width = this.dd_hw[dd.id].width + 8;
		var sn_end_width = sn_m_end_width + 20;
		if (this.isIE6) {
			sn_m_end_width += 2;
			sn_end_width += 2;
		}

		// sn portion
		
		if (this.sub_nav_visible) {

			// a sub nav is showing

			// height
			var sn_height_start = this.sn.getStyle('height').toInt();

			// left
			var sn_left_start = this.sn.getPosition().x;
			var mn_pos = this.mn.getPosition();
			var sn_left_end = 0;
			switch (mi.id) {
				case 'mi-admin':
					sn_left_end = this.mi_left_pos(mi, mn_pos.x) - sn_end_width + 101;
					break;
				case 'mi-home':
					sn_left_end = mn_pos.x + 6;
					break;
				default:
					sn_left_end = this.mi_left_pos(mi, mn_pos.x) - 1;
					break;
			}
			
			var anim_obj = {};

			// sub nav
			anim_obj[0] = {
				left: [sn_left_start, sn_left_end],
				height: [sn_height_start, sn_height_end], 
				width: [this.sn.getStyle('width').toInt(), sn_end_width],
				opacity: 0.97
			};
			// this.adm("anim_sn_dd_to_dd - manually setting opacity to .97");

			// sn_m portion
			anim_obj[1] = {
				'height': [this.sn_m.getStyle('height').toInt(), sn_height_end], 
				'width': [this.sn_m.getStyle('width').toInt(), sn_m_end_width]
			};
			
			// hide other dds, but show this one
			var dd_width_start = 0;
			if (this.dd_showing){
				dd_width_start = $(this.dd_showing).getStyle('width').toInt();
			}
			anim_obj[2] = {
				'width': [dd_width_start, this.dd_hw[dd.id].width],
				'opacity': [0,1]
			};

			this.sn_snm_fx = new Fx.Elements($$(this.sn, this.sn_m, dd), {
				wait: false, 
				duration: this.options.duration, 
				transition: Fx.Transitions.Expo.easeOut,
				onComplete: function() {
					this.curr_sect = this.sect(mi.id);
				}.bind(this)
			});

			this.sn_snm_fx.start(anim_obj);
			this.show_dd(dd);
			this.hide_other_dds(dd.id);	

			
		} else {
		
			// sub nav is NOT showing

			// sn_m 
			this.sn_m.setStyles({
				width: sn_m_end_width,
				height: sn_height_end
			}); 
			
			// sub nav
			
			this.sn.setStyles({
				width: sn_end_width,
				height: sn_height_end,
				display:'block'
			}); 
	
			// left
			var mn_pos = this.mn.getPosition();
			var mi_left = this.mi_left_pos(mi, mn_pos.x) - 1;
			switch (mi.id) {
				case 'mi-admin':
					// right align the admin, fly in from left
					var sn_left_end = mi_left - sn_end_width + 102;
					var sn_left_start = sn_left_end - this.options.fly_offset;
					break;
				case 'mi-home':
					// right align the admin, fly in from left
					var sn_left_end = mn_pos.x + 6;
					var sn_left_start = sn_left_end + this.options.fly_offset;
					break;
				default:
					if (mi_left <= (mn_pos.x + (this.mn_w/2))) {
						// main menu item is on the left side of the menu
						// fly in from right
						var sn_left_end = mi_left;
						var sn_left_start = sn_left_end + this.options.fly_offset;
					} else {
						// main menu item is on the right side of the menu
						// fly in from left
						var sn_left_end = mi_left;
						var sn_left_start = sn_left_end - this.options.fly_offset;
					}
					break;
			}
					
			var sn_anim_obj = {left: [sn_left_start, sn_left_end], opacity: 0.97};
			
			// dd
			this.show_dd(dd);
			dd.setStyles({
				width: this.dd_hw[dd.id].width,
				opacity:1
			}); 
			

			this.adm('anim_sn_dd_to_dd - sub nav is not visible - so adding sub nav opacity to elements fx');

			this.sn_snm_fx = new Fx.Morph(this.sn, {
				duration: this.options.duration, 
				transition: Fx.Transitions.Expo.easeOut,
				onComplete: function() {
					this.curr_sect = this.sect(mi.id);
				}.bind(this)
			});

			this.sn_snm_fx.start(sn_anim_obj);

		}


		if (this.isIE6 && !this.bckgrnd_layer_made) {
			this.make_background_layer();
		}
		if (this.isIE6) {
			this.bckgrnd_iframe.setStyles({
				left: mn_pos.x,
				height:sn_height_end,
				visibility:'visible',
				display:'block'
			}); 
		}

		this.adm("sn_left_start: " + sn_left_start + "; sn_left_end: " + sn_left_end + ";<br>sn_height_start: " + sn_height_start + "; sn_height_end: " + sn_height_end + ";<br>sn_m_end_width: " + sn_m_end_width + ";<br>dd_width_start: " + dd_width_start + "; original_dd_width: " + this.dd_hw[dd.id].width);

		if (!this.sub_nav_visible) {
			this.sub_nav_visible = true;
		}

	},
	hide_sub_nav: function(mid) { 
		if (this.sub_nav_visible){
			this.adm("hide_sub_nav called from " + mid + " - and yes, sub nav is visible --- hiding in progress");
			this.hide_sub_nav_fx.start({'opacity': 0});
			
		} else {
			this.adm("hide_sub_nav called from " + mid + " - but sub nav is not showing ... do nothing");
		}
	},
	sn_mousegone: function() { 
		this.adm("sn_mousegone called");
		if (!this.mouseover_sub_nav && !this.mouseover_kwick)	{
			// calc start/end x for sub nav
			var sn_left_start = this.sn.getPosition().x;
			var pos = this.mn.getPosition();
			var sn_left_end = 0;
			if (this.mouseover_mi == 'mi-home') {
				sn_left_end = pos.x + 6;
			} else {
				var mi = $(this.mouseover_mi);
				var target_mi_found = false;
				sn_left_end = pos.x + this.mi_ascribe_w;
				this.kwicks.each(function(kw, j){
					if (kw != mi) {
						if (!target_mi_found) { sn_left_end += 73; }
					} else {
						target_mi_found = true;
					}
				});
			}
			this.hide_sub_nav_fx.start({'opacity': 0});
			this.kwick_reset();
			if (this.isIE6) {
				this.bckgrnd_iframe.setStyles({
					visibility:'hidden',
					display:'none'
				}); 
			}
		}	
	},
	hover_mi: function(mi) {
		if (Browser.Engine.gecko) {
			mi.setStyle('background-position', this.mi_bgx[mi.id] + ' -' + this.options.mi_height + 'px');	
		} else {
			mi.setStyle('background-position-y', '-' + this.options.mi_height + 'px');
		}
	},
	restore_mi: function(mi) {
		if (Browser.Engine.gecko) {
			mi.setStyle('background-position', this.mi_bgx[mi.id] + ' 0');	
		} else {
			mi.setStyle('background-position-y', 0);
		}
	},
	mi_mouseenter: function(mi) {
		if (!this.mi_mouseenter_active) {
		
			this.curr_sect = this.sect(mi.id);

			if (this.hide_sub_nav_fx) { this.hide_sub_nav_fx.cancel(); }

			this.mi_mouseenter_active = true;
			this.adm("<b style=\"color:yellow\">MI MOUSE ENTER: " + this.curr_sect + "</b>");

			// mouseover image swap
			// shift bg img up for this mi	
			this.hover_mi(mi);	
			this.adm("moving mi bg img up 36px: " + mi.id + "; previous active mi was: " + this.mouseover_mi);

			// shift bg img back down for prev mi
			if (mi.id != this.mouseover_mi) {
				if (this.mouseover_mi) {
					var prev_midi = $(this.mouseover_mi);
					if (prev_midi && prev_midi.hasClass('mi')) {
						this.restore_mi(prev_midi);
						this.adm("making previously active mi bg img back to normal: " + this.mouseover_mi);

					}
				}
			}

			// set current mi/dd to this mi; must come after image swap
			this.mouseover_mi = mi.id;

			var dd = this.get_dd(mi);

			if (dd)	{
				// has sub nav
				// hide any other sub nav, but show this one
				var do_amin = true;

				if (this.dd_showing) {
					this.adm('dd exists and ' + this.dd_showing + ' is currently displayed');
					if ($(this.dd_showing) == dd) {
						do_amin = false;
					}
				
				}
				if (do_amin) {
					this.anim_sn_dd_to_dd(dd, mi);
				}
					
			} else {
				// no sub nav: hide all dds and close sub nav
				this.adm('no sub nav: hide all dds and close sub nav');
				if (this.sub_nav_visible) {
					this.adm('calling hide_sub_nav from mi mouseover');
					this.hide_sub_nav(mi.id);
					// cannot use sn_mousegone() here because it won't activate when the mouse is still over the mi
				}
			}
			this.mi_mouseenter_active = false;
		}
	},
	mi_mouseleave: function(mi, bgx) { 
		// this is called 5ms after mouse left to give the next mouseover function time to record where the mouse went to
		if (!this.mouseover_sub_nav) {
			this.adm("<b style=\"color:red\">MOUSE LEFT " + mi.id + " MI 5ms ago</b> - mouse is NOT over sub nav");
			if (mi.id == "mi-home") {
				if (this.mouseover_mi == mi.id) {
					// left mi-home and left nav, timer close
					$clear(this.timer);
					this.timer = this.mi_mousegone.delay(500, this, [mi, bgx]);
				}
			} else {
				if (!this.mouseover_kwick) {
					$clear(this.timer);
					this.timer = this.mi_mousegone.delay(500, this, [mi, bgx]);
				}
			}	
		} else {
			this.adm("<b>MOUSE LEFT " + mi.id + " MI 5ms ago but doing nothing because mouse is over sub nav</b>");
		}
		this.curr_sect = '';
	},
	mi_mousegone: function(mi) {
		// this is called 500ms after mouse left to reset kwick and make sub nav fade out for disuse of nav
		if (!this.mouseover_sub_nav && !this.mouseover_kwick)	{
			this.hide_sub_nav(mi.id);
			this.kwick_reset();	
			this.restore_mi(mi);
		}	
	},
	kwick_reset: function() {
		var obj = {};
		this.kwicks.each(function(kw, j){
			obj[j] = {'width': [kw.getStyle('width').toInt(), 72]};
		}.bind(this));
		this.kwicks_fx_group.start(obj);
	},
	sect: function(id) { // parses section from mi or dd id
		if (id) {
			var p = id.split('-');
			if (p) {
				return p[1];
			}	
		}
		return false;
	},
	adm: function(msg) { // add debug message
		if (this.options.debug) {
			this.dln++;
			var p = new Element('p').set('html', "<b>" + this.dln + ".</b> " + msg).inject(this.debug_window, 'top');
		}
	}

});
function init_intranav() {
	AscIntraNav = new AscIntranetNav({
		mi_height: 36
	});		
}
window.addEvent('domready', init_intranav);

/*
 *  2/18/2009
 *	record function buttons - minimize and maximize
*/	
var AscRecBtnsMinMax = new Class({
	Implements: [Options,Events], 
    Extends: AscTip,
	options: {
		strs: {
			'min': 'Click here to use <b>small</b> icons',
			'max': 'Click here to use <b>large</b> icons'
		},
		place: {
			'ss': { 'io':1, offset:16 }, // show start
			'se': { 'io':1, offset:11 }, // show end
			'he': { trans:'fade' } // hide end
		},
		asc_remote_auth:'',
		default_align:'sw',
		mod: 'person',
		script_bn: 'person.php',
		rb_max: 1
	},
	initialize: function(options){
		this.parent();
		this.setOptions(options);
		var s;
		for (s in this.options.strs) {
			if (typeof(this.options.strs[s])=='string') {
				this.options.strs[s] = translate_magic_quotes(this.options.strs[s]);
			}
		}
		this.mmrb_tog = $('mmrb_tog');
		this.mini_btns = $('mini_btns');
		this.subh = $('subh');
		if (this.mmrb_tog && this.mini_btns && this.subh) {
			this.enable_tip(this.mmrb_tog);
			this.vslide = new Fx.Slide('subh', {
			    duration: 500,
			    transition: Fx.Transitions.Pow.easeOut
			});
			this.vslide.wrapper.setStyle('position','relative');
			if (this.options.rb_max) {
				this.mmrb_tog.set('class','min');
				this.subh.setStyle('display','block');
				this.vslide.show();
				this.mini_btns.setStyle('display','none');
			} else {
				this.mmrb_tog.set('class','max');
				this.vslide.hide();
				this.mini_btns.setStyle('display','block');
			}

			this.subh.addEvents({
				'mouseenter': function(e) {
					this.mousein = true;
					this.current_el = this.mmrb_tog;
					this.do_show(this.mmrb_tog, this.options.strs.min, '', 'auto', 'ne');
					// hide after 3 seconds
					this.timer = this.hide.delay(3000, this);
				}.bind(this),	 
				'mouseleave': function(e) {
					this.hide();
				}.bind(this)
			});
		}
	},
	enable_tip: function(el) {
		if (el) {
			el.setStyle('visibility', 'visible');
			el.addEvents({
				'click': function(e) {
					e = new Event(e).stop();
					if (this.vslide.timer) {
						this.vslide.cancel();
					}
					if (this.options.rb_max) {
						this.options.rb_max = 0;
					} else {
						this.options.rb_max = 1;
					}
					this.set_contents(this.mmh_tip_msg(), '', 'auto');
					this.mm_toggle();
					var r = new Request({url: this.options.script_bn, method: 'get', data:{'action':'mmmm','mod':this.options.mod, 'rb_max':this.options.rb_max, 'asc_remote_auth': this.options.asc_remote_auth } }).send();
				}.bind(this),
				'mouseenter': function(e) {
					this.event = e;
					asc_tooltips.hide();
					this.current_el = el;
					this.mousein = true;
					$clear(this.timer);
					this.timer = this.do_show.delay(this.options.showDelay, this, [el, this.mmh_tip_msg(), '', 'auto', 'ne']);
				}.bind(this),	 
				'mouseleave': function(e) {
					this.mousein = false;
					$clear(this.timer);
					if (this.current_el == el) {
						this.current_el = '';
					}
					if (this.fx_in_process && (this.fx_dir == 1)) {
						this.isShowing = true;
						this.hide();
					} else {						
						this.timer = this.hide.delay(this.options.hideDelay, this);
					}
				}.bind(this)
			});
		}
		return false;
	},
	mm_toggle: function(){
		
		if (this.options.rb_max) {
			this.mmrb_tog.set('class','min');
			this.subh_show();
			this.mini_btns.setStyle('display','none');
		} else {
			this.mmrb_tog.set('class','max');
			this.subh_hide();
			this.mini_btns.setStyle('display','block');
		}
		this.mmrb_tog.blur();
	},
	mmh_tip_msg: function(){
		if (this.options.rb_max) {
			return this.options.strs.min;
		} else {
			return this.options.strs.max;
		}
	},
	subh_hide: function(){
		this.vslide.slideOut();
	},
	subh_show: function(){
		this.subh.setStyle('display','block');
		this.vslide.slideIn();
	}

});
var padfilename = function(file_name, pad) {
	if (file_name) {
		if (pad && file_name) {
			var tv = file_name.split('.');
			var ext = tv.pop();
			tv.push(pad);
			tv.push(ext);
			return tv.join('.');
		} else {
			return file_name;
		}
	}
	return false;
}

// gen image path
var gen_image_src = function(file_name, pan, sz, s3prefix, ssl) {
	if (s3prefix) {
		var dmn;
		if (ssl) {
			dmn = 'https://d1s7gsgjf7qqdk.cloudfront.net/';
		} else {
			dmn = 'http://edge.ascribedata.com/';
		}
		return dmn + s3prefix + padfilename(file_name, sz);
	} else {
		return asc_subject_private_url + "albums/" + pan + "/" + padfilename(file_name, sz);
	}
}


var AscBase = new Class({
	Implements: [Options,Events], 
	options: {
		strs: {},
		debug: false
	},
	initialize: function(options){
		this.setOptions(options);
		this.options.strs = this.unquote_str_obj(this.options.strs);
	},
	unquote_str_obj: function(obj) { 
		var s;
		for (s in obj) {
			switch ($type(this.options.strs[s])) {
				case 'string':
					this.options.strs[s] = translate_magic_quotes(this.options.strs[s]);
					break;
				case 'object':
					this.options.strs[s] = this.unquote_str_obj(this.options.strs[s]);
					break;
			}
		}
		return obj;
	},
	save_cancel_tbl: function(extra_td, save_str, save_cls){
		if (!$type(save_str) || (save_str=='')) { save_str = this.options.strs.save; }
		if (!$type(save_cls) || (save_cls=='')) { save_cls = 'i16 save16'; }
		var tbl = new Element('table', {'class':'btn-tbl'});
		var tbody = new Element('tbody').inject(tbl);
		var tr = new Element('tr').inject(tbody);
		var td2 = new Element('td', {'class':'save-btn-td'} ).inject(tr);
		var ok = this.gen_btn('form confirm_btn', save_str, '', '#', save_cls).inject(td2);
		var td3 = new Element('td', {'class':'tiny'} ).set('html',this.options.strs.or).inject(tr).setStyle('padding', 5);
		var td4 = new Element('td', {'class':'cancel'} ).inject(tr);
		if ($type(extra_td)=='element') extra_td.inject(tr);
		var cancel_a = new Element('a', {'href':'#', 'class': 'cancel'}).set('html',this.options.strs.cancel).inject(td4);
		return tbl;
	},
	gen_btn: function(btn_class, str,id, href, div_cls){
		if (!href) {
			href = '#';
		}
		var obj = { 'class':btn_class, 'href':href };
		if ($type(id)=='string') {
			obj.id = id;
		}
		var anchor = new Element('a', obj);
		var s1 = new Element('span').inject(anchor);
		var s2 = new Element('span').inject(s1);
		var s3 = new Element('span').inject(s2);
		var d4 = new Element('div', {'html':str}).inject(s3);
		if (div_cls) {
			d4.addClass(div_cls);
		}
		return anchor;
	},
	debug_msg: function(str) {
//		if (($type(this.options.debug)=='boolean') && (this.options.debug===true)) {
//			if ($defined(window.console)) {
//				console.log(str);
//			}
//		}
	}
});
var AscBaseTipModal = new Class({
	Implements: [Options,Events], 
	Extends: AscBase,
	options: {
		osme: false,
		os_show_fn: $empty,
		os_hide_fn: $empty,
		os_modal_cls: 'ok'
	},
	initialize: function(options){
        this.parent(options); 
		this.modal = new AscModal('', '', {
			addCloseBtn: false, 
			speed: 300,
			popOpacity: 1,
			place: {
				'ss': { target:'window', io:1, align:'n', offset:0, margin:0 }, // show start
				'se': { trans:'fly', target:'window', io:-1, align:'n', offset:70, margin:0 }, // show end
				'he': { trans:'fade', target:'window', io:1, align:'n', offset:0, margin:0 } // hide end
			}
		});
		this.tip = new AscDialog({
			isModal: false,
			speed: 200,
			useArrows: true,
			addCloseBtn: false,
			popOpacity: .9,
			classPrefix: 'Tip',		
			place: {
				'ss': { 'io':1, align:'sw', offset:9 }, // show start
				'se': { 'io':1, align:'sw', offset:4 }, // show end
				'he': { trans:'fade' } // hide end
			},
			onShow: $empty,
			onHide: $empty
		});
		
		if (this.options.strs.on_start_msg) {
			this.show_modal(this.options.strs.on_start_msg, this.options.osme, this.options.os_show_fn, this.options.os_hide_fn, this.options.os_modal_cls);
		}
		
	},
	prep_tip: function(el, align, msg, cls, width) { 
		this.tip.set_contents(msg, cls, width);
		this.tip.options.place.ss.target = el;
		this.tip.options.place.se.target = el;
		this.tip.options.place.ss.align = align;
		this.tip.options.place.se.align = align;
	},
	modal_contents: function(msg_cls, msg){
		var c = new Element('div',{'class':'eregmodal'});
		var p = new Element('p',{'class': msg_cls + ' med'}).inject(c);
		switch($type(msg)) {
			case 'element':
				p.adopt(msg);
				break;
			case 'string':
				p.set('html', msg);
				break;
		}
		return c;
	},
	show_confirm_modal: function(modal_cls, msg_cls, msg, confirm_btn_str, confirm_btn_cls, confirm_fn){
		var c = this.modal_contents(msg_cls, msg);
		this.save_cancel_tbl('', confirm_btn_str, confirm_btn_cls).inject(c);		
		
		this.modal.set_contents(c, modal_cls, 370);

		this.modal.removeEvents('show');
		this.modal.addEvent('show', function(e) {
			
			var confirm_btn = this.modal.pop.getElement('a[class*=confirm_btn]');
			if (confirm_btn) {
				confirm_btn.addEvent('click', function(e) {
					e = new Event(e).stop();
					if (confirm_fn) confirm_fn.attempt('',this);
				}.bind(this));
			}

			var cancel_btn = this.modal.pop.getElement('a[class=cancel]');
			if (cancel_btn) {
				cancel_btn.addEvent('click', function(e) {
					e = new Event(e).stop();
					this.modal.hide();
				}.bind(this));
			}

		}.bind(this));
		this.modal.show();		
	},
	show_modal: function(msg, err, show_fn, hide_fn, modal_cls, modal_width){
		if (!modal_cls) modal_cls = 'ok';
		if (!modal_width) modal_width = 370;
		var msg_cls = 'msg_pass';
		if (err) {
			modal_cls = 'f';
			msg_cls = 'msg_fail';
		}
		var c = this.modal_contents(msg_cls, msg);		
		var ok = this.gen_btn('form', this.options.strs.ok, 'ok_btn').inject(c);
		this.modal.set_contents(c, modal_cls, modal_width);

		$('ok_btn').addEvent('click', function(e) {
			e = new Event(e).stop();
			this.modal.hide();
		}.bind(this));
		
		if (show_fn) {
			this.modal.removeEvents('show');
			this.modal.addEvent('show', function(e) {		
				show_fn.attempt('', this);
			}.bind(this));
		}
		if (hide_fn) {
			this.modal.removeEvents('hide');
			this.modal.addEvent('hide', function(e) {		
				hide_fn.attempt('', this);
			}.bind(this));
		}
		this.modal.show();
	}
});
var AscForm = new Class({
	Implements: [Options,Events], 
	Extends: AscBaseTipModal,
	options: {
		onUnload: $empty
	},
	initialize: function(options){
        this.parent(options); 
        
		// if there are unsaved changes, confirm with user before leaving form		
		this.unsaved_changes_exist = false;
		window.onbeforeunload = function(){
			if (this.unsaved_changes_exist) {
				return this.options.strs.unsaved_changes_leave_confirm;
			}
			this.fireEvent('unload');
		}.bind(this);
        
		this.scroll = new Fx.Scroll(window, {
			wait: false,
			duration: 400,
			offset: {'x': -50, 'y': -50},
			transition: Fx.Transitions.Quad.easeInOut
		});
		
	},
	scroll_to_el_if_not_visible: function(fld){
		var doc_scr = document.window.getScroll();
		var win_sz = document.window.getSize();

		var fld_coord = fld.getCoordinates();
		var win_top = doc_scr.y;
		var win_bottom = doc_scr.y + win_sz.y - 58;
		if (win_top > fld_coord.top) {
			// fld is above the top of window
			this.scroll.start(doc_scr.x, (fld_coord.top + 15));
		} else if (win_bottom < fld_coord.bottom) {
			// fld is below bottom of window
			this.scroll.start(doc_scr.x, (win_top + (fld_coord.bottom - win_bottom) + 58));
		}
	},
	save_btn_saving: function(btn, saving, str){
		if (saving) {
			btn.removeClass('form').addClass('form-down').addClass('saving');
		} else {
			btn.removeClass('form-down').addClass('form').removeClass('saving');
		}
		btn.getElement('div').set('html', str);
	}
});