

var startList = function() {
if (document.all&&document.getElementById) {
navRoot = document.getElementById("nav");
if (navRoot) {
    for (i=0; i<navRoot.childNodes.length; i++) {
    node = navRoot.childNodes[i];
    if (node.nodeName=="LI") {     
    node.onmouseover=function() {
    this.className+=" over";
      }
      node.onmouseout=function() {
      this.className=this.className.replace(" over", "");
       }
       }
      }
    }      
 }
}
window.onload=startList;

/*  Copyright Mihai Bazon, 2002-2005  |  www.bazon.net/mishoo
 * -----------------------------------------------------------
 *
 * The DHTML Calendar, version 1.0 "It is happening again"
 *
 * Details and latest version at:
 * www.dynarch.com/projects/calendar
 *
 * This script is developed by Dynarch.com.  Visit us at www.dynarch.com.
 *
 * This script is distributed under the GNU Lesser General Public License.
 * Read the entire license text here: http://www.gnu.org/licenses/lgpl.html
 */

// $Id: calendar.js,v 1.51 2005/03/07 16:44:31 mishoo Exp $

/** The Calendar object constructor. */
var Calendar = function (firstDayOfWeek, dateStr, onSelected, onClose) {
	// member variables
	this.activeDiv = null;
	this.currentDateEl = null;
	this.getDateStatus = null;
	this.getDateToolTip = null;
	this.getDateText = null;
	this.timeout = null;
	this.onSelected = onSelected || null;
	this.onClose = onClose || null;
	this.dragging = false;
	this.hidden = false;
	this.minYear = 1970;
	this.maxYear = 2050;
	this.dateFormat = Calendar._TT["DEF_DATE_FORMAT"];
	this.ttDateFormat = Calendar._TT["TT_DATE_FORMAT"];
	this.isPopup = true;
	this.weekNumbers = true;
	this.firstDayOfWeek = typeof firstDayOfWeek == "number" ? firstDayOfWeek : Calendar._FD; // 0 for Sunday, 1 for Monday, etc.
	this.showsOtherMonths = false;
	this.dateStr = dateStr;
	this.ar_days = null;
	this.showsTime = false;
	this.time24 = true;
	this.yearStep = 2;
	this.hiliteToday = true;
	this.multiple = null;
	// HTML elements
	this.table = null;
	this.element = null;
	this.tbody = null;
	this.firstdayname = null;
	// Combo boxes
	this.monthsCombo = null;
	this.yearsCombo = null;
	this.hilitedMonth = null;
	this.activeMonth = null;
	this.hilitedYear = null;
	this.activeYear = null;
	// Information
	this.dateClicked = false;
	// one-time initializations
	if (typeof Calendar._SDN == "undefined") {
		// table of short day names
		if (typeof Calendar._SDN_len == "undefined")
			Calendar._SDN_len = 3;
		var ar = new Array();
		for (var i = 8; i > 0;) {
			ar[--i] = Calendar._DN[i].substr(0, Calendar._SDN_len);
		}
		Calendar._SDN = ar;
		// table of short month names
		if (typeof Calendar._SMN_len == "undefined")
			Calendar._SMN_len = 3;
		ar = new Array();
		for (var i = 12; i > 0;) {
			ar[--i] = Calendar._MN[i].substr(0, Calendar._SMN_len);
		}
		Calendar._SMN = ar;
	}
};

// ** constants

/// "static", needed for event handlers.
Calendar._C = null;

// This is a patch from sourceforge, author hodgestar

/// detect a special case of "web browser"
Calendar.is_ie = ( /msie/i.test(navigator.userAgent) &&
!/opera/i.test(navigator.userAgent) ); 
 
Calendar.is_ie5 = ( Calendar.is_ie && /msie 5\.0/i.test(navigator.userAgent) ); 
Calendar.is_ie6 = ( Calendar.is_ie && /msie 6\.0/i.test(navigator.userAgent) ); 
 
/// detect Opera browser 
Calendar.is_opera = /opera/i.test(navigator.userAgent); 

// /// detect a special case of "web browser"
// Calendar.is_ie = ( /msie/i.test(navigator.userAgent) &&
//         !/opera/i.test(navigator.userAgent) );
// 
// Calendar.is_ie5 = ( Calendar.is_ie && /msie 5\.0/i.test(navigator.userAgent) );
// 
// /// detect Opera browser
// Calendar.is_opera = /opera/i.test(navigator.userAgent);

/// detect KHTML-based browsers
Calendar.is_khtml = /Konqueror|Safari|KHTML/i.test(navigator.userAgent);

// BEGIN: UTILITY FUNCTIONS; beware that these might be moved into a separate
//        library, at some point.

Calendar.getAbsolutePos = function(el) {
	var SL = 0, ST = 0;
	var is_div = /^div$/i.test(el.tagName);
	var is_input = /^input$/i.test(el.tagName);
    var tmp_el ;
    
	if (is_input && el.type == 'hidden') {
	    tmp_el = el.parentNode ;
	} else {
	    tmp_el = el ;
	}
	

	if (is_div && tmp_el.scrollLeft)
		SL = tmp_el.scrollLeft;
	if (is_div && el.scrollTop)
		ST = tmp_el.scrollTop;
	var r = { x: tmp_el.offsetLeft - SL, y: tmp_el.offsetTop - ST };
	
	if (tmp_el.offsetParent) {
		var tmp = this.getAbsolutePos(tmp_el.offsetParent);
		r.x += tmp.x;
		r.y += tmp.y;
	}
	return r;
};

Calendar.isRelated = function (el, evt) {
	var related = evt.relatedTarget;
	if (!related) {
		var type = evt.type;
		if (type == "mouseover") {
			related = evt.fromElement;
		} else if (type == "mouseout") {
			related = evt.toElement;
		}
	}
	while (related) {
		if (related == el) {
			return true;
		}
		// -------------------------------------------------------------------
		// NW. Patch to avoid a "permission denied to get property of HTMLDiv.parentNode"
		// error when 'related' is an anonymouse div.
		// -------------------------------------------------------------------
		try {
		    related = related.parentNode;
		} catch (err) {
		    related = null ;
		}
	}
	return false;
};

Calendar.removeClass = function(el, className) {
	if (!(el && el.className)) {
		return;
	}
	var cls = el.className.split(" ");
	var ar = new Array();
	for (var i = cls.length; i > 0;) {
		if (cls[--i] != className) {
			ar[ar.length] = cls[i];
		}
	}
	el.className = ar.join(" ");
};

Calendar.addClass = function(el, className) {
	Calendar.removeClass(el, className);
	el.className += " " + className;
};

// FIXME: the following 2 functions totally suck, are useless and should be replaced immediately.
Calendar.getElement = function(ev) {
	var f = Calendar.is_ie ? window.event.srcElement : ev.currentTarget;
	while (f.nodeType != 1 || /^div$/i.test(f.tagName))
		f = f.parentNode;
	return f;
};

Calendar.getTargetElement = function(ev) {
	var f = Calendar.is_ie ? window.event.srcElement : ev.target;
	while (f.nodeType != 1)
		f = f.parentNode;
	return f;
};

Calendar.stopEvent = function(ev) {
	ev || (ev = window.event);
	if (Calendar.is_ie) {
		ev.cancelBubble = true;
		ev.returnValue = false;
	} else {
		ev.preventDefault();
		ev.stopPropagation();
	}
	return false;
};

Calendar.addEvent = function(el, evname, func) {
	if (el.attachEvent) { // IE
		el.attachEvent("on" + evname, func);
	} else if (el.addEventListener) { // Gecko / W3C
		el.addEventListener(evname, func, true);
	} else {
		el["on" + evname] = func;
	}
};

Calendar.removeEvent = function(el, evname, func) {
	if (el.detachEvent) { // IE
		el.detachEvent("on" + evname, func);
	} else if (el.removeEventListener) { // Gecko / W3C
		el.removeEventListener(evname, func, true);
	} else {
		el["on" + evname] = null;
	}
};

Calendar.createElement = function(type, parent) {
	var el = null;
	if (document.createElementNS) {
		// use the XHTML namespace; IE won't normally get here unless
		// _they_ "fix" the DOM2 implementation.
		el = document.createElementNS("http://www.w3.org/1999/xhtml", type);
	} else {
		el = document.createElement(type);
	}
	if (typeof parent != "undefined") {
		parent.appendChild(el);
	}
	return el;
};

// END: UTILITY FUNCTIONS

// BEGIN: CALENDAR STATIC FUNCTIONS

/** Internal -- adds a set of events to make some element behave like a button. */
Calendar._add_evs = function(el) {
	with (Calendar) {
		addEvent(el, "mouseover", dayMouseOver);
		addEvent(el, "mousedown", dayMouseDown);
		addEvent(el, "mouseout", dayMouseOut);
		if (is_ie) {
			addEvent(el, "dblclick", dayMouseDblClick);
			el.setAttribute("unselectable", true);
		}
	}
};

Calendar.findMonth = function(el) {
	if (typeof el.month != "undefined") {
		return el;
	} else if (typeof el.parentNode.month != "undefined") {
		return el.parentNode;
	}
	return null;
};

Calendar.findYear = function(el) {
	if (typeof el.year != "undefined") {
		return el;
	} else if (typeof el.parentNode.year != "undefined") {
		return el.parentNode;
	}
	return null;
};

Calendar.showMonthsCombo = function () {
	var cal = Calendar._C;
	if (!cal) {
		return false;
	}
	var cal = cal;
	var cd = cal.activeDiv;
	var mc = cal.monthsCombo;
	if (cal.hilitedMonth) {
		Calendar.removeClass(cal.hilitedMonth, "hilite");
	}
	if (cal.activeMonth) {
		Calendar.removeClass(cal.activeMonth, "active");
	}
	var mon = cal.monthsCombo.getElementsByTagName("div")[cal.date.getMonth()];
	Calendar.addClass(mon, "active");
	cal.activeMonth = mon;
	var s = mc.style;
	s.display = "block";
	if (cd.navtype < 0)
		s.left = cd.offsetLeft + "px";
	else {
		var mcw = mc.offsetWidth;
		if (typeof mcw == "undefined")
			// Konqueror brain-dead techniques
			mcw = 50;
		s.left = (cd.offsetLeft + cd.offsetWidth - mcw) + "px";
	}
	s.top = (cd.offsetTop + cd.offsetHeight) + "px";
};

Calendar.showYearsCombo = function (fwd) {
	var cal = Calendar._C;
	if (!cal) {
		return false;
	}
	var cal = cal;
	var cd = cal.activeDiv;
	var yc = cal.yearsCombo;
	if (cal.hilitedYear) {
		Calendar.removeClass(cal.hilitedYear, "hilite");
	}
	if (cal.activeYear) {
		Calendar.removeClass(cal.activeYear, "active");
	}
	cal.activeYear = null;
	var Y = cal.date.getFullYear() + (fwd ? 1 : -1);
	var yr = yc.firstChild;
	var show = false;
	for (var i = 12; i > 0; --i) {
		if (Y >= cal.minYear && Y <= cal.maxYear) {
			yr.innerHTML = Y;
			yr.year = Y;
			yr.style.display = "block";
			show = true;
		} else {
			yr.style.display = "none";
		}
		yr = yr.nextSibling;
		Y += fwd ? cal.yearStep : -cal.yearStep;
	}
	if (show) {
		var s = yc.style;
		s.display = "block";
		if (cd.navtype < 0)
			s.left = cd.offsetLeft + "px";
		else {
			var ycw = yc.offsetWidth;
			if (typeof ycw == "undefined")
				// Konqueror brain-dead techniques
				ycw = 50;
			s.left = (cd.offsetLeft + cd.offsetWidth - ycw) + "px";
		}
		s.top = (cd.offsetTop + cd.offsetHeight) + "px";
	}
};

// event handlers

Calendar.tableMouseUp = function(ev) {
	var cal = Calendar._C;
	if (!cal) {
		return false;
	}
	if (cal.timeout) {
		clearTimeout(cal.timeout);
	}
	var el = cal.activeDiv;
	if (!el) {
		return false;
	}
	var target = Calendar.getTargetElement(ev);
	ev || (ev = window.event);
	Calendar.removeClass(el, "active");
	if (target == el || target.parentNode == el) {
		Calendar.cellClick(el, ev);
	}
	var mon = Calendar.findMonth(target);
	var date = null;
	if (mon) {
		date = new Date(cal.date);
		if (mon.month != date.getMonth()) {
			date.setMonth(mon.month);
			cal.setDate(date);
			cal.dateClicked = false;
			cal.callHandler();
		}
	} else {
		var year = Calendar.findYear(target);
		if (year) {
			date = new Date(cal.date);
			if (year.year != date.getFullYear()) {
				date.setFullYear(year.year);
				cal.setDate(date);
				cal.dateClicked = false;
				cal.callHandler();
			}
		}
	}
	with (Calendar) {
		removeEvent(document, "mouseup", tableMouseUp);
		removeEvent(document, "mouseover", tableMouseOver);
		removeEvent(document, "mousemove", tableMouseOver);
		cal._hideCombos();
		_C = null;
		return stopEvent(ev);
	}
};

Calendar.tableMouseOver = function (ev) {
	var cal = Calendar._C;
	if (!cal) {
		return;
	}
	var el = cal.activeDiv;
	var target = Calendar.getTargetElement(ev);
	if (target == el || target.parentNode == el) {
		Calendar.addClass(el, "hilite active");
		Calendar.addClass(el.parentNode, "rowhilite");
	} else {
		if (typeof el.navtype == "undefined" || (el.navtype != 50 && (el.navtype == 0 || Math.abs(el.navtype) > 2)))
			Calendar.removeClass(el, "active");
		Calendar.removeClass(el, "hilite");
		Calendar.removeClass(el.parentNode, "rowhilite");
	}
	ev || (ev = window.event);
	if (el.navtype == 50 && target != el) {
		var pos = Calendar.getAbsolutePos(el);
		var w = el.offsetWidth;
		var x = ev.clientX;
		var dx;
		var decrease = true;
		if (x > pos.x + w) {
			dx = x - pos.x - w;
			decrease = false;
		} else
			dx = pos.x - x;

		if (dx < 0) dx = 0;
		var range = el._range;
		var current = el._current;
		var count = Math.floor(dx / 10) % range.length;
		for (var i = range.length; --i >= 0;)
			if (range[i] == current)
				break;
		while (count-- > 0)
			if (decrease) {
				if (--i < 0)
					i = range.length - 1;
			} else if ( ++i >= range.length )
				i = 0;
		var newval = range[i];
		el.innerHTML = newval;

		cal.onUpdateTime();
	}
	var mon = Calendar.findMonth(target);
	if (mon) {
		if (mon.month != cal.date.getMonth()) {
			if (cal.hilitedMonth) {
				Calendar.removeClass(cal.hilitedMonth, "hilite");
			}
			Calendar.addClass(mon, "hilite");
			cal.hilitedMonth = mon;
		} else if (cal.hilitedMonth) {
			Calendar.removeClass(cal.hilitedMonth, "hilite");
		}
	} else {
		if (cal.hilitedMonth) {
			Calendar.removeClass(cal.hilitedMonth, "hilite");
		}
		var year = Calendar.findYear(target);
		if (year) {
			if (year.year != cal.date.getFullYear()) {
				if (cal.hilitedYear) {
					Calendar.removeClass(cal.hilitedYear, "hilite");
				}
				Calendar.addClass(year, "hilite");
				cal.hilitedYear = year;
			} else if (cal.hilitedYear) {
				Calendar.removeClass(cal.hilitedYear, "hilite");
			}
		} else if (cal.hilitedYear) {
			Calendar.removeClass(cal.hilitedYear, "hilite");
		}
	}
	return Calendar.stopEvent(ev);
};

Calendar.tableMouseDown = function (ev) {
	if (Calendar.getTargetElement(ev) == Calendar.getElement(ev)) {
		return Calendar.stopEvent(ev);
	}
};

Calendar.calDragIt = function (ev) {
	var cal = Calendar._C;
	if (!(cal && cal.dragging)) {
		return false;
	}
	var posX;
	var posY;
	if (Calendar.is_ie) {
		posY = window.event.clientY + document.body.scrollTop;
		posX = window.event.clientX + document.body.scrollLeft;
	} else {
		posX = ev.pageX;
		posY = ev.pageY;
	}
	cal.hideShowCovered();
	var st = cal.element.style;
	st.left = (posX - cal.xOffs) + "px";
	st.top = (posY - cal.yOffs) + "px";
	return Calendar.stopEvent(ev);
};

Calendar.calDragEnd = function (ev) {
	var cal = Calendar._C;
	if (!cal) {
		return false;
	}
	cal.dragging = false;
	with (Calendar) {
		removeEvent(document, "mousemove", calDragIt);
		removeEvent(document, "mouseup", calDragEnd);
		tableMouseUp(ev);
	}
	cal.hideShowCovered();
};

Calendar.dayMouseDown = function(ev) {
	var el = Calendar.getElement(ev);
	if (el.disabled) {
		return false;
	}
	var cal = el.calendar;
	cal.activeDiv = el;
	Calendar._C = cal;
	if (el.navtype != 300) with (Calendar) {
		if (el.navtype == 50) {
			el._current = el.innerHTML;
			addEvent(document, "mousemove", tableMouseOver);
		} else
			addEvent(document, Calendar.is_ie5 ? "mousemove" : "mouseover", tableMouseOver);
		addClass(el, "hilite active");
		addEvent(document, "mouseup", tableMouseUp);
	} else if (cal.isPopup) {
		cal._dragStart(ev);
	}
	if (el.navtype == -1 || el.navtype == 1) {
		if (cal.timeout) clearTimeout(cal.timeout);
		cal.timeout = setTimeout("Calendar.showMonthsCombo()", 250);
	} else if (el.navtype == -2 || el.navtype == 2) {
		if (cal.timeout) clearTimeout(cal.timeout);
		cal.timeout = setTimeout((el.navtype > 0) ? "Calendar.showYearsCombo(true)" : "Calendar.showYearsCombo(false)", 250);
	} else {
		cal.timeout = null;
	}
	return Calendar.stopEvent(ev);
};

Calendar.dayMouseDblClick = function(ev) {
	Calendar.cellClick(Calendar.getElement(ev), ev || window.event);
	if (Calendar.is_ie) {
		document.selection.empty();
	}
};

Calendar.dayMouseOver = function(ev) {
	var el = Calendar.getElement(ev);
	if (Calendar.isRelated(el, ev) || Calendar._C || el.disabled) {
		return false;
	}
	if (el.ttip) {
		if (el.ttip.substr(0, 1) == "_") {
			el.ttip = el.caldate.print(el.calendar.ttDateFormat) + el.ttip.substr(1);
		}
		el.calendar.tooltips.innerHTML = el.ttip;
	}
	if (el.navtype != 300) {
		Calendar.addClass(el, "hilite");
		if (el.caldate) {
			Calendar.addClass(el.parentNode, "rowhilite");
		}
	}
	return Calendar.stopEvent(ev);
};

Calendar.dayMouseOut = function(ev) {
	with (Calendar) {
		var el = getElement(ev);
		if (isRelated(el, ev) || _C || el.disabled)
			return false;
		removeClass(el, "hilite");
		if (el.caldate)
			removeClass(el.parentNode, "rowhilite");
		if (el.calendar)
			el.calendar.tooltips.innerHTML = _TT["SEL_DATE"];
		return stopEvent(ev);
	}
};

/**
 *  A generic "click" handler :) handles all types of buttons defined in this
 *  calendar.
 */
Calendar.cellClick = function(el, ev) {
	var cal = el.calendar;
	var closing = false;
	var newdate = false;
	var date = null;
	if (typeof el.navtype == "undefined") {
		if (cal.currentDateEl) {
			Calendar.removeClass(cal.currentDateEl, "selected");
			Calendar.addClass(el, "selected");
			closing = (cal.currentDateEl == el);
			if (!closing) {
				cal.currentDateEl = el;
			}
		}
		cal.date.setDateOnly(el.caldate);
		date = cal.date;
		var other_month = !(cal.dateClicked = !el.otherMonth);
		if (!other_month && !cal.currentDateEl)
			cal._toggleMultipleDate(new Date(date));
		else
			newdate = !el.disabled;
		// a date was clicked
		if (other_month)
			cal._init(cal.firstDayOfWeek, date);
	} else {
		if (el.navtype == 200) {
			Calendar.removeClass(el, "hilite");
			cal.callCloseHandler();
			return;
		}
		date = new Date(cal.date);
		if (el.navtype == 0)
			date.setDateOnly(new Date()); // TODAY
		// unless "today" was clicked, we assume no date was clicked so
		// the selected handler will know not to close the calenar when
		// in single-click mode.
		// cal.dateClicked = (el.navtype == 0);
		cal.dateClicked = false;
		var year = date.getFullYear();
		var mon = date.getMonth();
		function setMonth(m) {
			var day = date.getDate();
			var max = date.getMonthDays(m);
			if (day > max) {
				date.setDate(max);
			}
			date.setMonth(m);
		};
		switch (el.navtype) {
		    case 400:
			Calendar.removeClass(el, "hilite");
			var text = Calendar._TT["ABOUT"];
			if (typeof text != "undefined") {
				text += cal.showsTime ? Calendar._TT["ABOUT_TIME"] : "";
			} else {
				// FIXME: this should be removed as soon as lang files get updated!
				text = "Help and about box text is not translated into this language.\n" +
					"If you know this language and you feel generous please update\n" +
					"the corresponding file in \"lang\" subdir to match calendar-en.js\n" +
					"and send it back to <mihai_bazon@yahoo.com> to get it into the distribution  ;-)\n\n" +
					"Thank you!\n" +
					"http://dynarch.com/mishoo/calendar.epl\n";
			}
			alert(text);
			return;
		    case -2:
			if (year > cal.minYear) {
				date.setFullYear(year - 1);
			}
			break;
		    case -1:
			if (mon > 0) {
				setMonth(mon - 1);
			} else if (year-- > cal.minYear) {
				date.setFullYear(year);
				setMonth(11);
			}
			break;
		    case 1:
			if (mon < 11) {
				setMonth(mon + 1);
			} else if (year < cal.maxYear) {
				date.setFullYear(year + 1);
				setMonth(0);
			}
			break;
		    case 2:
			if (year < cal.maxYear) {
				date.setFullYear(year + 1);
			}
			break;
		    case 100:
			cal.setFirstDayOfWeek(el.fdow);
			return;
		    case 50:
			var range = el._range;
			var current = el.innerHTML;
			for (var i = range.length; --i >= 0;)
				if (range[i] == current)
					break;
			if (ev && ev.shiftKey) {
				if (--i < 0)
					i = range.length - 1;
			} else if ( ++i >= range.length )
				i = 0;
			var newval = range[i];
			el.innerHTML = newval;
			cal.onUpdateTime();
			return;
		    case 0:
			// TODAY will bring us here
			if ((typeof cal.getDateStatus == "function") &&
			    cal.getDateStatus(date, date.getFullYear(), date.getMonth(), date.getDate())) {
				return false;
			}
			break;
		}
		if (!date.equalsTo(cal.date)) {
			cal.setDate(date);
			newdate = true;
		} else if (el.navtype == 0)
			newdate = closing = true;
	}
	if (newdate) {
		ev && cal.callHandler();
	}
	if (closing) {
		Calendar.removeClass(el, "hilite");
		ev && cal.callCloseHandler();
	}
};

// END: CALENDAR STATIC FUNCTIONS

// BEGIN: CALENDAR OBJECT FUNCTIONS

/**
 *  This function creates the calendar inside the given parent.  If _par is
 *  null than it creates a popup calendar inside the BODY element.  If _par is
 *  an element, be it BODY, then it creates a non-popup calendar (still
 *  hidden).  Some properties need to be set before calling this function.
 */
Calendar.prototype.create = function (_par) {
	var parent = null;
	if (! _par) {
		// default parent is the document body, in which case we create
		// a popup calendar.
		parent = document.getElementsByTagName("body")[0];
		this.isPopup = true;
	} else {
		parent = _par;
		this.isPopup = false;
	}
	this.date = this.dateStr ? new Date(this.dateStr) : new Date();

	var table = Calendar.createElement("table");
	this.table = table;
	table.cellSpacing = 0;
	table.cellPadding = 0;
	table.calendar = this;
	Calendar.addEvent(table, "mousedown", Calendar.tableMouseDown);

	var div = Calendar.createElement("div");
	this.element = div;
	div.className = "calendar";
	if (this.isPopup) {
		div.style.position = "absolute";
		div.style.display = "none";
	}
	div.appendChild(table);

	var thead = Calendar.createElement("thead", table);
	var cell = null;
	var row = null;

	var cal = this;
	var hh = function (text, cs, navtype) {
		cell = Calendar.createElement("td", row);
		cell.colSpan = cs;
		cell.className = "button";
		if (navtype != 0 && Math.abs(navtype) <= 2)
			cell.className += " nav";
		Calendar._add_evs(cell);
		cell.calendar = cal;
		cell.navtype = navtype;
		cell.innerHTML = "<div unselectable='on'>" + text + "</div>";
		return cell;
	};

	row = Calendar.createElement("tr", thead);
	var title_length = 6;
	(this.isPopup) && --title_length;
	(this.weekNumbers) && ++title_length;

	hh("?", 1, 400).ttip = Calendar._TT["INFO"];
	this.title = hh("", title_length, 300);
	this.title.className = "title";
	if (this.isPopup) {
		this.title.ttip = Calendar._TT["DRAG_TO_MOVE"];
		this.title.style.cursor = "move";
		hh("&#x00d7;", 1, 200).ttip = Calendar._TT["CLOSE"];
	}

	row = Calendar.createElement("tr", thead);
	row.className = "headrow";

	this._nav_py = hh("&#x00ab;", 1, -2);
	this._nav_py.ttip = Calendar._TT["PREV_YEAR"];

	this._nav_pm = hh("&#x2039;", 1, -1);
	this._nav_pm.ttip = Calendar._TT["PREV_MONTH"];

	this._nav_now = hh(Calendar._TT["TODAY"], this.weekNumbers ? 4 : 3, 0);
	this._nav_now.ttip = Calendar._TT["GO_TODAY"];

	this._nav_nm = hh("&#x203a;", 1, 1);
	this._nav_nm.ttip = Calendar._TT["NEXT_MONTH"];

	this._nav_ny = hh("&#x00bb;", 1, 2);
	this._nav_ny.ttip = Calendar._TT["NEXT_YEAR"];

	// day names
	row = Calendar.createElement("tr", thead);
	row.className = "daynames";
	if (this.weekNumbers) {
		cell = Calendar.createElement("td", row);
		cell.className = "name wn";
		cell.innerHTML = Calendar._TT["WK"];
	}
	for (var i = 7; i > 0; --i) {
		cell = Calendar.createElement("td", row);
		if (!i) {
			cell.navtype = 100;
			cell.calendar = this;
			Calendar._add_evs(cell);
		}
	}
	this.firstdayname = (this.weekNumbers) ? row.firstChild.nextSibling : row.firstChild;
	this._displayWeekdays();

	var tbody = Calendar.createElement("tbody", table);
	this.tbody = tbody;

	for (i = 6; i > 0; --i) {
		row = Calendar.createElement("tr", tbody);
		if (this.weekNumbers) {
			cell = Calendar.createElement("td", row);
		}
		for (var j = 7; j > 0; --j) {
			cell = Calendar.createElement("td", row);
			cell.calendar = this;
			Calendar._add_evs(cell);
		}
	}

	if (this.showsTime) {
		row = Calendar.createElement("tr", tbody);
		row.className = "time";

		cell = Calendar.createElement("td", row);
		cell.className = "time";
		cell.colSpan = 2;
		cell.innerHTML = Calendar._TT["TIME"] || "&nbsp;";

		cell = Calendar.createElement("td", row);
		cell.className = "time";
		cell.colSpan = this.weekNumbers ? 4 : 3;

		(function(){
			function makeTimePart(className, init, range_start, range_end) {
				var part = Calendar.createElement("span", cell);
				part.className = className;
				part.innerHTML = init;
				part.calendar = cal;
				part.ttip = Calendar._TT["TIME_PART"];
				part.navtype = 50;
				part._range = [];
				if (typeof range_start != "number")
					part._range = range_start;
				else {
					for (var i = range_start; i <= range_end; ++i) {
						var txt;
						if (i < 10 && range_end >= 10) txt = '0' + i;
						else txt = '' + i;
						part._range[part._range.length] = txt;
					}
				}
				Calendar._add_evs(part);
				return part;
			};
			var hrs = cal.date.getHours();
			var mins = cal.date.getMinutes();
			var t12 = !cal.time24;
			var pm = (hrs > 12);
			if (t12 && pm) hrs -= 12;
			var H = makeTimePart("hour", hrs, t12 ? 1 : 0, t12 ? 12 : 23);
			var span = Calendar.createElement("span", cell);
			span.innerHTML = ":";
			span.className = "colon";
			var M = makeTimePart("minute", mins, 0, 59);
			var AP = null;
			cell = Calendar.createElement("td", row);
			cell.className = "time";
			cell.colSpan = 2;
			if (t12)
				AP = makeTimePart("ampm", pm ? "pm" : "am", ["am", "pm"]);
			else
				cell.innerHTML = "&nbsp;";

			cal.onSetTime = function() {
				var pm, hrs = this.date.getHours(),
					mins = this.date.getMinutes();
				if (t12) {
					pm = (hrs >= 12);
					if (pm) hrs -= 12;
					if (hrs == 0) hrs = 12;
					AP.innerHTML = pm ? "pm" : "am";
				}
				H.innerHTML = (hrs < 10) ? ("0" + hrs) : hrs;
				M.innerHTML = (mins < 10) ? ("0" + mins) : mins;
			};

			cal.onUpdateTime = function() {
				var date = this.date;
				var h = parseInt(H.innerHTML, 10);
				if (t12) {
					if (/pm/i.test(AP.innerHTML) && h < 12)
						h += 12;
					else if (/am/i.test(AP.innerHTML) && h == 12)
						h = 0;
				}
				var d = date.getDate();
				var m = date.getMonth();
				var y = date.getFullYear();
				date.setHours(h);
				date.setMinutes(parseInt(M.innerHTML, 10));
				date.setFullYear(y);
				date.setMonth(m);
				date.setDate(d);
				this.dateClicked = false;
				this.callHandler();
			};
		})();
	} else {
		this.onSetTime = this.onUpdateTime = function() {};
	}

	var tfoot = Calendar.createElement("tfoot", table);

	row = Calendar.createElement("tr", tfoot);
	row.className = "footrow";

	cell = hh(Calendar._TT["SEL_DATE"], this.weekNumbers ? 8 : 7, 300);
	cell.className = "ttip";
	if (this.isPopup) {
		cell.ttip = Calendar._TT["DRAG_TO_MOVE"];
		cell.style.cursor = "move";
	}
	this.tooltips = cell;

	div = Calendar.createElement("div", this.element);
	this.monthsCombo = div;
	div.className = "combo";
	for (i = 0; i < Calendar._MN.length; ++i) {
		var mn = Calendar.createElement("div");
		mn.className = Calendar.is_ie ? "label-IEfix" : "label";
		mn.month = i;
		mn.innerHTML = Calendar._SMN[i];
		div.appendChild(mn);
	}

	div = Calendar.createElement("div", this.element);
	this.yearsCombo = div;
	div.className = "combo";
	for (i = 12; i > 0; --i) {
		var yr = Calendar.createElement("div");
		yr.className = Calendar.is_ie ? "label-IEfix" : "label";
		div.appendChild(yr);
	}

	this._init(this.firstDayOfWeek, this.date);
	parent.appendChild(this.element);
};

/** keyboard navigation, only for popup calendars */
Calendar._keyEvent = function(ev) {
	var cal = window._dynarch_popupCalendar;
	if (!cal || cal.multiple)
		return false;
	(Calendar.is_ie) && (ev = window.event);
	var act = (Calendar.is_ie || ev.type == "keypress"),
		K = ev.keyCode;
	if (ev.ctrlKey) {
		switch (K) {
		    case 37: // KEY left
			act && Calendar.cellClick(cal._nav_pm);
			break;
		    case 38: // KEY up
			act && Calendar.cellClick(cal._nav_py);
			break;
		    case 39: // KEY right
			act && Calendar.cellClick(cal._nav_nm);
			break;
		    case 40: // KEY down
			act && Calendar.cellClick(cal._nav_ny);
			break;
		    default:
			return false;
		}
	} else switch (K) {
	    case 32: // KEY space (now)
		Calendar.cellClick(cal._nav_now);
		break;
	    case 27: // KEY esc
		act && cal.callCloseHandler();
		break;
	    case 37: // KEY left
	    case 38: // KEY up
	    case 39: // KEY right
	    case 40: // KEY down
		if (act) {
			var prev, x, y, ne, el, step;
			prev = K == 37 || K == 38;
			step = (K == 37 || K == 39) ? 1 : 7;
			function setVars() {
				el = cal.currentDateEl;
				var p = el.pos;
				x = p & 15;
				y = p >> 4;
				ne = cal.ar_days[y][x];
			};setVars();
			function prevMonth() {
				var date = new Date(cal.date);
				date.setDate(date.getDate() - step);
				cal.setDate(date);
			};
			function nextMonth() {
				var date = new Date(cal.date);
				date.setDate(date.getDate() + step);
				cal.setDate(date);
			};
			while (1) {
				switch (K) {
				    case 37: // KEY left
					if (--x >= 0)
						ne = cal.ar_days[y][x];
					else {
						x = 6;
						K = 38;
						continue;
					}
					break;
				    case 38: // KEY up
					if (--y >= 0)
						ne = cal.ar_days[y][x];
					else {
						prevMonth();
						setVars();
					}
					break;
				    case 39: // KEY right
					if (++x < 7)
						ne = cal.ar_days[y][x];
					else {
						x = 0;
						K = 40;
						continue;
					}
					break;
				    case 40: // KEY down
					if (++y < cal.ar_days.length)
						ne = cal.ar_days[y][x];
					else {
						nextMonth();
						setVars();
					}
					break;
				}
				break;
			}
			if (ne) {
				if (!ne.disabled)
					Calendar.cellClick(ne);
				else if (prev)
					prevMonth();
				else
					nextMonth();
			}
		}
		break;
	    case 13: // KEY enter
		if (act)
			Calendar.cellClick(cal.currentDateEl, ev);
		break;
	    default:
		return false;
	}
	return Calendar.stopEvent(ev);
};

/**
 *  (RE)Initializes the calendar to the given date and firstDayOfWeek
 */
Calendar.prototype._init = function (firstDayOfWeek, date) {
	var today = new Date(),
		TY = today.getFullYear(),
		TM = today.getMonth(),
		TD = today.getDate();
	this.table.style.visibility = "hidden";
	var year = date.getFullYear();
	if (year < this.minYear) {
		year = this.minYear;
		date.setFullYear(year);
	} else if (year > this.maxYear) {
		year = this.maxYear;
		date.setFullYear(year);
	}
	this.firstDayOfWeek = firstDayOfWeek;
	this.date = new Date(date);
	var month = date.getMonth();
	var mday = date.getDate();
	var no_days = date.getMonthDays();

	// calendar voodoo for computing the first day that would actually be
	// displayed in the calendar, even if it's from the previous month.
	// WARNING: this is magic. ;-)
	date.setDate(1);
	var day1 = (date.getDay() - this.firstDayOfWeek) % 7;
	if (day1 < 0)
		day1 += 7;
	date.setDate(-day1);
	date.setDate(date.getDate() + 1);

	var row = this.tbody.firstChild;
	var MN = Calendar._SMN[month];
	var ar_days = this.ar_days = new Array();
	var weekend = Calendar._TT["WEEKEND"];
	var dates = this.multiple ? (this.datesCells = {}) : null;
	for (var i = 0; i < 6; ++i, row = row.nextSibling) {
		var cell = row.firstChild;
		if (this.weekNumbers) {
			cell.className = "day wn";
			cell.innerHTML = date.getWeekNumber();
			cell = cell.nextSibling;
		}
		row.className = "daysrow";
		var hasdays = false, iday, dpos = ar_days[i] = [];
		for (var j = 0; j < 7; ++j, cell = cell.nextSibling, date.setDate(iday + 1)) {
			iday = date.getDate();
			var wday = date.getDay();
			cell.className = "day";
			cell.pos = i << 4 | j;
			dpos[j] = cell;
			var current_month = (date.getMonth() == month);
			if (!current_month) {
				if (this.showsOtherMonths) {
					cell.className += " othermonth";
					cell.otherMonth = true;
				} else {
					cell.className = "emptycell";
					cell.innerHTML = "&nbsp;";
					cell.disabled = true;
					continue;
				}
			} else {
				cell.otherMonth = false;
				hasdays = true;
			}
			cell.disabled = false;
			cell.innerHTML = this.getDateText ? this.getDateText(date, iday) : iday;
			if (dates)
				dates[date.print("%Y%m%d")] = cell;
			if (this.getDateStatus) {
				var status = this.getDateStatus(date, year, month, iday);
				if (this.getDateToolTip) {
					var toolTip = this.getDateToolTip(date, year, month, iday);
					if (toolTip)
						cell.title = toolTip;
				}
				if (status === true) {
					cell.className += " disabled";
					cell.disabled = true;
				} else {
					if (/disabled/i.test(status))
						cell.disabled = true;
					cell.className += " " + status;
				}
			}
			if (!cell.disabled) {
				cell.caldate = new Date(date);
				cell.ttip = "_";
				if (!this.multiple && current_month
				    && iday == mday && this.hiliteToday) {
					cell.className += " selected";
					this.currentDateEl = cell;
				}
				if (date.getFullYear() == TY &&
				    date.getMonth() == TM &&
				    iday == TD) {
					cell.className += " today";
					cell.ttip += Calendar._TT["PART_TODAY"];
				}
				if (weekend.indexOf(wday.toString()) != -1)
					cell.className += cell.otherMonth ? " oweekend" : " weekend";
			}
		}
		if (!(hasdays || this.showsOtherMonths))
			row.className = "emptyrow";
	}
	this.title.innerHTML = Calendar._MN[month] + ", " + year;
	this.onSetTime();
	this.table.style.visibility = "visible";
	this._initMultipleDates();
	// PROFILE
	// this.tooltips.innerHTML = "Generated in " + ((new Date()) - today) + " ms";
};

Calendar.prototype._initMultipleDates = function() {
	if (this.multiple) {
		for (var i in this.multiple) {
			var cell = this.datesCells[i];
			var d = this.multiple[i];
			if (!d)
				continue;
			if (cell)
				cell.className += " selected";
		}
	}
};

Calendar.prototype._toggleMultipleDate = function(date) {
	if (this.multiple) {
		var ds = date.print("%Y%m%d");
		var cell = this.datesCells[ds];
		if (cell) {
			var d = this.multiple[ds];
			if (!d) {
				Calendar.addClass(cell, "selected");
				this.multiple[ds] = date;
			} else {
				Calendar.removeClass(cell, "selected");
				delete this.multiple[ds];
			}
		}
	}
};

Calendar.prototype.setDateToolTipHandler = function (unaryFunction) {
	this.getDateToolTip = unaryFunction;
};

/**
 *  Calls _init function above for going to a certain date (but only if the
 *  date is different than the currently selected one).
 */
Calendar.prototype.setDate = function (date) {
	if (!date.equalsTo(this.date)) {
		this._init(this.firstDayOfWeek, date);
	}
};

/**
 *  Refreshes the calendar.  Useful if the "disabledHandler" function is
 *  dynamic, meaning that the list of disabled date can change at runtime.
 *  Just * call this function if you think that the list of disabled dates
 *  should * change.
 */
Calendar.prototype.refresh = function () {
	this._init(this.firstDayOfWeek, this.date);
};

/** Modifies the "firstDayOfWeek" parameter (pass 0 for Synday, 1 for Monday, etc.). */
Calendar.prototype.setFirstDayOfWeek = function (firstDayOfWeek) {
	this._init(firstDayOfWeek, this.date);
	this._displayWeekdays();
};

/**
 *  Allows customization of what dates are enabled.  The "unaryFunction"
 *  parameter must be a function object that receives the date (as a JS Date
 *  object) and returns a boolean value.  If the returned value is true then
 *  the passed date will be marked as disabled.
 */
Calendar.prototype.setDateStatusHandler = Calendar.prototype.setDisabledHandler = function (unaryFunction) {
	this.getDateStatus = unaryFunction;
};

/** Customization of allowed year range for the calendar. */
Calendar.prototype.setRange = function (a, z) {
	this.minYear = a;
	this.maxYear = z;
};

/** Calls the first user handler (selectedHandler). */
Calendar.prototype.callHandler = function () {
	if (this.onSelected) {
		this.onSelected(this, this.date.print(this.dateFormat));
	}
};

/** Calls the second user handler (closeHandler). */
Calendar.prototype.callCloseHandler = function () {
	if (this.onClose) {
		this.onClose(this);
	}
	this.hideShowCovered();
};

/** Removes the calendar object from the DOM tree and destroys it. */
Calendar.prototype.destroy = function () {
	var el = this.element.parentNode;
	el.removeChild(this.element);
	Calendar._C = null;
	window._dynarch_popupCalendar = null;
};

/**
 *  Moves the calendar element to a different section in the DOM tree (changes
 *  its parent).
 */
Calendar.prototype.reparent = function (new_parent) {
	var el = this.element;
	el.parentNode.removeChild(el);
	new_parent.appendChild(el);
};

// This gets called when the user presses a mouse button anywhere in the
// document, if the calendar is shown.  If the click was outside the open
// calendar this function closes it.
Calendar._checkCalendar = function(ev) {
	var calendar = window._dynarch_popupCalendar;
	if (!calendar) {
		return false;
	}
	var el = Calendar.is_ie ? Calendar.getElement(ev) : Calendar.getTargetElement(ev);
	for (; el != null && el != calendar.element; el = el.parentNode);
	if (el == null) {
		// calls closeHandler which should hide the calendar.
		window._dynarch_popupCalendar.callCloseHandler();
		return Calendar.stopEvent(ev);
	}
};

/** Shows the calendar. */
Calendar.prototype.show = function () {
	var rows = this.table.getElementsByTagName("tr");
	for (var i = rows.length; i > 0;) {
		var row = rows[--i];
		Calendar.removeClass(row, "rowhilite");
		var cells = row.getElementsByTagName("td");
		for (var j = cells.length; j > 0;) {
			var cell = cells[--j];
			Calendar.removeClass(cell, "hilite");
			Calendar.removeClass(cell, "active");
		}
	}
	this.element.style.display = "block";
	this.hidden = false;
	if (this.isPopup) {
		window._dynarch_popupCalendar = this;
		Calendar.addEvent(document, "keydown", Calendar._keyEvent);
		Calendar.addEvent(document, "keypress", Calendar._keyEvent);
		Calendar.addEvent(document, "mousedown", Calendar._checkCalendar);
	}
	this.hideShowCovered();
};

/**
 *  Hides the calendar.  Also removes any "hilite" from the class of any TD
 *  element.
 */
Calendar.prototype.hide = function () {
	if (this.isPopup) {
		Calendar.removeEvent(document, "keydown", Calendar._keyEvent);
		Calendar.removeEvent(document, "keypress", Calendar._keyEvent);
		Calendar.removeEvent(document, "mousedown", Calendar._checkCalendar);
	}
	this.element.style.display = "none";
	this.hidden = true;
	this.hideShowCovered();
};

/**
 *  Shows the calendar at a given absolute position (beware that, depending on
 *  the calendar element style -- position property -- this might be relative
 *  to the parent's containing rectangle).
 */
Calendar.prototype.showAt = function (x, y) {
	var s = this.element.style;
	s.left = x + "px";
	s.top = y + "px";
	this.show();
};

/** Shows the calendar near a given element. */
Calendar.prototype.showAtElement = function (el, opts) {
	var self = this;
	var p = Calendar.getAbsolutePos(el);
	if (!opts || typeof opts != "string") {
		this.showAt(p.x, p.y + el.offsetHeight);
		return true;
	}
    // function OLDfixPosition(box) {
    //  if (box.x < 0)
    //      box.x = 0;
    //  if (box.y < 0)
    //      box.y = 0;
    //  var cp = document.createElement("div");
    //  var s = cp.style;
    //  s.position = "absolute";
    //  s.right = s.bottom = s.width = s.height = "0px";
    //  document.body.appendChild(cp);
    //  var br = Calendar.getAbsolutePos(cp);
    //  document.body.removeChild(cp);
    //  if (Calendar.is_ie) {
    //      br.y += document.body.scrollTop;
    //      br.x += document.body.scrollLeft;
    //  } else {
    //      br.y += window.scrollY;
    //      br.x += window.scrollX;
    //  }
    //  var tmp = box.x + box.width - br.x;
    //  if (tmp > 0) box.x -= tmp;
    //  tmp = box.y + box.height - br.y;
    //  if (tmp > 0) box.y -= tmp;
    // };
	
// Anonymous My x-only fix (code rearranged slightly to clarify the issue):

	function fixPosition(box) {
		var cp = document.createElement("div");
		var s = cp.style;
		s.position = "absolute";
		s.right = s.bottom = s.width = s.height = "0px";
		document.body.appendChild(cp);
		var br = Calendar.getAbsolutePos(cp);

		document.body.removeChild(cp);

// 
        // if (Calendar.is_ie) {
  if (Calendar.is_ie5 || Calendar.is_ie6) { 		    
			br.y += document.body.scrollTop;
			br.x += document.body.scrollLeft;
		} else {
			br.y += window.scrollY;
			br.x += window.scrollX;
		}

// 
		if (box.y < 0 || br.y < box.height)
			box.y = 0;

// 

		if (box.x < 0)
			box.x = 0;
		var tmp = box.x + box.width - br.x;
		if (tmp > 0) box.x -= tmp;

	};
		
	this.element.style.display = "block";
	Calendar.continuation_for_the_fucking_khtml_browser = function() {
		var w = self.element.offsetWidth;
		var h = self.element.offsetHeight;
		self.element.style.display = "none";
		var valign = opts.substr(0, 1);
		var halign = "l";
		if (opts.length > 1) {
			halign = opts.substr(1, 1);
		}
		// vertical alignment
		switch (valign) {
		    case "T": p.y -= h; break;
		    case "B": p.y += el.offsetHeight; break;
		    case "C": p.y += (el.offsetHeight - h) / 2; break;
		    case "t": p.y += el.offsetHeight - h; break;
		    case "b": break; // already there
		}
		// horizontal alignment
		switch (halign) {
		    case "L": p.x -= w; break;
		    case "R": p.x += el.offsetWidth; break;
		    case "C": p.x += (el.offsetWidth - w) / 2; break;
		    case "l": p.x += el.offsetWidth - w; break;
		    case "r": break; // already there
		}
		p.width = w;
		p.height = h + 40;
		self.monthsCombo.style.display = "none";
		fixPosition(p);
		self.showAt(p.x, p.y);
	};
	if (Calendar.is_khtml)
		setTimeout("Calendar.continuation_for_the_fucking_khtml_browser()", 10);
	else
		Calendar.continuation_for_the_fucking_khtml_browser();
};

/** Customizes the date format. */
Calendar.prototype.setDateFormat = function (str) {
	this.dateFormat = str;
};

/** Customizes the tooltip date format. */
Calendar.prototype.setTtDateFormat = function (str) {
	this.ttDateFormat = str;
};

/**
 *  Tries to identify the date represented in a string.  If successful it also
 *  calls this.setDate which moves the calendar to the given date.
 */
Calendar.prototype.parseDate = function(str, fmt) {
	if (!fmt)
		fmt = this.dateFormat;
	this.setDate(Date.parseDate(str, fmt));
};

Calendar.prototype.hideShowCovered = function () {
	if (!Calendar.is_ie && !Calendar.is_opera)
		return;
	function getVisib(obj){
		var value = obj.style.visibility;
		if (!value) {
			if (document.defaultView && typeof (document.defaultView.getComputedStyle) == "function") { // Gecko, W3C
				if (!Calendar.is_khtml)
					value = document.defaultView.
						getComputedStyle(obj, "").getPropertyValue("visibility");
				else
					value = '';
			} else if (obj.currentStyle) { // IE
				value = obj.currentStyle.visibility;
			} else
				value = '';
		}
		return value;
	};

	var tags = new Array("applet", "iframe", "select");
	var el = this.element;

	var p = Calendar.getAbsolutePos(el);
	var EX1 = p.x;
	var EX2 = el.offsetWidth + EX1;
	var EY1 = p.y;
	var EY2 = el.offsetHeight + EY1;

	for (var k = tags.length; k > 0; ) {
		var ar = document.getElementsByTagName(tags[--k]);
		var cc = null;

		for (var i = ar.length; i > 0;) {
			cc = ar[--i];

			p = Calendar.getAbsolutePos(cc);
			var CX1 = p.x;
			var CX2 = cc.offsetWidth + CX1;
			var CY1 = p.y;
			var CY2 = cc.offsetHeight + CY1;

			if (this.hidden || (CX1 > EX2) || (CX2 < EX1) || (CY1 > EY2) || (CY2 < EY1)) {
				if (!cc.__msh_save_visibility) {
					cc.__msh_save_visibility = getVisib(cc);
				}
				cc.style.visibility = cc.__msh_save_visibility;
			} else {
				if (!cc.__msh_save_visibility) {
					cc.__msh_save_visibility = getVisib(cc);
				}
				cc.style.visibility = "hidden";
			}
		}
	}
};

/** Internal function; it displays the bar with the names of the weekday. */
Calendar.prototype._displayWeekdays = function () {
	var fdow = this.firstDayOfWeek;
	var cell = this.firstdayname;
	var weekend = Calendar._TT["WEEKEND"];
	for (var i = 0; i < 7; ++i) {
		cell.className = "day name";
		var realday = (i + fdow) % 7;
		if (i) {
			cell.ttip = Calendar._TT["DAY_FIRST"].replace("%s", Calendar._DN[realday]);
			cell.navtype = 100;
			cell.calendar = this;
			cell.fdow = realday;
			Calendar._add_evs(cell);
		}
		if (weekend.indexOf(realday.toString()) != -1) {
			Calendar.addClass(cell, "weekend");
		}
		cell.innerHTML = Calendar._SDN[(i + fdow) % 7];
		cell = cell.nextSibling;
	}
};

/** Internal function.  Hides all combo boxes that might be displayed. */
Calendar.prototype._hideCombos = function () {
	this.monthsCombo.style.display = "none";
	this.yearsCombo.style.display = "none";
};

/** Internal function.  Starts dragging the element. */
Calendar.prototype._dragStart = function (ev) {
	if (this.dragging) {
		return;
	}
	this.dragging = true;
	var posX;
	var posY;
	if (Calendar.is_ie) {
		posY = window.event.clientY + document.body.scrollTop;
		posX = window.event.clientX + document.body.scrollLeft;
	} else {
		posY = ev.clientY + window.scrollY;
		posX = ev.clientX + window.scrollX;
	}
	var st = this.element.style;
	this.xOffs = posX - parseInt(st.left);
	this.yOffs = posY - parseInt(st.top);
	with (Calendar) {
		addEvent(document, "mousemove", calDragIt);
		addEvent(document, "mouseup", calDragEnd);
	}
};

// BEGIN: DATE OBJECT PATCHES

/** Adds the number of days array to the Date object. */
Date._MD = new Array(31,28,31,30,31,30,31,31,30,31,30,31);

/** Constants used for time computations */
Date.SECOND = 1000 /* milliseconds */;
Date.MINUTE = 60 * Date.SECOND;
Date.HOUR   = 60 * Date.MINUTE;
Date.DAY    = 24 * Date.HOUR;
Date.WEEK   =  7 * Date.DAY;

Date.parseDate = function(str, fmt) {

	var today = new Date();
	var y = 0;
	var m = -1;
	var d = 0;
	var a = str.split(/\W+/);
	var b = fmt.match(/%./g);
	var i = 0, j = 0;
	var hr = 0;
	var min = 0;
	for (i = 0; i < a.length; ++i) {
		if (!a[i])
			continue;
		switch (b[i]) {
		    case "%d":
		    case "%e":
			d = parseInt(a[i], 10);
			break;

		    case "%m":
			m = parseInt(a[i], 10) - 1;
			break;

		    case "%Y":
		    case "%y":
			y = parseInt(a[i], 10);
			(y < 100) && (y += (y > 29) ? 1900 : 2000);
			break;

		    case "%b":
		    case "%B":
			for (j = 0; j < 12; ++j) {
				if (Calendar._MN[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) { m = j; break; }
			}
			break;

		    case "%H":
		    case "%I":
		    case "%k":
		    case "%l":
			hr = parseInt(a[i], 10);
			break;

		    case "%P":
		    case "%p":
			if (/pm/i.test(a[i]) && hr < 12)
				hr += 12;
			else if (/am/i.test(a[i]) && hr >= 12)
				hr -= 12;
			break;

		    case "%M":
			min = parseInt(a[i], 10);
			break;
		}
	}
	if (isNaN(y)) y = today.getFullYear();
	if (isNaN(m)) m = today.getMonth();
	if (isNaN(d)) d = today.getDate();
	if (isNaN(hr)) hr = today.getHours();
	if (isNaN(min)) min = today.getMinutes();
	if (y != 0 && m != -1 && d != 0)
		return new Date(y, m, d, hr, min, 0);
	y = 0; m = -1; d = 0;
	for (i = 0; i < a.length; ++i) {
		if (a[i].search(/[a-zA-Z]+/) != -1) {
			var t = -1;
			for (j = 0; j < 12; ++j) {
				if (Calendar._MN[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) { t = j; break; }
			}
			if (t != -1) {
				if (m != -1) {
					d = m+1;
				}
				m = t;
			}
		} else if (parseInt(a[i], 10) <= 12 && m == -1) {
			m = a[i]-1;
		} else if (parseInt(a[i], 10) > 31 && y == 0) {
			y = parseInt(a[i], 10);
			(y < 100) && (y += (y > 29) ? 1900 : 2000);
		} else if (d == 0) {
			d = a[i];
		}
	}
	if (y == 0)
		y = today.getFullYear();
	if (m != -1 && d != 0)
		return new Date(y, m, d, hr, min, 0);
	return today;
};

/** Returns the number of days in the current month */
Date.prototype.getMonthDays = function(month) {
	var year = this.getFullYear();
	if (typeof month == "undefined") {
		month = this.getMonth();
	}
	if (((0 == (year%4)) && ( (0 != (year%100)) || (0 == (year%400)))) && month == 1) {
		return 29;
	} else {
		return Date._MD[month];
	}
};

/** Returns the number of day in the year. */
Date.prototype.getDayOfYear = function() {
	var now = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0);
	var then = new Date(this.getFullYear(), 0, 0, 0, 0, 0);
	var time = now - then;
	return Math.floor(time / Date.DAY);
};

/** Returns the number of the week in year, as defined in ISO 8601. */
Date.prototype.getWeekNumber = function() {
	var d = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0);
	var DoW = d.getDay();
	d.setDate(d.getDate() - (DoW + 6) % 7 + 3); // Nearest Thu
	var ms = d.valueOf(); // GMT
	d.setMonth(0);
	d.setDate(4); // Thu in Week 1
	return Math.round((ms - d.valueOf()) / (7 * 864e5)) + 1;
};

/** Checks date and time equality */
Date.prototype.equalsTo = function(date) {
	return ((this.getFullYear() == date.getFullYear()) &&
		(this.getMonth() == date.getMonth()) &&
		(this.getDate() == date.getDate()) &&
		(this.getHours() == date.getHours()) &&
		(this.getMinutes() == date.getMinutes()));
};

/** Set only the year, month, date parts (keep existing time) */
Date.prototype.setDateOnly = function(date) {
	var tmp = new Date(date);
	this.setDate(1);
	this.setFullYear(tmp.getFullYear());
	this.setMonth(tmp.getMonth());
	this.setDate(tmp.getDate());
};

/** Prints the date in a string according to the given format. */
Date.prototype.print = function (str) {
	var m = this.getMonth();
	var d = this.getDate();
	var y = this.getFullYear();
	var wn = this.getWeekNumber();
	var w = this.getDay();
	var s = {};
	var hr = this.getHours();
	var pm = (hr >= 12);
	var ir = (pm) ? (hr - 12) : hr;
	var dy = this.getDayOfYear();
	if (ir == 0)
		ir = 12;
	var min = this.getMinutes();
	var sec = this.getSeconds();
	s["%a"] = Calendar._SDN[w]; // abbreviated weekday name [FIXME: I18N]
	s["%A"] = Calendar._DN[w]; // full weekday name
	s["%b"] = Calendar._SMN[m]; // abbreviated month name [FIXME: I18N]
	s["%B"] = Calendar._MN[m]; // full month name
	// FIXME: %c : preferred date and time representation for the current locale
	s["%C"] = 1 + Math.floor(y / 100); // the century number
	s["%d"] = (d < 10) ? ("0" + d) : d; // the day of the month (range 01 to 31)
	s["%e"] = d; // the day of the month (range 1 to 31)
	// FIXME: %D : american date style: %m/%d/%y
	// FIXME: %E, %F, %G, %g, %h (man strftime)
	s["%H"] = (hr < 10) ? ("0" + hr) : hr; // hour, range 00 to 23 (24h format)
	s["%I"] = (ir < 10) ? ("0" + ir) : ir; // hour, range 01 to 12 (12h format)
	s["%j"] = (dy < 100) ? ((dy < 10) ? ("00" + dy) : ("0" + dy)) : dy; // day of the year (range 001 to 366)
	s["%k"] = hr;		// hour, range 0 to 23 (24h format)
	s["%l"] = ir;		// hour, range 1 to 12 (12h format)
	s["%m"] = (m < 9) ? ("0" + (1+m)) : (1+m); // month, range 01 to 12
	s["%M"] = (min < 10) ? ("0" + min) : min; // minute, range 00 to 59
	s["%n"] = "\n";		// a newline character
	s["%p"] = pm ? "PM" : "AM";
	s["%P"] = pm ? "pm" : "am";
	// FIXME: %r : the time in am/pm notation %I:%M:%S %p
	// FIXME: %R : the time in 24-hour notation %H:%M
	s["%s"] = Math.floor(this.getTime() / 1000);
	s["%S"] = (sec < 10) ? ("0" + sec) : sec; // seconds, range 00 to 59
	s["%t"] = "\t";		// a tab character
	// FIXME: %T : the time in 24-hour notation (%H:%M:%S)
	s["%U"] = s["%W"] = s["%V"] = (wn < 10) ? ("0" + wn) : wn;
	s["%u"] = w + 1;	// the day of the week (range 1 to 7, 1 = MON)
	s["%w"] = w;		// the day of the week (range 0 to 6, 0 = SUN)
	// FIXME: %x : preferred date representation for the current locale without the time
	// FIXME: %X : preferred time representation for the current locale without the date
	s["%y"] = ('' + y).substr(2, 2); // year without the century (range 00 to 99)
	s["%Y"] = y;		// year with the century
	s["%%"] = "%";		// a literal '%' character

	var re = /%./g;
	if (!Calendar.is_ie5 && !Calendar.is_khtml)
		return str.replace(re, function (par) { return s[par] || par; });

	var a = str.match(re);
	for (var i = 0; i < a.length; i++) {
		var tmp = s[a[i]];
		if (tmp) {
			re = new RegExp(a[i], 'g');
			str = str.replace(re, tmp);
		}
	}

	return str;
};

Date.prototype.__msh_oldSetFullYear = Date.prototype.setFullYear;
Date.prototype.setFullYear = function(y) {
	var d = new Date(this);
	d.__msh_oldSetFullYear(y);
	if (d.getMonth() != this.getMonth())
		this.setDate(28);
	this.__msh_oldSetFullYear(y);
};

// END: DATE OBJECT PATCHES


// global object that remembers the calendar
window._dynarch_popupCalendar = null;


// ** I18N

// Calendar EN language
// Author: Mihai Bazon, <mihai_bazon@yahoo.com>
// Encoding: any
// Distributed under the same terms as the calendar itself.

// For translators: please use UTF-8 if possible.  We strongly believe that
// Unicode is the answer to a real internationalized world.  Also please
// include your contact information in the header, as can be seen above.

// full day names
Calendar._DN = new Array
("Sunday",
 "Monday",
 "Tuesday",
 "Wednesday",
 "Thursday",
 "Friday",
 "Saturday",
 "Sunday");

// Please note that the following array of short day names (and the same goes
// for short month names, _SMN) isn't absolutely necessary.  We give it here
// for exemplification on how one can customize the short day names, but if
// they are simply the first N letters of the full name you can simply say:
//
//   Calendar._SDN_len = N; // short day name length
//   Calendar._SMN_len = N; // short month name length
//
// If N = 3 then this is not needed either since we assume a value of 3 if not
// present, to be compatible with translation files that were written before
// this feature.

// short day names
Calendar._SDN = new Array
("Sun",
 "Mon",
 "Tue",
 "Wed",
 "Thu",
 "Fri",
 "Sat",
 "Sun");

// First day of the week. "0" means display Sunday first, "1" means display
// Monday first, etc.
Calendar._FD = 0;

// full month names
Calendar._MN = new Array
("January",
 "February",
 "March",
 "April",
 "May",
 "June",
 "July",
 "August",
 "September",
 "October",
 "November",
 "December");

// short month names
Calendar._SMN = new Array
("Jan",
 "Feb",
 "Mar",
 "Apr",
 "May",
 "Jun",
 "Jul",
 "Aug",
 "Sep",
 "Oct",
 "Nov",
 "Dec");

// tooltips
Calendar._TT = {};
Calendar._TT["INFO"] = "About the calendar";

Calendar._TT["ABOUT"] =
"DHTML Date/Time Selector\n" +
"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-)
"For latest version visit: http://www.dynarch.com/projects/calendar/\n" +
"Distributed under GNU LGPL.  See http://gnu.org/licenses/lgpl.html for details." +
"\n\n" +
"Date selection:\n" +
"- Use the \xab, \xbb buttons to select year\n" +
"- Use the " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " buttons to select month\n" +
"- Hold mouse button on any of the above buttons for faster selection.";
Calendar._TT["ABOUT_TIME"] = "\n\n" +
"Time selection:\n" +
"- Click on any of the time parts to increase it\n" +
"- or Shift-click to decrease it\n" +
"- or click and drag for faster selection.";

Calendar._TT["PREV_YEAR"] = "Prev. year (hold for menu)";
Calendar._TT["PREV_MONTH"] = "Prev. month (hold for menu)";
Calendar._TT["GO_TODAY"] = "Go Today";
Calendar._TT["NEXT_MONTH"] = "Next month (hold for menu)";
Calendar._TT["NEXT_YEAR"] = "Next year (hold for menu)";
Calendar._TT["SEL_DATE"] = "Select date";
Calendar._TT["DRAG_TO_MOVE"] = "Drag to move";
Calendar._TT["PART_TODAY"] = " (today)";

// the following is to inform that "%s" is to be the first day of week
// %s will be replaced with the day name.
Calendar._TT["DAY_FIRST"] = "Display %s first";

// This may be locale-dependent.  It specifies the week-end days, as an array
// of comma-separated numbers.  The numbers are from 0 to 6: 0 means Sunday, 1
// means Monday, etc.
Calendar._TT["WEEKEND"] = "0,6";

Calendar._TT["CLOSE"] = "Close";
Calendar._TT["TODAY"] = "Today";
Calendar._TT["TIME_PART"] = "(Shift-)Click or drag to change value";

// date formats
Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d";
Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e";

Calendar._TT["WK"] = "wk";
Calendar._TT["TIME"] = "Time:";


/*  Copyright Mihai Bazon, 2002, 2003  |  http://dynarch.com/mishoo/
 * ---------------------------------------------------------------------------
 *
 * The DHTML Calendar
 *
 * Details and latest version at:
 * http://dynarch.com/mishoo/calendar.epl
 *
 * This script is distributed under the GNU Lesser General Public License.
 * Read the entire license text here: http://www.gnu.org/licenses/lgpl.html
 *
 * This file defines helper functions for setting up the calendar.  They are
 * intended to help non-programmers get a working calendar on their site
 * quickly.  This script should not be seen as part of the calendar.  It just
 * shows you what one can do with the calendar, while in the same time
 * providing a quick and simple method for setting it up.  If you need
 * exhaustive customization of the calendar creation process feel free to
 * modify this code to suit your needs (this is recommended and much better
 * than modifying calendar.js itself).
 */

// $Id: calendar-setup.js,v 1.25 2005/03/07 09:51:33 mishoo Exp $

/**
 *  This function "patches" an input field (or other element) to use a calendar
 *  widget for date selection.
 *
 *  The "params" is a single object that can have the following properties:
 *
 *    prop. name   | description
 *  -------------------------------------------------------------------------------------------------
 *   inputField    | the ID of an input field to store the date
 *   displayArea   | the ID of a DIV or other element to show the date
 *   button        | ID of a button or other element that will trigger the calendar
 *   eventName     | event that will trigger the calendar, without the "on" prefix (default: "click")
 *   ifFormat      | date format that will be stored in the input field
 *   daFormat      | the date format that will be used to display the date in displayArea
 *   singleClick   | (true/false) wether the calendar is in single click mode or not (default: true)
 *   firstDay      | numeric: 0 to 6.  "0" means display Sunday first, "1" means display Monday first, etc.
 *   align         | alignment (default: "Br"); if you don't know what's this see the calendar documentation
 *   range         | array with 2 elements.  Default: [1900, 2999] -- the range of years available
 *   weekNumbers   | (true/false) if it's true (default) the calendar will display week numbers
 *   flat          | null or element ID; if not null the calendar will be a flat calendar having the parent with the given ID
 *   flatCallback  | function that receives a JS Date object and returns an URL to point the browser to (for flat calendar)
 *   disableFunc   | function that receives a JS Date object and should return true if that date has to be disabled in the calendar
 *   onSelect      | function that gets called when a date is selected.  You don't _have_ to supply this (the default is generally okay)
 *   onClose       | function that gets called when the calendar is closed.  [default]
 *   onUpdate      | function that gets called after the date is updated in the input field.  Receives a reference to the calendar.
 *   date          | the date that the calendar will be initially displayed to
 *   showsTime     | default: false; if true the calendar will include a time selector
 *   timeFormat    | the time format; can be "12" or "24", default is "12"
 *   electric      | if true (default) then given fields/date areas are updated for each move; otherwise they're updated only on close
 *   step          | configures the step of the years in drop-down boxes; default: 2
 *   position      | configures the calendar absolute position; default: null
 *   cache         | if "true" (but default: "false") it will reuse the same calendar object, where possible
 *   showOthers    | if "true" (but default: "false") it will show days from other months too
 *
 *  None of them is required, they all have default values.  However, if you
 *  pass none of "inputField", "displayArea" or "button" you'll get a warning
 *  saying "nothing to setup".
 */
Calendar.setup = function (params) {
	function param_default(pname, def) { if (typeof params[pname] == "undefined") { params[pname] = def; } };

	param_default("inputField",     null);
	param_default("displayArea",    null);
	param_default("button",         null);
	param_default("eventName",      "click");
	param_default("ifFormat",       "%Y/%m/%d");
	param_default("daFormat",       "%Y/%m/%d");
	param_default("singleClick",    true);
	param_default("disableFunc",    null);
	param_default("dateStatusFunc", params["disableFunc"]);	// takes precedence if both are defined
	param_default("dateText",       null);
	param_default("firstDay",       null);
	param_default("align",          "Br");
	param_default("range",          [1900, 2999]);
	param_default("weekNumbers",    true);
	param_default("flat",           null);
	param_default("flatCallback",   null);
	param_default("onSelect",       null);
	param_default("onClose",        null);
	param_default("onUpdate",       null);
	param_default("date",           null);
	param_default("showsTime",      false);
	param_default("timeFormat",     "24");
	param_default("electric",       true);
	param_default("step",           2);
	param_default("position",       null);
	param_default("cache",          false);
	param_default("showOthers",     false);
	param_default("multiple",       null);

	var tmp = ["inputField", "displayArea", "button"];
	for (var i in tmp) {
		if (typeof params[tmp[i]] == "string") {
			params[tmp[i]] = document.getElementById(params[tmp[i]]);
		}
	}
	if (!(params.flat || params.multiple || params.inputField || params.displayArea || params.button)) {
		alert("Calendar.setup:\n  Nothing to setup (no fields found).  Please check your code");
		return false;
	}

	function onSelect(cal) {
		var p = cal.params;
		var update = (cal.dateClicked || p.electric);
		if (update && p.inputField) {
			p.inputField.value = cal.date.print(p.ifFormat);
			if (typeof p.inputField.onchange == "function")
				p.inputField.onchange();
		}
		if (update && p.displayArea)
			p.displayArea.innerHTML = cal.date.print(p.daFormat);
		if (update && typeof p.onUpdate == "function")
			p.onUpdate(cal);
		if (update && p.flat) {
			if (typeof p.flatCallback == "function")
				p.flatCallback(cal);
		}
		if (update && p.singleClick && cal.dateClicked)
			cal.callCloseHandler();
	};

	if (params.flat != null) {
		if (typeof params.flat == "string")
			params.flat = document.getElementById(params.flat);
		if (!params.flat) {
			alert("Calendar.setup:\n  Flat specified but can't find parent.");
			return false;
		}
		var cal = new Calendar(params.firstDay, params.date, params.onSelect || onSelect);
		cal.showsOtherMonths = params.showOthers;
		cal.showsTime = params.showsTime;
		cal.time24 = (params.timeFormat == "24");
		cal.params = params;
		cal.weekNumbers = params.weekNumbers;
		cal.setRange(params.range[0], params.range[1]);
		cal.setDateStatusHandler(params.dateStatusFunc);
		cal.getDateText = params.dateText;
		if (params.ifFormat) {
			cal.setDateFormat(params.ifFormat);
		}
		if (params.inputField && typeof params.inputField.value == "string") {
			cal.parseDate(params.inputField.value);
		}
		cal.create(params.flat);
		cal.show();
		return false;
	}

	var triggerEl = params.button || params.displayArea || params.inputField;
	triggerEl["on" + params.eventName] = function() {
		var dateEl = params.inputField || params.displayArea;
		var dateFmt = params.inputField ? params.ifFormat : params.daFormat;
		var mustCreate = false;
		var cal = window.calendar;
		if (dateEl)
			params.date = Date.parseDate(dateEl.value || dateEl.innerHTML, dateFmt);
		if (!(cal && params.cache)) {
			window.calendar = cal = new Calendar(params.firstDay,
							     params.date,
							     params.onSelect || onSelect,
							     params.onClose || function(cal) { cal.hide(); });
			cal.showsTime = params.showsTime;
			cal.time24 = (params.timeFormat == "24");
			cal.weekNumbers = params.weekNumbers;
			mustCreate = true;
		} else {
			if (params.date)
				cal.setDate(params.date);
			cal.hide();
		}
		if (params.multiple) {
			cal.multiple = {};
			for (var i = params.multiple.length; --i >= 0;) {
				var d = params.multiple[i];
				var ds = d.print("%Y%m%d");
				cal.multiple[ds] = d;
			}
		}
		cal.showsOtherMonths = params.showOthers;
		cal.yearStep = params.step;
		cal.setRange(params.range[0], params.range[1]);
		cal.params = params;
		cal.setDateStatusHandler(params.dateStatusFunc);
		cal.getDateText = params.dateText;
		cal.setDateFormat(dateFmt);
		if (mustCreate)
			cal.create();
		cal.refresh();
		if (!params.position)
			cal.showAtElement(params.button || params.displayArea || params.inputField, params.align);
		else
			cal.showAt(params.position[0], params.position[1]);
		return false;
	};

	return cal;
};

/*
 * 
 * TableSorter 2.0 - Client-side table sorting with ease!
 * Version 2.0.3
 * @requires jQuery v1.2.3
 * 
 * Copyright (c) 2007 Christian Bach
 * Examples and docs at: http://tablesorter.com
 * Dual licensed under the MIT and GPL licenses:
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.gnu.org/licenses/gpl.html
 * 
 */
/**
 *
 * @description Create a sortable table with multi-column sorting capabilitys
 * 
 * @example $('table').tablesorter();
 * @desc Create a simple tablesorter interface.
 *
 * @example $('table').tablesorter({ sortList:[[0,0],[1,0]] });
 * @desc Create a tablesorter interface and sort on the first and secound column in ascending order.
 * 
 * @example $('table').tablesorter({ headers: { 0: { sorter: false}, 1: {sorter: false} } });
 * @desc Create a tablesorter interface and disableing the first and secound column headers.
 * 
 * @example $('table').tablesorter({ 0: {sorter:"integer"}, 1: {sorter:"currency"} });
 * @desc Create a tablesorter interface and set a column parser for the first and secound column.
 * 
 * 
 * @param Object settings An object literal containing key/value pairs to provide optional settings.
 * 
 * @option String cssHeader (optional) 			A string of the class name to be appended to sortable tr elements in the thead of the table. 
 * 												Default value: "header"
 * 
 * @option String cssAsc (optional) 			A string of the class name to be appended to sortable tr elements in the thead on a ascending sort. 
 * 												Default value: "headerSortUp"
 * 
 * @option String cssDesc (optional) 			A string of the class name to be appended to sortable tr elements in the thead on a descending sort. 
 * 												Default value: "headerSortDown"
 * 
 * @option String sortInitialOrder (optional) 	A string of the inital sorting order can be asc or desc. 
 * 												Default value: "asc"
 * 
 * @option String sortMultisortKey (optional) 	A string of the multi-column sort key. 
 * 												Default value: "shiftKey"
 * 
 * @option String textExtraction (optional) 	A string of the text-extraction method to use. 
 * 												For complex html structures inside td cell set this option to "complex", 
 * 												on large tables the complex option can be slow. 
 * 												Default value: "simple"
 * 
 * @option Object headers (optional) 			An array containing the forces sorting rules. 
 * 												This option let's you specify a default sorting rule. 
 * 												Default value: null
 * 
 * @option Array sortList (optional) 			An array containing the forces sorting rules. 
 * 												This option let's you specify a default sorting rule. 
 * 												Default value: null
 * 
 * @option Array sortForce (optional) 			An array containing forced sorting rules. 
 * 												This option let's you specify a default sorting rule, which is prepended to user-selected rules.
 * 												Default value: null
 *  
  * @option Array sortAppend (optional) 			An array containing forced sorting rules. 
 * 												This option let's you specify a default sorting rule, which is appended to user-selected rules.
 * 												Default value: null
 * 
 * @option Boolean widthFixed (optional) 		Boolean flag indicating if tablesorter should apply fixed widths to the table columns.
 * 												This is usefull when using the pager companion plugin.
 * 												This options requires the dimension jquery plugin.
 * 												Default value: false
 *
 * @option Boolean cancelSelection (optional) 	Boolean flag indicating if tablesorter should cancel selection of the table headers text.
 * 												Default value: true
 *
 * @option Boolean debug (optional) 			Boolean flag indicating if tablesorter should display debuging information usefull for development.
 *
 * @type jQuery
 *
 * @name tablesorter
 * 
 * @cat Plugins/Tablesorter
 * 
 * @author Christian Bach/christian.bach@polyester.se
 */

(function($) {
	$.extend({
		tablesorter: new function() {
			
			var parsers = [], widgets = [];
			
			this.defaults = {
				cssHeader: "header",
				cssAsc: "headerSortUp",
				cssDesc: "headerSortDown",
				sortInitialOrder: "asc",
				sortMultiSortKey: "shiftKey",
				sortForce: null,
				sortAppend: null,
				textExtraction: "simple",
				parsers: {}, 
				widgets: [],		
				widgetZebra: {css: ["even","odd"]},
				headers: {},
				widthFixed: false,
				cancelSelection: true,
				sortList: [],
				headerList: [],
				dateFormat: "us",
				decimal: '.',
				debug: false
			};
			
			/* debuging utils */
			function benchmark(s,d) {
				log(s + "," + (new Date().getTime() - d.getTime()) + "ms");
			}
			
			this.benchmark = benchmark;
			
			function log(s) {
				if (typeof console != "undefined" && typeof console.debug != "undefined") {
					console.log(s);
				} else {
					alert(s);
				}
			}
						
			/* parsers utils */
			function buildParserCache(table,$headers) {
				
				if(table.config.debug) { var parsersDebug = ""; }
				
				var rows = table.tBodies[0].rows;
				
				if(table.tBodies[0].rows[0]) {

					var list = [], cells = rows[0].cells, l = cells.length;
					
					for (var i=0;i < l; i++) {
						var p = false;
						if($.metadata && ($($headers[i]).metadata() && $($headers[i]).metadata().sorter)  ) {
						
							p = getParserById($($headers[i]).metadata().sorter);	

						} else if((table.config.headers[i] && table.config.headers[i].sorter)) {
	
							p = getParserById(table.config.headers[i].sorter);
						}
						if(!p) {
							p = detectParserForColumn(table,cells[i]);
						}
	
						if(table.config.debug) { parsersDebug += "column:" + i + " parser:" +p.id + "\n"; }

						list.push(p);
					}
				}
				
				if(table.config.debug) { log(parsersDebug); }

				return list;
			};
			
			function detectParserForColumn(table,node) {
				var l = parsers.length;
				for(var i=1; i < l; i++) {
					if(parsers[i].is($.trim(getElementText(table.config,node)),table,node)) {
						return parsers[i];
					}
				}
				// 0 is always the generic parser (text)
				return parsers[0];
			}
			
			function getParserById(name) {
				var l = parsers.length;
				for(var i=0; i < l; i++) {
					if(parsers[i].id.toLowerCase() == name.toLowerCase()) {	
						return parsers[i];
					}
				}
				return false;
			}
			
			/* utils */
			function buildCache(table) {
				
				if(table.config.debug) { var cacheTime = new Date(); }
				
				
				var totalRows = (table.tBodies[0] && table.tBodies[0].rows.length) || 0,
					totalCells = (table.tBodies[0].rows[0] && table.tBodies[0].rows[0].cells.length) || 0,
					parsers = table.config.parsers, 
					cache = {row: [], normalized: []};
				
					for (var i=0;i < totalRows; ++i) {
					
						/** Add the table data to main data array */
						var c = table.tBodies[0].rows[i], cols = [];
					
						cache.row.push($(c));
						
						for(var j=0; j < totalCells; ++j) {
							cols.push(parsers[j].format(getElementText(table.config,c.cells[j]),table,c.cells[j]));	
						}
												
						cols.push(i); // add position for rowCache
						cache.normalized.push(cols);
						cols = null;
					};
				
				if(table.config.debug) { benchmark("Building cache for " + totalRows + " rows:", cacheTime); }
				return cache;
			};
			
			function getElementText(config,node) {
				
				if(!node) return "";
								
				var t = "";
				
				if(config.textExtraction == "simple") {
					if(node.childNodes[0] && node.childNodes[0].hasChildNodes()) {
						t = node.childNodes[0].innerHTML;
					} else {
						t = node.innerHTML;
					}
				} else {
					if(typeof(config.textExtraction) == "function") {
						t = config.textExtraction(node);
					} else { 
						t = $(node).text();
					}	
				}
				return t;
			}
			
			function appendToTable(table,cache) {
				
				if(table.config.debug) {var appendTime = new Date()}
				
				var c = cache, 
					r = c.row, 
					n= c.normalized, 
					totalRows = n.length, 
					checkCell = (n[0].length-1), 
					tableBody = $(table.tBodies[0]),
					rows = [];
				
				for (var i=0;i < totalRows; i++) {
					rows.push(r[n[i][checkCell]]);	
					if(!table.config.appender) {
						
						var o = r[n[i][checkCell]];
						var l = o.length;
						for(var j=0; j < l; j++) {
							
							tableBody[0].appendChild(o[j]);
						
						}
						
						//tableBody.append(r[n[i][checkCell]]);
					}
				}	
				
				if(table.config.appender) {
				
					table.config.appender(table,rows);	
				}
				
				rows = null;
				
				if(table.config.debug) { benchmark("Rebuilt table:", appendTime); }
								
				//apply table widgets
				applyWidget(table);
				
				// trigger sortend
				setTimeout(function() {
					$(table).trigger("sortEnd");	
				},0);
				
			};
			
			function buildHeaders(table) {
				
				if(table.config.debug) { var time = new Date(); }
				
				var meta = ($.metadata) ? true : false, tableHeadersRows = [];
			
				for(var i = 0; i < table.tHead.rows.length; i++) { tableHeadersRows[i]=0; };
				
				$tableHeaders = $("thead th",table);
		
				$tableHeaders.each(function(index) {
							
					this.count = 0;
					this.column = index;
					this.order = formatSortingOrder(table.config.sortInitialOrder);

					if(checkHeaderMetadata(this) || checkHeaderOptions(table,index)) this.sortDisabled = true;
					if(!this.sortDisabled) {
						$(this).addClass(table.config.cssHeader);
					}
					
					// add cell to headerList
					table.config.headerList[index]= this;
				});
				
				if(table.config.debug) { benchmark("Built headers:", time); log($tableHeaders); }
				
				return $tableHeaders;
				
			};
						
		   	function checkCellColSpan(table, rows, row) {
                var arr = [], r = table.tHead.rows, c = r[row].cells;
				
				for(var i=0; i < c.length; i++) {
					var cell = c[i];
					
					if ( cell.colSpan > 1) { 
						arr = arr.concat(checkCellColSpan(table, headerArr,row++));
					} else  {
						if(table.tHead.length == 1 || (cell.rowSpan > 1 || !r[row+1])) {
							arr.push(cell);
						}
						//headerArr[row] = (i+row);
					}
				}
				return arr;
			};
			
			function checkHeaderMetadata(cell) {
				if(($.metadata) && ($(cell).metadata().sorter === false)) { return true; };
				return false;
			}
			
			function checkHeaderOptions(table,i) {	
				if((table.config.headers[i]) && (table.config.headers[i].sorter === false)) { return true; };
				return false;
			}
			
			function applyWidget(table) {
				var c = table.config.widgets;
				var l = c.length;
				for(var i=0; i < l; i++) {
					
					getWidgetById(c[i]).format(table);
				}
				
			}
			
			function getWidgetById(name) {
				var l = widgets.length;
				for(var i=0; i < l; i++) {
					if(widgets[i].id.toLowerCase() == name.toLowerCase() ) {
						return widgets[i]; 
					}
				}
			};
			
			function formatSortingOrder(v) {
				
				if(typeof(v) != "Number") {
					i = (v.toLowerCase() == "desc") ? 1 : 0;
				} else {
					i = (v == (0 || 1)) ? v : 0;
				}
				return i;
			}
			
			function isValueInArray(v, a) {
				var l = a.length;
				for(var i=0; i < l; i++) {
					if(a[i][0] == v) {
						return true;	
					}
				}
				return false;
			}
				
			function setHeadersCss(table,$headers, list, css) {
				// remove all header information
				$headers.removeClass(css[0]).removeClass(css[1]);
				
				var h = [];
				$headers.each(function(offset) {
						if(!this.sortDisabled) {
							h[this.column] = $(this);					
						}
				});
				
				var l = list.length; 
				for(var i=0; i < l; i++) {
					h[list[i][0]].addClass(css[list[i][1]]);
				}
			}
			
			function fixColumnWidth(table,$headers) {
				var c = table.config;
				if(c.widthFixed) {
					var colgroup = $('<colgroup>');
					$("tr:first td",table.tBodies[0]).each(function() {
						colgroup.append($('<col>').css('width',$(this).width()));
					});
					$(table).prepend(colgroup);
				};
			}
			
			function updateHeaderSortCount(table,sortList) {
				var c = table.config, l = sortList.length;
				for(var i=0; i < l; i++) {
					var s = sortList[i], o = c.headerList[s[0]];
					o.count = s[1];
					o.count++;
				}
			}
			
			/* sorting methods */
			function multisort(table,sortList,cache) {
				
				if(table.config.debug) { var sortTime = new Date(); }
				
				var dynamicExp = "var sortWrapper = function(a,b) {", l = sortList.length;
					
				for(var i=0; i < l; i++) {
					
					var c = sortList[i][0];
					var order = sortList[i][1];
					var s = (getCachedSortType(table.config.parsers,c) == "text") ? ((order == 0) ? "sortText" : "sortTextDesc") : ((order == 0) ? "sortNumeric" : "sortNumericDesc");
					var e = "e" + i;
					
					dynamicExp += "var " + e + " = " + s + "(a[" + c + "],b[" + c + "]); ";
					dynamicExp += "if(" + e + ") { return " + e + "; } ";
					dynamicExp += "else { ";
				}
				
				// if value is the same keep orignal order	
				var orgOrderCol = cache.normalized[0].length - 1;
				dynamicExp += "return a[" + orgOrderCol + "]-b[" + orgOrderCol + "];";
						
				for(var i=0; i < l; i++) {
					dynamicExp += "}; ";
				}
				
				dynamicExp += "return 0; ";	
				dynamicExp += "}; ";	
				
				eval(dynamicExp);
				
				cache.normalized.sort(sortWrapper);
				
				if(table.config.debug) { benchmark("Sorting on " + sortList.toString() + " and dir " + order+ " time:", sortTime); }
				
				return cache;
			};
			
			function sortText(a,b) {
				return ((a < b) ? -1 : ((a > b) ? 1 : 0));
			};
			
			function sortTextDesc(a,b) {
				return ((b < a) ? -1 : ((b > a) ? 1 : 0));
			};	
			
	 		function sortNumeric(a,b) {
				return a-b;
			};
			
			function sortNumericDesc(a,b) {
				return b-a;
			};
			
			function getCachedSortType(parsers,i) {
				return parsers[i].type;
			};
			
			/* public methods */
			this.construct = function(settings) {

				return this.each(function() {
					
					if(!this.tHead || !this.tBodies) return;
					
					var $this, $document,$headers, cache, config, shiftDown = 0, sortOrder;
					
					this.config = {};
					
					config = $.extend(this.config, $.tablesorter.defaults, settings);
					
					// store common expression for speed					
					$this = $(this);
					
					// build headers
					$headers = buildHeaders(this);
					
					// try to auto detect column type, and store in tables config
					this.config.parsers = buildParserCache(this,$headers);
					
					// build the cache for the tbody cells
					cache = buildCache(this);
					
					// get the css class names, could be done else where.
					var sortCSS = [config.cssDesc,config.cssAsc];
					
					// fixate columns if the users supplies the fixedWidth option
					fixColumnWidth(this);
					
					// apply event handling to headers
					// this is to big, perhaps break it out?
					$headers.click(function(e) {
						
						$this.trigger("sortStart");
						
						var totalRows = ($this[0].tBodies[0] && $this[0].tBodies[0].rows.length) || 0;
						
						if(!this.sortDisabled && totalRows > 0) {
							
							
							// store exp, for speed
							var $cell = $(this);
	
							// get current column index
							var i = this.column;
							
							// get current column sort order
							this.order = this.count++ % 2;
							
							// user only whants to sort on one column
							if(!e[config.sortMultiSortKey]) {
								
								// flush the sort list
								config.sortList = [];
								
								if(config.sortForce != null) {
									var a = config.sortForce; 
									for(var j=0; j < a.length; j++) {
										if(a[j][0] != i) {
											config.sortList.push(a[j]);
										}
									}
								}
								
								// add column to sort list
								config.sortList.push([i,this.order]);
							
							// multi column sorting
							} else {
								// the user has clicked on an all ready sortet column.
								if(isValueInArray(i,config.sortList)) {	 
									
									// revers the sorting direction for all tables.
									for(var j=0; j < config.sortList.length; j++) {
										var s = config.sortList[j], o = config.headerList[s[0]];
										if(s[0] == i) {
											o.count = s[1];
											o.count++;
											s[1] = o.count % 2;
										}
									}	
								} else {
									// add column to sort list array
									config.sortList.push([i,this.order]);
								}
							};
							setTimeout(function() {
								//set css for headers
								setHeadersCss($this[0],$headers,config.sortList,sortCSS);
								appendToTable($this[0],multisort($this[0],config.sortList,cache));
							},1);
							// stop normal event by returning false
							return false;
						}
					// cancel selection	
					}).mousedown(function() {
						if(config.cancelSelection) {
							this.onselectstart = function() {return false};
							return false;
						}
					});
					
					// apply easy methods that trigger binded events
					$this.bind("update",function() {
						
						// rebuild parsers.
						this.config.parsers = buildParserCache(this,$headers);
						
						// rebuild the cache map
						cache = buildCache(this);
						
					}).bind("sorton",function(e,list) {
						
						$(this).trigger("sortStart");
						
						config.sortList = list;
						
						// update and store the sortlist
						var sortList = config.sortList;
						
						// update header count index
						updateHeaderSortCount(this,sortList);
						
						//set css for headers
						setHeadersCss(this,$headers,sortList,sortCSS);
						
						
						// sort the table and append it to the dom
						appendToTable(this,multisort(this,sortList,cache));

					}).bind("appendCache",function() {
						
						appendToTable(this,cache);
					
					}).bind("applyWidgetId",function(e,id) {
						
						getWidgetById(id).format(this);
						
					}).bind("applyWidgets",function() {
						// apply widgets
						applyWidget(this);
					});
					
					if($.metadata && ($(this).metadata() && $(this).metadata().sortlist)) {
						config.sortList = $(this).metadata().sortlist;
					}
					// if user has supplied a sort list to constructor.
					if(config.sortList.length > 0) {
						$this.trigger("sorton",[config.sortList]);	
					}
					
					// apply widgets
					applyWidget(this);
				});
			};
			
			this.addParser = function(parser) {
				var l = parsers.length, a = true;
				for(var i=0; i < l; i++) {
					if(parsers[i].id.toLowerCase() == parser.id.toLowerCase()) {
						a = false;
					}
				}
				if(a) { parsers.push(parser); };
			};
			
			this.addWidget = function(widget) {
				widgets.push(widget);
			};
			
			this.formatFloat = function(s) {
				var i = parseFloat(s);
				return (isNaN(i)) ? 0 : i;
			};
			this.formatInt = function(s) {
				var i = parseInt(s);
				return (isNaN(i)) ? 0 : i;
			};
			
			this.isDigit = function(s,config) {
				var DECIMAL = '\\' + config.decimal;
				var exp = '/(^[+]?0(' + DECIMAL +'0+)?$)|(^([-+]?[1-9][0-9]*)$)|(^([-+]?((0?|[1-9][0-9]*)' + DECIMAL +'(0*[1-9][0-9]*)))$)|(^[-+]?[1-9]+[0-9]*' + DECIMAL +'0+$)/';
				return RegExp(exp).test($.trim(s));
			};
			
			this.clearTableBody = function(table) {
				if($.browser.msie) {
					function empty() {
						while ( this.firstChild ) this.removeChild( this.firstChild );
					}
					empty.apply(table.tBodies[0]);
				} else {
					table.tBodies[0].innerHTML = "";
				}
			};
		}
	});
	
	// extend plugin scope
	$.fn.extend({
        tablesorter: $.tablesorter.construct
	});
	
	var ts = $.tablesorter;
	
	// add default parsers
	ts.addParser({
		id: "text",
		is: function(s) {
			return true;
		},
		format: function(s) {
			return $.trim(s.toLowerCase());
		},
		type: "text"
	});
	
	ts.addParser({
		id: "digit",
		is: function(s,table) {
			var c = table.config;
			return $.tablesorter.isDigit(s,c);
		},
		format: function(s) {
			return $.tablesorter.formatFloat(s);
		},
		type: "numeric"
	});
	
	ts.addParser({
		id: "currency",
		is: function(s) {
			return /^[Â£$â¬?.]/.test(s);
		},
		format: function(s) {
			return $.tablesorter.formatFloat(s.replace(new RegExp(/[^0-9.]/g),""));
		},
		type: "numeric"
	});
	
	ts.addParser({
		id: "ipAddress",
		is: function(s) {
			return /^\d{2,3}[\.]\d{2,3}[\.]\d{2,3}[\.]\d{2,3}$/.test(s);
		},
		format: function(s) {
			var a = s.split("."), r = "", l = a.length;
			for(var i = 0; i < l; i++) {
				var item = a[i];
			   	if(item.length == 2) {
					r += "0" + item;
			   	} else {
					r += item;
			   	}
			}
			return $.tablesorter.formatFloat(r);
		},
		type: "numeric"
	});
	
	ts.addParser({
		id: "url",
		is: function(s) {
			return /^(https?|ftp|file):\/\/$/.test(s);
		},
		format: function(s) {
			return jQuery.trim(s.replace(new RegExp(/(https?|ftp|file):\/\//),''));
		},
		type: "text"
	});
	
	ts.addParser({
		id: "isoDate",
		is: function(s) {
			return /^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(s);
		},
		format: function(s) {
			return $.tablesorter.formatFloat((s != "") ? new Date(s.replace(new RegExp(/-/g),"/")).getTime() : "0");
		},
		type: "numeric"
	});
		
	ts.addParser({
		id: "percent",
		is: function(s) { 
			return /\%$/.test($.trim(s));
		},
		format: function(s) {
			return $.tablesorter.formatFloat(s.replace(new RegExp(/%/g),""));
		},
		type: "numeric"
	});

	ts.addParser({
		id: "usLongDate",
		is: function(s) {
			return s.match(new RegExp(/^[A-Za-z]{3,10}\.? [0-9]{1,2}, ([0-9]{4}|'?[0-9]{2}) (([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(AM|PM)))$/));
		},
		format: function(s) {
			return $.tablesorter.formatFloat(new Date(s).getTime());
		},
		type: "numeric"
	});

	ts.addParser({
		id: "shortDate",
		is: function(s) {
			return /\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4}/.test(s);
		},
		format: function(s,table) {
			var c = table.config;
			s = s.replace(/\-/g,"/");
			if(c.dateFormat == "us") {
				// reformat the string in ISO format
				s = s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/, "$3/$1/$2");
			} else if(c.dateFormat == "uk") {
				//reformat the string in ISO format
				s = s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/, "$3/$2/$1");
			} else if(c.dateFormat == "dd/mm/yy" || c.dateFormat == "dd-mm-yy") {
				s = s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{2})/, "$1/$2/$3");	
			}
			return $.tablesorter.formatFloat(new Date(s).getTime());
		},
		type: "numeric"
	});

	ts.addParser({
	    id: "time",
	    is: function(s) {
	        return /^(([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(am|pm)))$/.test(s);
	    },
	    format: function(s) {
	        return $.tablesorter.formatFloat(new Date("2000/01/01 " + s).getTime());
	    },
	  type: "numeric"
	});
	
	
	ts.addParser({
	    id: "metadata",
	    is: function(s) {
	        return false;
	    },
	    format: function(s,table,cell) {
			var c = table.config, p = (!c.parserMetadataName) ? 'sortValue' : c.parserMetadataName;
	        return $(cell).metadata()[p];
	    },
	  type: "numeric"
	});
	
	// add default widgets
	ts.addWidget({
		id: "zebra",
		format: function(table) {
			if(table.config.debug) { var time = new Date(); }
			$("tr:visible",table.tBodies[0])
	        .filter(':even')
	        .removeClass(table.config.widgetZebra.css[1]).addClass(table.config.widgetZebra.css[0])
	        .end().filter(':odd')
	        .removeClass(table.config.widgetZebra.css[0]).addClass(table.config.widgetZebra.css[1]);
			if(table.config.debug) { $.tablesorter.benchmark("Applying Zebra widget", time); }
		}
	});	
})(jQuery);

/*
 * Metadata - jQuery plugin for parsing metadata from elements
 *
 * Copyright (c) 2006 John Resig, Yehuda Katz, Jï¿½Ã¶rn Zaefferer, Paul McLanahan
 *
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 *
 * Revision: $Id: jquery.metadata.js 4187 2007-12-16 17:15:27Z joern.zaefferer $
 *
 */

/**
 * Sets the type of metadata to use. Metadata is encoded in JSON, and each property
 * in the JSON will become a property of the element itself.
 *
 * There are three supported types of metadata storage:
 *
 *   attr:  Inside an attribute. The name parameter indicates *which* attribute.
 *          
 *   class: Inside the class attribute, wrapped in curly braces: { }
 *   
 *   elem:  Inside a child element (e.g. a script tag). The
 *          name parameter indicates *which* element.
 *          
 * The metadata for an element is loaded the first time the element is accessed via jQuery.
 *
 * As a result, you can define the metadata type, use $(expr) to load the metadata into the elements
 * matched by expr, then redefine the metadata type and run another $(expr) for other elements.
 * 
 * @name $.metadata.setType
 *
 * @example <p id="one" class="some_class {item_id: 1, item_label: 'Label'}">This is a p</p>
 * @before $.metadata.setType("class")
 * @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label"
 * @desc Reads metadata from the class attribute
 * 
 * @example <p id="one" class="some_class" data="{item_id: 1, item_label: 'Label'}">This is a p</p>
 * @before $.metadata.setType("attr", "data")
 * @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label"
 * @desc Reads metadata from a "data" attribute
 * 
 * @example <p id="one" class="some_class"><script>{item_id: 1, item_label: 'Label'}</script>This is a p</p>
 * @before $.metadata.setType("elem", "script")
 * @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label"
 * @desc Reads metadata from a nested script element
 * 
 * @param String type The encoding type
 * @param String name The name of the attribute to be used to get metadata (optional)
 * @cat Plugins/Metadata
 * @descr Sets the type of encoding to be used when loading metadata for the first time
 * @type undefined
 * @see metadata()
 */

(function($) {

$.extend({
	metadata : {
		defaults : {
			type: 'class',
			name: 'metadata',
			cre: /({.*})/,
			single: 'metadata'
		},
		setType: function( type, name ){
			this.defaults.type = type;
			this.defaults.name = name;
		},
		get: function( elem, opts ){

			var settings = $.extend({},this.defaults,opts);
			// check for empty string in single property
			if ( !settings.single.length ) settings.single = 'metadata';
			
			var data = $.data(elem, settings.single);
			// returned cached data if it already exists
			if ( data ) return data;

			data = "{}";

			if ( settings.type == "class" ) {
				var m = settings.cre.exec( elem.className );
				if ( m )
					data = m[1];
			} else if ( settings.type == "elem" ) {
				if( !elem.getElementsByTagName )
					return undefined;
				var e = elem.getElementsByTagName(settings.name);
				if ( e.length )
					data = $.trim(e[0].innerHTML);
			} else if ( elem.getAttribute != undefined ) {
				var attr = elem.getAttribute( settings.name );
				if ( attr )
					data = attr;
			}
			
			if ( data.indexOf( '{' ) <0 )
			    data = "{" + data + "}";
			
			data = eval("(" + data + ")");
			
			$.data( elem, settings.single, data );
			return data;
		}
	}
});

/**
 * Returns the metadata object for the first member of the jQuery object.
 *
 * @name metadata
 * @descr Returns element's metadata object
 * @param Object opts An object contianing settings to override the defaults
 * @type jQuery
 * @cat Plugins/Metadata
 */
$.fn.metadata = function( opts ){
	return $.metadata.get( this[0], opts );
};

})(jQuery);

/*!
 * jQuery Taconite plugin - A port of the Taconite framework by Ryan Asleson and
 *     Nathaniel T. Schutta: http://taconite.sourceforge.net/
 *
 * Examples and documentation at: http://malsup.com/jquery/taconite/
 * Copyright (c) 2007-2011 M. Alsup
 * Dual licensed under the MIT and GPL licenses:
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.gnu.org/licenses/gpl.html
 * Thanks to Kenton Simpson for contributing many good ideas!
 *
 * @version: 3.64  16-JUN-2011
 * @requires jQuery v1.3.2 or later
 */

(function($) {
var version = '3.64';

$.taconite = function(xml) {
    processDoc(xml);
};

$.taconite.debug = 0;  // set to true to enable debug logging to window.console.log
$.taconite.autodetect = true;
$.taconite.defaults = {
    cdataWrap: 'div'
};

// add 'replace' and 'replaceContent' plugins (conditionally)
$.fn.replace = $.fn.replace || function(a) {
    this.after(a);
    return this.remove();
};
$.fn.replaceContent = $.fn.replaceContent || function(a) {
    return this.empty().append(a);
};

$.expr[':'].taconiteTag = function(a) {
    return a.taconiteTag === 1;
};

// allow auto-detection to be enabled/disabled on-demand
$.taconite.enableAutoDetection = function(b) {
    $.taconite.autodetect = b;
    if (origHttpData)
        $.httpData = b ? origHttpData : detect;
};

var logCount = 0;
function log() {
    if (!$.taconite.debug || !window.console || !window.console.log) return;
    !logCount++ && log('Plugin Version: ' + version);
    window.console.log('[taconite] ' + [].join.call(arguments,''));
}

var parseJSON = $.parseJSON || function(s) {
    return window['eval']('(' + s + ')');
};

function httpData( xhr, type, s ) {
    var ct = xhr.getResponseHeader('content-type') || '',
        xml = type === 'xml' || !type && ct.indexOf('xml') >= 0,
        data = xml ? xhr.responseXML : xhr.responseText;

    if (xml && data.documentElement.nodeName === 'parsererror') {
        $.error && $.error('parsererror');
    }
    if (s && s.dataFilter) {
        data = s.dataFilter(data, type);
    }
    if (typeof data === 'string') {
        if (type === 'json' || !type && ct.indexOf('json') >= 0) {
            data = parseJSON(data);
        } else if (type === "script" || !type && ct.indexOf("javascript") >= 0) {
            $.globalEval(data);
        }
    }
    return data;
}

function getResponse(xhr, type, s) {
    if (origHttpData)
        return origHttpData(xhr, type, s);
    return xhr.responseXML || xhr.responseText;
}

function detect(xhr, type, s) {
    var ct = xhr.getResponseHeader('content-type');
    if ($.taconite.debug) {
        log('[AJAX response] content-type: ', ct, ';  status: ', xhr.status, ' ', xhr.statusText, ';  has responseXML: ', xhr.responseXML != null);
        log('type arg: ' + type);
//        log('responseXML: ' + xhr.responseXML);  // IE9 doesn't like xhr.toString()
    }
    var data = getResponse(xhr, type, s);
    if (data && data.documentElement && data.documentElement.nodeName != 'parsererror') {
        $.taconite(data);
    }
    else if (typeof data == 'string') {
        // issue #4 (don't try to parse plain text or html responses
        if ( /taconite/.test(data) )
            $.taconite(data);
    }
    else {
        log('jQuery core httpData returned: ' + data);
        log('httpData: response is not XML (or not "valid" XML)');
    }
    return data;
}

// 1.5+ hook
$.ajaxPrefilter && $.ajaxPrefilter(function( options, originalOptions, jqXHR ) {
    jqXHR.success(function( data, status, jqXHR ) {
        if ($.taconite.autodetect)
            detect(jqXHR, options.dataType, options);
    });
});

// < 1.5 hook
var origHttpData = $.httpData;
if ($.httpData)
    $.httpData = detect;  // replace jQuery's httpData method

// custom data parsers
var parsers = { 'json': jsonParser }, rawData, rawDataIndic;

$.taconite.registerParser = function(type, fn) {
    parsers[type] = fn;
};

function parseRawData(type, data) {
    var d = data, parser = parsers[type];
    if ($.isFunction(parser))
        return parser(data);
    else
        throw 'No parser registered for rawData of type "' + type + '"';
}

function jsonParser(json) {
    return parseJSON(json);
}


function processDoc(xml) {
    var status = true, ex;
    try {
        if (typeof xml == 'string')
            xml = convert(xml);
        if (! ( xml && xml.documentElement) ) {
            log('$.taconite invoked without valid document; nothing to process');
            return false;
        }

        var root = xml.documentElement.tagName;
        log('XML document root: ', root);

        var taconiteDoc = $('taconite', xml)[0];

        if (!taconiteDoc) {
            log('document does not contain <taconite> element; nothing to process');
            return false;
        }

        $.event.trigger('taconite-begin-notify', [taconiteDoc]);
        status = go(taconiteDoc);
    } catch(e) {
        status = ex = e;
    }
    rawDataIndic && $.event.trigger('taconite-rawdata-notify', [rawData]);
    $.event.trigger('taconite-complete-notify', [xml, !!status, status === true ? null : status]);
    if (ex)
        throw ex;
}

// convert string to xml document
function convert(s) {
    var doc;
    log('attempting string to document conversion');
    try {
        if (window.DOMParser) {
            var parser = new DOMParser();
            doc = parser.parseFromString(s, 'text/xml');
        }
        else {
            doc = $("<xml>")[0];
            doc.async = 'false';
            doc.loadXML(s);
        }
    }
    catch(e) {
        if (window.console && window.console.error)
            window.console.error('[taconite] ERROR parsing XML string for conversion: ' + e);
        throw e;
    }
    var ok = doc && doc.documentElement && doc.documentElement.tagName != 'parsererror';
    log('conversion ', ok ? 'successful!' : 'FAILED');
    return doc;
}

function go(xml) {
    try {
        var t = new Date().getTime();
        // process the document
        process(xml.childNodes);
        $.taconite.lastTime = (new Date().getTime()) - t;
        log('time to process response: ' + $.taconite.lastTime + 'ms');
    } catch(e) {
        if (window.console && window.console.error)
            window.console.error('[taconite] ERROR processing document: ' + e);
        throw e;
    }
    return true;
}

// process the taconite commands
function process(commands) {
    rawData = {};
    rawDataIndic = false;
    var trimHash = { wrap: 1 };
    var doPostProcess = 0;
    var a, n, v, i, j, js, els, raw, type, q, jq, cdataWrap;

    for(i=0; i < commands.length; i++) {
        if (commands[i].nodeType != 1)
            continue; // commands are elements
        var cmdNode = commands[i], cmd = cmdNode.tagName;
        if (cmd == 'eval') {
            js = (cmdNode.firstChild ? cmdNode.firstChild.nodeValue : null);
            log('invoking "eval" command: ', js);
            if (js)
                $.globalEval(js);
            continue;
        }
        if (cmd == 'rawData') {
            raw = (cmdNode.firstChild ? cmdNode.firstChild.nodeValue : null);
            type = cmdNode.getAttribute('type');
            log('rawData ('+type+'): ', raw);

            var namespace = cmdNode.getAttribute('namespace') || 'none';

            !rawData[namespace] && (rawData[namespace] = []);

            rawData[namespace].push({
                data: parseRawData(type, raw),
                type: type,
                name: cmdNode.getAttribute('name') || null,
                raw: raw
            });
            !rawDataIndic && (rawDataIndic = true);
            continue;
        }
        q = cmdNode.getAttribute('select');
        jq = $(q);
        if (!jq[0]) {
            log('No matching targets for selector: ', q);
            continue;
        }
        cdataWrap = cmdNode.getAttribute('cdataWrap') || $.taconite.defaults.cdataWrap;

        a = [];
        if (cmdNode.childNodes.length > 0) {
            doPostProcess = 1;
            for (j=0,els=[]; j < cmdNode.childNodes.length; j++)
                els[j] = createNode(cmdNode.childNodes[j], cdataWrap);
            a.push(trimHash[cmd] ? cleanse(els) : els);
        }

        // remain backward compat with pre 2.0.9 versions
        n = cmdNode.getAttribute('name');
        v = cmdNode.getAttribute('value');
        if (n !== null) a.push(n);
        if (v !== null) a.push(v);

        // @since: 2.0.9: support arg1, arg2, arg3...
        for (var j=1; true; j++) {
            v = cmdNode.getAttribute('arg'+j);
            if (v === null)
                break;
            // support numeric primitives
            if (v.length) {
                var n = Number(v);
                if (v == n)
                    v = n;
            }
            a.push(v);
        }

        $.taconite.debug && logCommand(q, cmd, a, els);
        jq[cmd].apply(jq,a);
    }

    // apply dynamic fixes
    doPostProcess && postProcess();
}

function logCommand(q, cmd, a, els) {
    var args = '...';
    if (!els) {
        args = '';
        for (var k=0, val=a[0]; k < a.length, val=a[k]; k++) {
            k > 0 && (args += ',');
            typeof val == 'string' ? (args += ("'" + val + "'")) : (args += val);
        }
    }
    log("invoking command: $('", q, "').", cmd, '('+ args +')');
}

function postProcess() {
    if ($.browser.mozilla) return;
    // post processing fixes go here; currently there is only one:
    // fix1: opera, IE6, Safari/Win don't maintain selected options in all cases (thanks to Karel FuÄÃ­k for this!)
    $('select:taconiteTag').each(function() {
        var sel = this;
        $('option:taconiteTag', this).each(function() {
            this.setAttribute('selected','selected');
            this.taconiteTag = null;
            if (sel.type == 'select-one') {
                var idx = $('option',sel).index(this);
                sel.selectedIndex = idx;
            }
        });
        this.taconiteTag = null;
    });
}

function cleanse(els) {
    for (var i=0, a=[]; i < els.length; i++)
        if (els[i].nodeType == 1) a.push(els[i]);
    return a;
}

function createNode(node, cdataWrap) {
    var type = node.nodeType;
    if (type == 1) return createElement(node, cdataWrap);
    if (type == 3) return fixTextNode(node.nodeValue);
    if (type == 4) return handleCDATA(node.nodeValue, cdataWrap);
    return null;
}

function handleCDATA(s, cdataWrap) {
    var el = document.createElement(cdataWrap);
    var $el = $(el)[cdataWrap == 'script' ? 'text' : 'html'](s);
    var $ch = $el.children();

    // remove wrapper node if possible
    if ($ch.size() == 1)
        return $ch[0];
    return el;
}

function fixTextNode(s) {
    if ($.browser.msie) s = s.replace(/\n/g, '\r').replace(/\s+/g, ' ');
    return document.createTextNode(s);
}

function createElement(node, cdataWrap) {
    var e, tag = node.tagName.toLowerCase();
    // some elements in IE need to be created with attrs inline
    if ($.browser.msie && $.browser.version < 9) {
        var type = node.getAttribute('type');
        if (tag == 'table' || type == 'radio' || type == 'checkbox' || tag == 'button' ||
            (tag == 'select' && node.getAttribute('multiple'))) {
            e = document.createElement('<' + tag + ' ' + copyAttrs(null, node, true) + '>');
        }
    }
    if (!e) {
        e = document.createElement(tag);
        // copyAttrs(e, node, tag == 'option' && $.browser.safari);
        copyAttrs(e, node);
    }

    // IE fix; colspan must be explicitly set
    if ($.browser.msie && tag == 'td') {
        var colspan = node.getAttribute('colspan');
        if (colspan) e.colSpan = parseInt(colspan);
    }

    // IE fix; script tag not allowed to have children
    if($.browser.msie && !e.canHaveChildren) {
        if(node.childNodes.length > 0)
            e.text = node.text;
    }
    else {
        for(var i=0, max=node.childNodes.length; i < max; i++) {
            var child = createNode (node.childNodes[i], cdataWrap);
            if(child) e.appendChild(child);
        }
    }
    if (! $.browser.mozilla) {
        if (tag == 'select' || (tag == 'option' && node.getAttribute('selected')))
            e.taconiteTag = 1;
    }
    return e;
}

function copyAttrs(dest, src, inline) {
    for (var i=0, attr=''; i < src.attributes.length; i++) {
        var a = src.attributes[i], n = $.trim(a.name), v = $.trim(a.value);
        if (inline) attr += (n + '="' + v + '" ');
        else if (n == 'style') { // IE workaround
            dest.style.cssText = v;
            dest.setAttribute(n, v);
        }
        else $.attr(dest, n, v);
    }
    return attr;
}

})(jQuery);


/*
 * Jeditable - jQuery in place edit plugin
 *
 * Copyright (c) 2006-2008 Mika Tuupola, Dylan Verheul
 *
 * Licensed under the MIT license:
 *   http://www.opensource.org/licenses/mit-license.php
 *
 * Project home:
 *   http://www.appelsiini.net/projects/jeditable
 *
 * Based on editable by Dylan Verheul <dylan_at_dyve.net>:
 *    http://www.dyve.net/jquery/?editable
 *
 * Revision: $Id: jquery.jeditable.js 372 2008-05-22 19:25:32Z tuupola $
 *
 */

/**
  * Version 1.5.x
  *
  * @name  Jeditable
  * @type  jQuery
  * @param String  target             POST URL or function name to send edited content
  * @param Hash    options            additional options 
  * @param Function options[callback] Function to run after submitting edited content
  * @param String  options[name]      POST parameter name of edited content
  * @param String  options[id]        POST parameter name of edited div id
  * @param Hash    options[submitdata] Extra parameters to send when submitting edited content.
  * @param String  options[type]      text, textarea or select
  * @param Integer options[rows]      number of rows if using textarea
  * @param Integer options[cols]      number of columns if using textarea
  * @param Mixed   options[height]    'auto', 'none' or height in pixels
  * @param Mixed   options[width]     'auto', 'none' or width in pixels 
  * @param String  options[loadurl]   URL to fetch input content before editing
  * @param String  options[loadtype]  Request type for load url. Should be GET or POST.
  * @param String  options[loadtext]  Text to display while loading external content.
  * @param Hash    options[loaddata]  Extra parameters to pass when fetching content before editing.
  * @param String  options[data]      Or content given as paramameter.
  * @param String  options[indicator] indicator html to show when saving
  * @param String  options[tooltip]   optional tooltip text via title attribute
  * @param String  options[event]     jQuery event such as 'click' of 'dblclick'
  * @param String  options[onblur]    'cancel', 'submit', 'ignore' or function

  * @param String  options[ondelete]  function or ignored

  * @param String  options[submit]    submit button value, empty means no button
  * @param String  options[cancel]    cancel button value, empty means no button

  * @param String  options[delete]    delete button value, empty means no button

  * @param String  options[cssclass]  CSS class to apply to input form. 'inherit' to copy from parent.
  * @param String  options[csssubmitclass]  CSS class to apply to input form when submitting the form
  * @param String  options[style]     Style to apply to input form 'inherit' to copy from parent.
  * @param String  options[select]    true or false, when true text is highlighted
  * @param String  options[placeholder] Placeholder text or html to insert when element is empty.
  *             
  */

(function($) {

    $.fn.editable = function(target, options) {
        // -------------------------------------------------------------------
        // Assume the url is an absolute path rather than a file name
        // -------------------------------------------------------------------
        if (target.substr(0, 1) != '/' &&
            window.location.pathname.substr(-1) != '/') {
                target = window.location.pathname + '/' + target ;
        }

        var settings = {
            target     : target,
            name       : 'value',
            id         : 'id',
            type       : 'text',
            width      : 'auto',
            height     : 'auto',
            event      : 'click',
            onblur     : 'cancel',
            ondelete   : 'cancel',

            loadtype   : 'GET',
            loadtext   : 'Loading...',
            placeholder: 'Click to edit',
            csssubmitclass : 'ac_loading',
            // indicator  : '',
            loaddata   : {},
            submitdata : {},
            submitbefore : {},                   // Noel - allow the user code to validate inputs
            afterSubmit : {}
        };
        
        if(options) {
            $.extend(settings, options);
        }
    
        /* setup some functions */
        var plugin   = $.editable.types[settings.type].plugin || function() { };
        var submit   = $.editable.types[settings.type].submit || function() { };
        var buttons  = $.editable.types[settings.type].buttons 
                    || $.editable.types['defaults'].buttons;
        var content  = $.editable.types[settings.type].content 
                    || $.editable.types['defaults'].content;
        var element  = $.editable.types[settings.type].element 
                    || $.editable.types['defaults'].element;
        var reset    = $.editable.types[settings.type].reset 
                    || $.editable.types['defaults'].reset;
        var callback = settings.callback || function() { };

        /* add custom event if it does not exist */
        if  (!$.isFunction($(this)[settings.event])) {
            $.fn[settings.event] = function(fn){
          		return fn ? this.bind(settings.event, fn) : this.trigger(settings.event);
          	}
        }
          
        /* TODO: remove this when form is displayed */
        $(this).attr('title', settings.tooltip);
        
        settings.autowidth  = 'auto' == settings.width;
        settings.autoheight = 'auto' == settings.height;

        return this.each(function() {

            /* save this to self because this changes when scope changes */
            var self = this;  
                   
            /* inlined block elements lose their width and height after first edit */
            /* save them for later use as workaround */
            var savedwidth  = $(self).width();
            var savedheight = $(self).height();
            
            /* if element is empty add something clickable (if requested) */
            if (!$.trim($(this).html())) {
                $(this).html(settings.placeholder);
            }
            
            if (settings.event != 'mouseover') {
                $(this).hover(function () {
                    $(this).addClass('editable') 
                }, function () {
                    $(this).removeClass('editable')
                }
                )
            }            
            
            $(this)[settings.event](function(e) {

                /* prevent throwing an exeption if edit field is clicked again */
                // if (self.editing) {

                
                /* Noel 27/12/2008 : The above doesn't work well, often resulting
                                     in the form html displaying in the edit area.
                                     As a work around, added a check for a visible
                                     form and skip recreating if found. */
                                     
                if (self.editing || $('form', self).length > 0) {
                    return;
                }
                self.editing    = true;
                settings.deleting = false ;

                /* figure out how wide and tall we are, saved width and height */
                /* are workaround for http://dev.jquery.com/ticket/2190 */
                if (0 == $(self).width()) {
                    //$(self).css('visibility', 'hidden');
                    settings.width  = savedwidth;
                    settings.height = savedheight;
                } else {
                    if (settings.width != 'none') {
                        settings.width = 
                            settings.autowidth ? $(self).width()  : settings.width;
                    }
                    if (settings.height != 'none') {
                        settings.height = 
                            settings.autoheight ? $(self).height() : settings.height;
                    }
                }
                //$(this).css('visibility', '');
                
                /* remove placeholder text, replace is here because of IE */
                if ($(this).html().toLowerCase().replace(/;/, '') == 
                    settings.placeholder.toLowerCase().replace(/;/, '')) {
                        $(this).html('');
                }
                                
                self.revert     = $(self).html();
                $(self).html('');

                /* create the form object */
                var form = $('<form/>');
                
                /* apply css or style or both */
                if (settings.cssclass) {
                    if ('inherit' == settings.cssclass) {
                        form.attr('class', $(self).attr('class'));
                    } else {
                        form.attr('class', settings.cssclass);
                    }
                }

                if (settings.style) {
                    if ('inherit' == settings.style) {
                        form.attr('style', $(self).attr('style'));
                        /* IE needs the second line or display wont be inherited */
                        form.css('display', $(self).css('display'));                
                    } else {
                        form.attr('style', settings.style);
                    }
                }

                /* add main input element to form and store it in input */
                var input = element.apply(form, [settings, self]);

                /* set input content via POST, GET, given data or existing value */
                var input_content;
                
                if (settings.loadurl) {
                    var t = setTimeout(function() {
                        input.disabled = true;
                        content.apply(form, [settings.loadtext, settings, self]);
                    }, 100);

                    var loaddata = {};
                    loaddata[settings.id] = self.id;
                    if ($.isFunction(settings.loaddata)) {
                        $.extend(loaddata, settings.loaddata.apply(self, [self.revert, settings]));
                    } else {
                        $.extend(loaddata, settings.loaddata);
                    }
                    $.ajax({
                       type : settings.loadtype,
                       url  : settings.loadurl,
                       data : loaddata,
                       async : false,
                       success: function(result) {
                       	  window.clearTimeout(t);
                       	  input_content = result;
                          input.disabled = false;
                       }
                    });
                } else if (settings.data) {
                    input_content = settings.data;
                    if ($.isFunction(settings.data)) {
                        input_content = settings.data.apply(self, [self.revert, settings]);
                    }
                } else {
                    input_content = self.revert; 
                }
                input_content = input_content.replace(/&amp;/g, '&') ;           // Noel - ensure the input box contains proper ampersands
                
                content.apply(form, [input_content, settings, self]);

                input.attr('name', settings.name);
        
                /* add buttons to the form */
                buttons.apply(form, [settings, self]);
         
                /* add created form to self */
                $(self).append(form);
         
                /* attach 3rd party plugin if requested */
                plugin.apply(form, [settings, self]);

                /* focus to first visible form element */
                $(':input:visible:enabled:first', form).focus();

                /* highlight input contents when requested */
                if (settings.select) {
                    input.select();
                }
        
                /* discard changes if pressing esc */
                input.keydown(function(e) {
                    if (e.keyCode == 27) {
                        e.preventDefault();
                        // reset.apply(form, [settings, self]);
                        self.reset();
                    }
                });

                /* discard, submit or nothing with changes when clicking outside */
                /* do nothing is usable when navigating with tab */
                var t;
                if ('cancel' == settings.onblur) {
                    input.blur(function(e) {
                        if (!settings.resetting) {
                            //t = setTimeout(self.reset, 500);
                            t = setTimeout(function() {
                                self.reset();
                                // reset.apply(form, [settings, self]);
                            }, 500);
                        }
                    });
                } else if ('submit' == settings.onblur) {
                    input.blur(function(e) {
                        form.submit();
                    });
                } else if ($.isFunction(settings.onblur)) {
                    input.blur(function(e) {
                        settings.onblur.apply(self, [input.val(), settings]);
                    });
                } else {
                    input.blur(function(e) {
                      /* TODO: maybe something here */
                    });
                }

                form.submit(function(e) {

                    if (t) { 
                        clearTimeout(t);
                    }

                    /* do no submit */
                    e.preventDefault(); 
            
                    /* call before submit hook. if it returns false abort submitting */
                    // =======================================================
                    // Noel : Added the submitbefore call. This takes 3 parameters,
                    //      the new value
                    //      the original value
                    //      the settings
                    // and can return false to prevent the ajax call. Currently 
                    // it cannot modify the value.
                    // =======================================================
                    if (false !== submit.apply(form, [settings, self])
                        && (!$.isFunction(settings.submitbefore) ||
                            settings.submitbefore.apply(self, [input.val(), self.revert, settings])) 
                    ) {

                      /* check if given target is function */
                      if ($.isFunction(settings.target)) {
                          var str = settings.target.apply(self, [input.val(), settings]);
                          $(self).html(str);
                          self.editing = false;
                          callback.apply(self, [self.innerHTML, settings]);
                          /* TODO: this is not dry */                              
                          if (!$.trim($(self).html())) {
                              $(self).html(settings.placeholder);
                          }
                      } else {
                          /* add edited content and id of edited element to POST */
                          var submitdata = {};
                          submitdata[settings.name] = input.val();
                          submitdata[settings.id] = self.id;
                          /* add extra data to be POST:ed */
                          if ($.isFunction(settings.submitdata)) {
                              // ----------------------------------------------------
                              // Noel 12 Jun 2008 Added the submitdata as a parameter
                              // ----------------------------------------------------
                              $.extend(submitdata, settings.submitdata.apply(self, [submitdata, self.revert, settings]));
                          } else {
                              $.extend(submitdata, settings.submitdata);
                          }          
                           if (settings.deleting) {
                               $.extend(submitdata, {deleting: true});
                           }

                          // -------------------------------------------------
                          // NOEL. If indicator is set, display it in place of
                          // the selected contents
                          // -------------------------------------------------
                          /* show the saving indicator */
                          if (typeof(settings.indicator) == 'string') {
                              $(self).html(settings.indicator);
                          }

                          /* apply css or style or both */
                          if (settings.csssubmitclass) {
                              // form.attr('class', settings.csssubmitclass);
                              $('.ac_input', form).addClass(settings.csssubmitclass) ;
                          }

                          $.post(settings.target, submitdata, function(str) {
                              /* apply css or style or both */
                              if (settings.csssubmitclass) {
                                  // form.attr('class', settings.csssubmitclass);
                                  $('.ac_input', form).removeClass(settings.csssubmitclass) ;
                              }
                              if (typeof(settings.indicator) == 'string') {         // NOEL: Changed from !=
                                  // reset.apply(form, [settings, self]);
                                  self.reset();
                              }

                              // ---------------------------------------------
                              // NOEL": This used to always pass self.innerHTML 
                              // to the callback function. The problem is that
                              // that corrupted self-closing html tags causing a 
                              // subsequent call to TACONITE to fail.
                              // ---------------------------------------------
                              // Added the afterSubmit callback to allow the 
                              // current display to be left visible under errors.
                              // ---------------------------------------------
                              if (!$.isFunction(settings.afterSubmit) || 
                                    settings.afterSubmit.apply(self, [submitdata, self.revert, settings])) {
                                  self.editing = false;
                              }
                              if (typeof(str) == 'string') {
                                 var isTaconite = $.trim(str).substr(0, 10) == '<taconite>' ;
                                 if (!isTaconite) {       // NOEL
                                     $(self).html(str);
                                 }
                                 callback.apply(self, [str, settings]);
                                  
//                                 if (isTaconite && typeof(settings['output'] != 'undefined')) {       // NOEL
//                                     $(self).html(settings['output']);
//                                 }
                                  
                              } else {
                                  callback.apply(self, [self.innerHTML, settings]);                                  
                              }
                              
                              /* TODO: this is not dry */
                              if (!$.trim($(self).html())) {
                                  $(self).html(settings.placeholder);
                              }
                          });
                      }
                      
                    }
                     
                    return false;
                });
            });
            
            /* privileged methods */
            this.reset = function() {
                if (!settings.resetting) {
                    settings.resetting = true ;
                    reset.apply(self, [settings, self]);
                    // -----------------------------------------------------------
                    // NOEL: Added an onreset method. This was explictly for use
                    // where I'm overwriting a cell in a table row, as I hide the
                    // other cells in the ELEMENT method call and need to redisplay
                    // them now.
                    // -----------------------------------------------------------
                    if (!$.isFunction(settings.onreset) ||
                          settings.onreset.apply(self, [self, self.revert, settings])) {
                          }
                    $(self).html(self.revert);
                    self.editing   = false;
                    if (!$.trim($(self).html())) {
                        $(self).html(settings.placeholder);
                    }
                    settings.resetting = false ;
                }
            }
            
            // ---------------------------------------------------------------
            // DELETEIT
            // ========
            // This is called from the button handler to identify the relevant
            // form element and then activate teh callback function with three
            // inputs
            //          the current value
            //          the value prior to editing
            //          the settings array
            // The call method should return 
            //          TRUE        to submit the form with a 'deleting:true'
            //          FALSE
            // ---------------------------------------------------------------
            this.deleteit = function(event) {
                $(self).addClass('deleting') ;
                var cur_value = $('input:first', self).val() ;
                event.preventDefault() ;
                settings.resetting = true ;
                var result = settings.ondelete.apply(self, [cur_value, self.revert, settings]);
                $('input:first', self).focus() ;
                $(self).removeClass('deleting') ;
                settings.resetting = false;
                return result ;
            }

            
        });

    };


    $.editable = {
        types: {
            defaults: {
                element : function(settings, original) {
                    var input = $('<input type="hidden">');                
                    $(this).append(input);
                    return(input);
                },
                content : function(string, settings, original) {
                    $(':input:first', this).val(string);
                },
                reset : function(settings, original) {
                  original.reset();
                },
                buttons : function(settings, original) {
                    var form = this;
                    if (settings.submit) {
                        /* if given html string use that */
                        if (settings.submit.match(/>$/)) {
                            var submit = $(settings.submit).click(function() {
                                form.submit();
                            });
                        /* otherwise use button with given string as text */
                        } else {
                            var submit = $('<button type="submit">').addClass('jedit-submit');
                            submit.html(settings.submit);                            
                        }
                        $(this).append(submit);
                    }
                    if (settings.cancel) {
                        /* if given html string use that */
                        if (settings.cancel.match(/>$/)) {
                            var cancel = $(settings.cancel);
                        /* otherwise use button with given string as text */
                        } else {
                            var cancel = $('<button type="cancel">').addClass('jedit-cancel') ;
                            cancel.html(settings.cancel);
                        }
                        $(this).append(cancel);

                        $(cancel).click(function(event) {
                            //original.reset();
                            // if ($.isFunction($.editable.types[settings.type].reset)) {
                            //     var reset = $.editable.types[settings.type].reset;                                                                
                            // } else {

                                var reset = $.editable.types['defaults'].reset;                                

                            // }
                            reset.apply(form, [settings, original]);
                            // self.reset() ;
                            return false;
                        });
                    }
                    
                    // ---------------------------------------------------------------
                    // if a delete html string and associated function are provided, 
                    // add support for these.
                    // NOTE: As a HACK to avoid showing the delete button if this is
                    //      being used to create a new entry, it won't be shown if the
                    //      id ends in'-0',
                    // ---------------------------------------------------------------
                    if (settings.delete_but && original.id.substr(-2) != '-0' &&
                            $.isFunction(settings.ondelete)) {
                        var del ;                                   // Can't use the full name 'delete'
                        if (settings.delete_but.match(/>$/)) {
                            del = $(settings.delete_but);
                            
                        /* otherwise use button with given string as text */
                        } else {
                            del = $('<button type="">').addClass('jedit-delete') ;
                            del.html(settings.delete_but);
                        }
                        $(this).append(del);

                        // ---------------------------------------------------
                        // Indirectly call the callback function (as we don't
                        // have access to it here), which should return either 
                        // true or false. TRUE will result in the form being
                        // submnitted with an additional 'deleted=true' value
                        // and the back end should return code to remove the
                        // record from the screen.
                        // ---------------------------------------------------
                        $(del).click(function(event) {
                            if (original.deleteit(event)) {
                                settings.deleting = true ;
                                form.submit() ;
                            }
                            return false;
                        });
                    }
                    
                }
            },
            text: {
                element : function(settings, original) {
                    var input = $('<input>');
                    if (settings.width  != 'none') { input.width(settings.width);  }
                    if (settings.height != 'none') { input.height(settings.height); }
                    /* https://bugzilla.mozilla.org/show_bug.cgi?id=236791 */
                    //input[0].setAttribute('autocomplete','off');
                    input.attr('autocomplete','off');
                    $(this).append(input);
                    return(input);
                }
            },
            textarea: {
                element : function(settings, original) {
                    var textarea = $('<textarea>');
                    if (settings.rows) {
                        textarea.attr('rows', settings.rows);
                    } else {
                        textarea.height(settings.height);
                    }
                    if (settings.cols) {
                        textarea.attr('cols', settings.cols);
                    } else {
                        textarea.width(settings.width);
                    }
                    $(this).append(textarea);
                    return(textarea);
                }
            },
            select: {
                element : function(settings, original) {
                    var select = $('<select>');
                    $(this).append(select);
                    return(select);
                },
                content : function(string, settings, original) {
                    if (String == string.constructor) { 	 
                        eval ('var json = ' + string);
                        for (var key in json) {
                            if (!json.hasOwnProperty(key)) {
                                continue;
                            }
                            if ('selected' == key) {
                                continue;
                            } 
                            var option = $('<option>').val(key).append(json[key]);
                            $('select', this).append(option); 	 
                        }
                    }
                    /* Loop option again to set selected. IE needed this... */ 
                    $('select', this).children().each(function() {
                        if ($(this).val() == json['selected'] || 
                            $(this).text() == original.revert) {
                                $(this).attr('selected', 'selected');
                        };
                    });
                }
            }
        },

        /* Add new input type */
        addInputType: function(name, input) {
            $.editable.types[name] = input;
        }
    };

})(jQuery);

jQuery.editable.addInputType('autocomplete', {
    element : function(settings, original) {
                var input = $('<input>');
                if (settings.width  != 'none') { input.width(settings.width);  }
                if (settings.height != 'none') { input.height(settings.height); }

                // input.attr('autocomplete','off');
                $(this).append(input);
                // jQuery(this).autocomplete(cities);
                return(input);
        
    },

    plugin : function (settings, original) {
        settings.autocomplete_options = settings.autocomplete_options || {} ;
        
        // jQuery('input', this).autocomplete(settings.autocomplete_data, settings);
        // settings.__autoc = jQuery('input', this).autocomplete(settings.autocomplete_data);
        settings.autocomplete_options['source'] = settings.autocomplete_data
        settings.autocomplete_options['open'] = function(event, ui) {
          // $(".ui-autocomplete li:odd").addClass("ui-menu-item-alternate ac_odd") ;
          $(".ui-autocomplete li:odd").addClass("ac_odd") ;
          $(".ui-autocomplete li").hover(function () {$(this).addClass('ac_over') },
                                         function () {$(this).removeClass('ac_over')}
                                        ) ;
        }
        
        settings.__autoc = jQuery('input', this).autocomplete(settings.autocomplete_options);

        if (settings.autocomplete_options.renderItem) {
            jQuery('input', this).data( "autocomplete" )._renderItem = function( ul, item ) {
                                    settings.autocomplete_options.renderItem(ul, item) ;
                            }
        }
        
    },
    
    reset: function (settings) {
        // settings.__autoc[0].element.hide()
        $(settings.__autoc[0]).hide()
    }

    
});


/*
 * Record Status Form for Jeditable
 * ================================
 *
 *
 */
$.editable.addInputType('recstatus_def', {
    

    // -----------------------------------------------------------------------
    // ELEMENT
    // =======
    // This creates the form fields and appends them to the form itself (passed
    // in as 'this')
    // -----------------------------------------------------------------------
    current_id : function (original) {
        var parts = original.id.split('-') ;
        return parts[2] ;
    },
    
    element : function (settings, original) {
        var id   = $.editable.types['recstatus_def'].current_id(original) ;
        var name = $('<input name="rt-name" id="rt-name-' + id + '" class="rt-name" />') ;
        var retest = $('<input name="rt-retest" id="rt-retest-' + id + '" class="rt-retest" />')
        var autoa = $('<input type="checkbox" name="rt-autoa" id="rt-autoa-' + id + '" class="rt-autoa" />')
        var active = false ;
        
        if (typeof(settings.orig_submitdata) == 'undefined') {
            settings.orig_submitdata = settings.submitdata ;
        }
        
        settings.submitdata = function(submitdata, old_value, settings) {
            if (!active) {
                active = true ;
                
                var name   = $('#rt-name-' + id).val() ;
                var retest = $('#rt-retest-' + id).val() ;
                var autoa  = $('#rt-autoa-' + id, this).attr('checked') ? $('#rt-autoa-' + id, this).val() : '' ;
            
                $.extend(submitdata, {name: name, retest: retest, autoa: autoa});
            
                if ($.isFunction(settings.orig_submitdata)) {
                    $.extend(submitdata, settings.orig_submitdata.apply(self, [submitdata, self.revert, settings]));
                } else {
                    $.extend(submitdata, settings.orig_submitdata);
                }
                active = false
            }
            return submitdata ;
        } ;
        
        $(this).append('<label for="rt-name-' + id + '" ">Type </label>')
        $(this).append(name);
        $(this).append(' <label for="rt-retest-' + id + '" ">Retest Frequency </label>')
        $(this).append(retest);
        $(this).append(' months&#160; &#160; ') ;
        $(this).append('<label for="rt-autoa-' + id + '" ">Add Action </label>')
        $(this).append(autoa);
        $(this).append('<br />') ;
        
        /* Last create an hidden input. This is returned to plugin. It will */
        /* later hold the actual value which will be submitted to server.   */
        var hidden = $('<input type="hidden">');
        $(this).append(hidden);
        return(hidden);
        
    },

    // -----------------------------------------------------------------------
    // CONTENT
    // =======
    // Parameters:
    //      string      : the value displayed prior to starting editing
    //      settings    : the options passed in to jEditable
    //      original    : the tag used as the jEditable trigger
    // -----------------------------------------------------------------------
    content : function (string, settings, original) {
        var id   = $.editable.types['recstatus_def'].current_id(original) ;
        $('#rt-name-' + id, this).val($('#rt-n-' + id).val()) ;
        $('#rt-retest-' + id, this).val($('#rt-rt-' + id).val()) ;
        if ($('#rt-a-' + id).val()) {
            $('#rt-autoa-' + id, this).attr('checked', 'checked') ;
        }
    },
    
    // -----------------------------------------------------------------------
    // SUBMIT
    // ======
    // This is called prior to submitting the form.
    // -----------------------------------------------------------------------
    submit : function (settings, original) {
        var id   = $.editable.types['recstatus_def'].current_id(original) ;
        var name = $('#rt-name-' + id, this).val() ;
        var retest = $('#rt-retest-' + id, this).val();
        var autoa = $('#rt-autoa-' + id, this).val();
        var value  = name ;
        
        if (name != '' && retest > 0) {
            value += ' : ' + retest ;
        }
        if (name != '' && autoa != '') {
            value += ' : ' + autoa ;
        }
        $('input:hidden', this).val(value);
        
    }
}) ;

/*
 * Record Status Form for Jeditable
 * ================================
 *
 *
 */
$.editable.addInputType('recservice_item', {

        // rep person - 1 row lots of clients
        // 
        // scheduled visits - add responsible person to property bo
        // 

    // -----------------------------------------------------------------------
    // CURRENT_ID
    // =========
    // It is assumed the 'original' element has an id in the format 'xxx'-<item-id>
    // -----------------------------------------------------------------------
    current_id : function (original) {
        var parts = original.id.split('-') ;
        return parts ;
        
        // return original.id ;
    },
        
    // -----------------------------------------------------------------------
    /* Create pulldowns for hours and minutes. Append them to */
    /* form which is accessible as variable this.                 */        
    // -----------------------------------------------------------------------
    date_selector : function (cday, cmonth, cyear) {
        var monthselect = $('<select name="month_">');
        var yearselect = $('<select name="year_">');
        
        var selected ;
        var div = $('<span>') ;
        
        div.append ('<input name="day_" value="' + cday + '" size="2" />&#160') ;
        // div.append ()
        
        var months = ['', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sept', 'Oct', 'Nov', 'Dec'] ;
        
        for (var month=0; month <= months.length; month++) {
            selected = month == cmonth ? ' selected' : '' ;

            var option = $('<option>').attr('selected',  selected ).val(month).append(months[month]) ;
            monthselect.append(option);
        }
        div.append(monthselect) ;
        div.append('&#160;') ;
        
        var tyear = new Date().getFullYear() ;
        
        var option = $('<option>') ;
        yearselect.append(option);
        for (year = tyear-1; year <= tyear+5; year++) {
            selected = year == cyear ? 'selected' : '' ;

            var option = $('<option>').attr('selected', selected ).val(year).append(year);
            yearselect.append(option);
        }
        div.append(yearselect) ;
        return div ;
    },
    // -----------------------------------------------------------------------
    // ELEMENT
    // =======
    // This creates the form fields and appends them to the form itself (passed
    // in as 'this'). It is assumed the 'original' element has an id in the
    // format 'xxx'-<item-id>.
    // 
    // The generated form fields are (by name :- append -<real-id> for the id)
    //      cat              the category name
    //      type             the records status type
    //      retest           the retest interval (numeric months)
    //      location         the place the certificate is stored
    //      notify-to        the name of the person to email
    //      notify-interval  the number of weeks/months before to send the email
    //      notify-units     whether the above is weeks or months
    //      add-al           true if should generate an action entry when sending reminder
    //
    // We also include 3 hidden fields to hold the db keys of selected items. These are 
    // named, and have ids, as above, but with -id appended.
    //      cat-id           the db key for the category name (ID cat-<real-id>-id)
    //      type-id          the db key for the type name     (ID type-<real-id>-id) 
    //      notify-to-id     the db key for the person to be emailed.(ID notify-to-<real-id>-id)
    // 
    // When the page is initially created, each records-status entry is associated
    // with a form, identifiable by it's id in the format 'frm-<real-id>'.
    // Inside the form are a set of hidden fields, named as above, but with no
    // id, containing the current values. These are copied over to the matching 
    // fields in the new form.
    // 
    // The db hidden fields are maintained via the on-change events, while the
    // others are updated via the server response to the submitted form.
    // 
    // When called 'this' refers to the form element added by jEditable
    // -----------------------------------------------------------------------
    element : function (settings, original) {
        var active = false ;
        var service_row = $(original).parent() ;
        
        var parts  = $.editable.types['recservice_item'].current_id(service_row[0]) ;
        var id     = parts[1] ;

        var colspan = $(original).attr('colspan') ;
        colspan     = colspan ? colspan : 1 ;
        colspan     = parseInt(colspan) ;
        
        $(original).siblings('td').hide() ;
        $(original).attr('colspan', $(original).siblings('td').size()+colspan) ;

        var main_form = $('#srvedit-' + id) ;
        
        var cur_srv    = $('[name=sname]', main_form).val() ;
        var cur_tim    = $('[name=stime]', main_form).val() ;
        
        var cur_srvid  = $('[name=sname-id]', main_form).val() ;
        var cur_timid  = $('[name=stime-id]', main_form).val() ;
        
        var cdays      = $('[name=cdays]', main_form).val() ;
        var repeat_count = $('[name=repeat_count]', main_form).val() ;
        var report_delay  = $('[name=report_delay]', main_form).val() ;
        var invoice_delay = $('[name=invoice_delay]', main_form).val() ;

        this.cur_timid = cur_timid ;
        
        if (typeof(settings.orig_submitdata) == 'undefined') {
            settings.orig_submitdata = settings.submitdata ;
        }
        
        html =
'        <form>' +
'            <div id="srv-" class="rt-item">' +
'                <h2>Service : ' + cur_srv + '</h2>' +
'                    <input type="hidden" name="service" id="srv-' + id +'" value="' + cur_srv + '" />' +
'                <fieldset>' +
        '                    <label for="tim-' + id +'">Timing</label><input type="text" name="timing" class="timing" id="tim-' + id +'" size="40" value="' + cur_tim + '" /><br />' +
'                    <label for="cdv-' + id +'">Number of consecutive days for vist</label><input type="text" name="cdv" id="cdv-' + id +'" size="2" value="' + cdays + '" />' +
'                    <label for="rsch-' + id +'">Repeat the schedule sequence</label><input type="text" name="rsch" id="rsch-' + id +'" size="2" value="' + repeat_count + '" />&#160;times.' +
'                </fieldset>' +

'                <fieldset>' +
'                    <label for="mvr-' + id +'">Maximum days between visit and report production</label><input type="text" name="mvr" id="mvr-' + id +'" size="2" value="' + report_delay +'" /> and ' +
'                    <label for="mvr-' + id +'">between report production and invoicing</label><input type="text" name="mvr" id="mvr-' + id +'" size="2" value="' + invoice_delay + '" />' +
'                </fieldset>' +

'                <fieldset>' +
'                    <label for="lcs">Linked child services?</label>' +
'                    <input type="text" id="lcs" />' +
'                </fieldset>' ;

        if (id > 0) {
            html +=
                    '<span class="del" style="float:right;color:#003800;font-style:oblique"><input type="checkbox" class="del" name="del" id="del-' + id +'" value="del">&#160;<label class="del" for="del-' + id + '">Tick here to delete this entry</label></span>' ;
        }
        
            html +=
'            </div>' +
'        </form>' ;
        
        $(this).append(html);

        // $('#del-' + id, this).click(function() {
        //     if (this.checked) {
        //         $('#d' + id).css('background-color', 'lightgrey') ;
        //         $('[class!=del]', '#d' + id).filter('[type!=hidden]').attr('disabled', 'disabled').css('color', 'grey') ;
        //         $('label[class=del]', '#d' + id).css('color', 'red') ;
        //         if (!confirm('Do your really want to delete this records status entry?')) {
        //             this.checked = false;                
        //             
        //         } else {
        //             $('label[class=del]', '#d' + id).html('This entry will be deleted after clicking save') ;
        //         }
        //     } 
        //     
        //     if (!this.checked) {
        //         $('label[class=del]', '#d' + id).css('color', '') ;
        //         $('[class!=del]', '#d' + id).filter('[type!=hidden]').attr('disabled', '').css('color', '') ;
        //         $('#d' + id).css('background-color', '') ;
        //         $('label[class=del]', '#d' + id).html('Tick here to delete this entry') ;
        //     }
        //     }
        //     ) ;


        // -------------------------------------------------------------------
        // SUBMITDATA
        // ==========
        // An anonymous function called prior to the actual submission, this
        // gathers the fields from the form and appends them to submitdata.
        // If not done here, the standard autocomplete code would only submit
        // the contents of the hidden field we return below (which we don't use).
        // -------------------------------------------------------------------
        settings.submitdata = function(submitdata, old_value, settings) {
            if (!active) {
                active = true ;

                var fields = $(this).children().serialize().split('&') ;
                var result = {} ;
                for (ind=0; ind < fields.length; ind++) {
                    var parts = fields[ind].split('=') ;
                    result[parts[0]] = parts[1] ;
                }
                $.extend(submitdata, result) ;
                
                if ($.isFunction(settings.orig_submitdata)) {
                    $.extend(submitdata, settings.orig_submitdata.apply(self, [submitdata, self.revert, settings]));
                    
                } else {
                    $.extend(submitdata, settings.orig_submitdata);
                }
                active = false
            }
            return submitdata ;
        } ;
        
        var hidden = $('<input type="hidden">');
        $(this).append(hidden);
        return(hidden);
        
    },

    // -----------------------------------------------------------------------
    // CONTENT
    // =======
    // Parameters:
    //      string      : the value displayed prior to starting editing
    //      settings    : the options passed in to jEditable
    //      original    : the tag used as the jEditable trigger
    // 
    // When called 'this' refers to the form element added by jEditable
    // -----------------------------------------------------------------------
    content : function (string, settings, original) {
        var id   = $.editable.types['recservice_item'].current_id($(original).parent().children('td:eq(0)')[0]) ;
        $('#type-' + id, this).val($('#n-' + id).val()) ;
        $('#retest-' + id, this).val($('#' + id).val()) ;
    },
    
    // -----------------------------------------------------------------------
    // SUBMIT
    // ======
    // This is called prior to submitting the form.
    // -----------------------------------------------------------------------
    submit : function (settings, original) {
        var id     = $.editable.types['recservice_item'].current_id($(original).parent().children('td:eq(0)')[0]) ;
        var name   = $('#type-' + id, this).val() ;
        var retest = $('#retest-' + id, this).val();
        
        if (name != '' && retest > 0) {
            var value = $('#type-' + id, this).val() + ' : ' +
                        $('#retest-' + id, this).val() ;
        }
        // $('input:hidden', this).val(value);
        
    },



    // -----------------------------------------------------------------------
    // PLUGIN
    // ======
    // 
    // When called 'this' refers to the form element added by jEditable
    // -----------------------------------------------------------------------
    plugin : function (settings, original) {
        
        var local_timing_options = $.extend (
                        {
                            // onchange : $.editable.types['recservice_item'].on_type_change,
                        },
                        settings.autoc_timing_options.autocomplete_options
                    ) ;
    
        var timing_data = settings.autoc_timing_options.autocomplete_data
        if (this.cur_timid) {
            for (var c_ind=0; c_ind < timing_data.length; c_ind++) {
                if (timing_data[c_ind]['id'] == this.timing_data) {
                    timing_data = timing_data[c_ind]['types'] 
                    break ;
                }
            }
        }
        
        $('input.timing', this).autocomplete(timing_data, local_timing_options);
    }
    
}) ;

// ---------------------------------------------------------------------------
// FIXBLOCK
// ========
// This plugin will move it's element inside the passed container, aligning
// it to the top and left and extending it to the full width. It will also 
// tweak the css and attach event handlers to ensure the elements scroll
// together, but that the element itself never scrolls off the top of the screen.
// ---------------------------------------------------------------------------
(function($) {

    $.fn.fixblock = function(container, options) {

        var settings = {
            container   : container,
            tgl         : false, 
            name       : 'value',
            id         : 'id',
            type       : 'text',
            width      : 'auto',
            height     : 'default'
        };

        if(options) {
            $.extend(settings, options);
        }

	    var head = $(settings.container) ;

        this.each(function() {
            var fme = $(this) ;
    	    var tgl = false ;

    	    if (settings.tgl && settings.tgl != false) {
    	        var tgl = $(settings.tgl) ;
	        }
	        
	        if (tgl !== false && tgl.length == 0) {
    		    tgl = $('<span style="float:right;padding:0 10px 10px;font-size:80%"><a href="#" id="tgl">Toggle</a></span>') ;		    
    		    fme.prepend (tgl) ;
    	    }

            sizeit() ;
	        scrollIt () ;

		    if (tgl != false) {
    		    tgl.click(function () {
        	        if (parseInt(fme.height()) > 20) {
        	            fme.animate({height: '1em'}, 'fast') ;
        	        } else {
        	            fme.animate({height: fme.data('height')}, 'fast') ;
        	        }
        	        return false;
        	    })
    	    }
    	    
    	    $(window).bind('scroll.fixblock', function () {
    	        if (fme.is(':visible') && fme.height() > 0) {
                    scrollIt() ;
    			}
    	    }).bind('resize.fixblock', function () {
    	        if (fme.is(':visible') && fme.height() > 0) {
        	        sizeit() ;
        	        scrollIt () ;
        	    }
    	    })
    	    
    	    function sizeit () {
        	    var pos = head.offset() ;
        	    var width = head.width() ;
        	    var height = head.height() ;
        	    var bleft  = parseInt(head.css('border-left-width')) ;
        	    var bright = parseInt(head.css('border-right-width')) ;
        	    var btop   = parseInt(head.css('border-top-width')) ;
        	    var bbot   = parseInt(head.css('border-bottom-width')) ;
        	    var pleft  = parseInt(fme.css('padding-left')) ;
        	    var pright = parseInt(fme.css('padding-right')) ;
        	    var ptop   = parseInt(fme.css('padding-top')) ;
        	    var pbot   = parseInt(fme.css('padding-bottom')) ;
                var curHeight = fme.height() ;
                
                if (isNaN(bleft)) {
                    bleft = 1 ;
                }
                if (isNaN(bright)) {
                    bright = 1 ;
                }
                if (isNaN(btop)) {
                    btop = 1 ;
                }
                if (isNaN(bbot)) {
                    bbot = 1 ;                    
                }
                
                curHeight += pbot + ptop + btop + bbot ;

        	    aScrollTop = pos.top+btop ;
    	    
                // fme.css({'left': pos.left+bleft, 'top': aScrollTop, 'overflow': 'hidden'}) ;
        	    fme.css({'left': pos.left+bleft, 'top': aScrollTop, 'overflow': 'hidden', 'position': 'fixed'}) ;
                fme.width (width-bleft-bright-pleft-pright) ;

        	    if (settings.height == 'auto') {
        	        fme.height (height-btop-bbot) ;
    	        } else {
    	            head.height (curHeight) ;
    	        }
        	    fme.data('height', fme.height()) ;
    	        var zind = parseInt(head.css('z-index')) ;

    	        if (isNaN(zind)) {
    	            zind = 1 ;
    	        } else {
    	            zind++ ;
    	        }
    	        fme.css('z-index', zind) ;
    	    }
    	    
    	    function scrollIt () {
    			var ScrollTop = document.body.scrollTop;
    			if (ScrollTop == 0) {
    				if (window.pageYOffset)
    					ScrollTop = window.pageYOffset;
    				else
    					ScrollTop = (document.body.parentElement) ? document.body.parentElement.scrollTop : 0;
    			}
    			if(ScrollTop < aScrollTop)
    				fme.css('top', aScrollTop - ScrollTop + "px") ;
    			else
    				fme.css('top', "0px");
    	    }
    	    
        });

    }

})(jQuery);

/*
 * Thickbox 3.1 - One Box To Rule Them All.
 * By Cody Lindley (http://www.codylindley.com)
 * Copyright (c) 2007 cody lindley
 * Licensed under the MIT License: http://www.opensource.org/licenses/mit-license.php
*/
		  
var tb_pathToImage = "/js/thickbox/loadingAnimation.gif";

/*!!!!!!!!!!!!!!!!! edit below this line at your own risk !!!!!!!!!!!!!!!!!!!!!!!*/

//on page load call tb_init
$(document).ready(function(){   
	tb_init('a.thickbox, area.thickbox, input.thickbox');//pass where to apply thickbox
	imgLoader = new Image();// preload image
	imgLoader.src = tb_pathToImage;
});

//add thickbox to href & area elements that have a class of .thickbox
function tb_init(domChunk){
	$(domChunk).click(function(){
	var t = this.title || this.name || null;
	var a = this.href || $(this).attr('alt') ;              // Noel. Only checked for alt, and it's only accessible this way for <TR>
	var g = this.rel || false;
	tb_show(t,a,g);
	this.blur();
	return false;
	});
}

function tb_show(caption, url, imageGroup) {//function called when the user clicks on a thickbox link

	try {
		if (typeof document.body.style.maxHeight === "undefined") {//if IE 6
			$("body","html").css({height: "100%", width: "100%"});
			$("html").css("overflow","hidden");
			if (document.getElementById("TB_HideSelect") === null) {//iframe to hide select elements in ie6
				$("body").append("<iframe id='TB_HideSelect'></iframe><div id='TB_overlay'></div><div id='TB_window'></div>");
				$("#TB_overlay").click(tb_remove);
			}
		}else{//all others
			if(document.getElementById("TB_overlay") === null){
				$("body").append("<div id='TB_overlay'></div><div id='TB_window'></div>");
				$("#TB_overlay").click(tb_remove);
			}
		}
		
		if(tb_detectMacXFF()){
			$("#TB_overlay").addClass("TB_overlayMacFFBGHack");//use png overlay so hide flash
		}else{
			$("#TB_overlay").addClass("TB_overlayBG");//use background and opacity
		}
		
		if(caption===null){caption="";}
		$("body").append("<div id='TB_load'><img src='"+imgLoader.src+"' /></div>");//add loader to the page
		$('#TB_load').show();//show loader
		
		var baseURL;
	   if(url.indexOf("?")!==-1){ //ff there is a query string involved
			baseURL = url.substr(0, url.indexOf("?"));
	   }else{ 
	   		baseURL = url;
	   }
	   
	   var urlString = /\.jpg$|\.jpeg$|\.png$|\.gif$|\.bmp$/;
	   var urlType = baseURL.toLowerCase().match(urlString);

		if(urlType == '.jpg' || urlType == '.jpeg' || urlType == '.png' || urlType == '.gif' || urlType == '.bmp'){//code to show images
				
			TB_PrevCaption = "";
			TB_PrevURL = "";
			TB_PrevHTML = "";
			TB_NextCaption = "";
			TB_NextURL = "";
			TB_NextHTML = "";
			TB_imageCount = "";
			TB_FoundURL = false;
			if(imageGroup){
				TB_TempArray = $("a[@rel="+imageGroup+"]").get();
				for (TB_Counter = 0; ((TB_Counter < TB_TempArray.length) && (TB_NextHTML === "")); TB_Counter++) {
					var urlTypeTemp = TB_TempArray[TB_Counter].href.toLowerCase().match(urlString);
						if (!(TB_TempArray[TB_Counter].href == url)) {						
							if (TB_FoundURL) {
								TB_NextCaption = TB_TempArray[TB_Counter].title;
								TB_NextURL = TB_TempArray[TB_Counter].href;
								TB_NextHTML = "<span id='TB_next'>&nbsp;&nbsp;<a href='#'>Next &gt;</a></span>";
							} else {
								TB_PrevCaption = TB_TempArray[TB_Counter].title;
								TB_PrevURL = TB_TempArray[TB_Counter].href;
								TB_PrevHTML = "<span id='TB_prev'>&nbsp;&nbsp;<a href='#'>&lt; Prev</a></span>";
							}
						} else {
							TB_FoundURL = true;
							TB_imageCount = "Image " + (TB_Counter + 1) +" of "+ (TB_TempArray.length);											
						}
				}
			}

			imgPreloader = new Image();
			imgPreloader.onload = function(){		
			imgPreloader.onload = null;
				
			// Resizing large images - orginal by Christian Montoya edited by me.
			var pagesize = tb_getPageSize();
			var x = pagesize[0] - 150;
			var y = pagesize[1] - 150;
			var imageWidth = imgPreloader.width;
			var imageHeight = imgPreloader.height;
			if (imageWidth > x) {
				imageHeight = imageHeight * (x / imageWidth); 
				imageWidth = x; 
				if (imageHeight > y) { 
					imageWidth = imageWidth * (y / imageHeight); 
					imageHeight = y; 
				}
			} else if (imageHeight > y) { 
				imageWidth = imageWidth * (y / imageHeight); 
				imageHeight = y; 
				if (imageWidth > x) { 
					imageHeight = imageHeight * (x / imageWidth); 
					imageWidth = x;
				}
			}
			// End Resizing
			
			TB_WIDTH = imageWidth + 30;
			TB_HEIGHT = imageHeight + 60;
			$("#TB_window").append("<a href='' id='TB_ImageOff' title='Close'><img id='TB_Image' src='"+url+"' width='"+imageWidth+"' height='"+imageHeight+"' alt='"+caption+"'/></a>" + "<div id='TB_caption'>"+caption+"<div id='TB_secondLine'>" + TB_imageCount + TB_PrevHTML + TB_NextHTML + "</div></div><div id='TB_closeWindow'><a href='#' id='TB_closeWindowButton' title='Close'>close</a> or Esc Key</div>"); 		
			
			$("#TB_closeWindowButton").click(tb_remove);
			
			if (!(TB_PrevHTML === "")) {
				function goPrev(){
					if($(document).unbind("click",goPrev)){$(document).unbind("click",goPrev);}
					$("#TB_window").remove();
					$("body").append("<div id='TB_window'></div>");
					tb_show(TB_PrevCaption, TB_PrevURL, imageGroup);
					return false;	
				}
				$("#TB_prev").click(goPrev);
			}
			
			if (!(TB_NextHTML === "")) {		
				function goNext(){
					$("#TB_window").remove();
					$("body").append("<div id='TB_window'></div>");
					tb_show(TB_NextCaption, TB_NextURL, imageGroup);				
					return false;	
				}
				$("#TB_next").click(goNext);
				
			}

			document.onkeydown = function(e){ 	
				if (e == null) { // ie
					keycode = event.keyCode;
				} else { // mozilla
					keycode = e.which;
				}
				if(keycode == 27){ // close
					tb_remove();
				} else if(keycode == 190){ // display previous image
					if(!(TB_NextHTML == "")){
						document.onkeydown = "";
						goNext();
					}
				} else if(keycode == 188){ // display next image
					if(!(TB_PrevHTML == "")){
						document.onkeydown = "";
						goPrev();
					}
				}	
			};
			
			tb_position();
			$("#TB_load").remove();
			$("#TB_ImageOff").click(tb_remove);
			$("#TB_window").css({display:"block"}); //for safari using css instead of show
			};
			
			imgPreloader.src = url;
		}else{//code to show html
			
			var queryString = url.replace(/^[^\?]+\??/,'');
			var params = tb_parseQuery( queryString );

// ---------------------------------------------------------------------------
// Noel : Removed the + 30, +40, -30, -45 as it produces an undersirable white border.
//        This should be controlled via css if wanted
// ---------------------------------------------------------------------------
            // TB_WIDTH = (params['width']*1) + 30 || 630; //defaults to 630 if no paramaters were added to URL
            // TB_HEIGHT = (params['height']*1) + 40 || 440; //defaults to 440 if no paramaters were added to URL
			TB_WIDTH = (params['width']*1)  || 630; //defaults to 630 if no paramaters were added to URL
			TB_HEIGHT = (params['height']*1) || 440; //defaults to 440 if no paramaters were added to URL
			ajaxContentW = TB_WIDTH ; //- 30;
			ajaxContentH = TB_HEIGHT ; //- 45;
			
			if(url.indexOf('TB_iframe') != -1){// either iframe or ajax window		
					urlNoQuery = url.split('TB_');
					$("#TB_iframeContent").remove();
					if(params['modal'] != "true"){//iframe no modal
					    
					    // Noel - allow totally empty frame
					    
					    if (param['nobutton']) {
					        
					    } else {
					        $("#TB_window").append("<div id='TB_title'><div id='TB_ajaxWindowTitle'>"+caption+"</div><div id='TB_closeAjaxWindow'><a href='#' id='TB_closeWindowButton' title='Close'>close</a> or Esc Key</div></div>") ;
					        
					    }
					    
						$("#TB_window").append("<iframe frameborder='0' hspace='0' src='"+urlNoQuery[0]+"' id='TB_iframeContent' name='TB_iframeContent"+Math.round(Math.random()*1000)+"' onload='tb_showIframe()' style='width:"+(ajaxContentW + 29)+"px;height:"+(ajaxContentH + 17)+"px;' > </iframe>");
						
						
						
					}else{//iframe modal
					    
					$("#TB_overlay").unbind();
						$("#TB_window").append("<iframe frameborder='0' hspace='0' src='"+urlNoQuery[0]+"' id='TB_iframeContent' name='TB_iframeContent"+Math.round(Math.random()*1000)+"' onload='tb_showIframe()' style='width:"+(ajaxContentW + 29)+"px;height:"+(ajaxContentH + 17)+"px;'> </iframe>");
					}
					
			}else{// not an iframe, ajax
					if($("#TB_window").css("display") != "block"){
						if(params['modal'] != "true"){//ajax no modal

    					    // Noel - allow totally empty frame

						    if (params['nobutton']) {
						        
						    } else {
        						$("#TB_window").append("<div id='TB_title'><div id='TB_ajaxWindowTitle'>"+caption+"</div><div id='TB_closeAjaxWindow'><a href='#' id='TB_closeWindowButton'>close</a> or Esc Key</div></div>");
						        
						    }
						    if ($("#TB_ajaxContent").length == 0) {
                                $("#TB_window").append("<div id='TB_ajaxContent' class='god' style='width:"+ajaxContentW+"px;height:"+ajaxContentH+"px'></div>");
						    }
						}else{//ajax modal
    						$("#TB_overlay").unbind();
    						$("#TB_window").append("<div id='TB_ajaxContent' class='TB_modal' style='width:"+ajaxContentW+"px;height:"+ajaxContentH+"px;'></div>");	
						}
					}else{//this means the window is already up, we are just loading new content via ajax
						$("#TB_ajaxContent")[0].style.width = ajaxContentW +"px";
						$("#TB_ajaxContent")[0].style.height = ajaxContentH +"px";
						$("#TB_ajaxContent")[0].scrollTop = 0;
						$("#TB_ajaxWindowTitle").html(caption);
					}
			}
					
			$("#TB_closeWindowButton").click(tb_remove);
			
				if(url.indexOf('TB_inline') != -1){	
					$("#TB_ajaxContent").append($('#' + params['inlineId']).children());
					$("#TB_window").unload(function () {
						$('#' + params['inlineId']).append( $("#TB_ajaxContent").children() ); // move elements back when you're finished
					});
					tb_position();
					$("#TB_load").remove();
					$("#TB_window").css({display:"block"}); 
				}else if(url.indexOf('TB_iframe') != -1){
					tb_position();
					if($.browser.safari){//safari needs help because it will not fire iframe onload
						$("#TB_load").remove();
						$("#TB_window").css({display:"block"});
					}
				}else{
                    // -------------------------------------------------------
                    // Noel: Add either a ? or & and then a random value to 
                    // ensure the request is always executed.
                    // -------------------------------------------------------
                    url += (url.indexOf('?') >= 0 ? '&' : '?') + 'random=' + new Date().getTime() ;
                    // $.get(url += "&random=" + (new Date().getTime()),function(){//to do a post change this load method
                    $("#TB_ajaxContent").load(url, function(){//to do a post change this load method
						tb_position();
						$("#TB_load").remove();
						tb_init("#TB_ajaxContent a.thickbox");
						$("#TB_window").css({display:"block"});
					});
				}
			
		}

		if(!params['modal']){
			document.onkeyup = function(e){ 	
				if (e == null) { // ie
					keycode = event.keyCode;
				} else { // mozilla
					keycode = e.which;
				}
				if(keycode == 27){ // close
					tb_remove();
				}	
			};
		}
		
	} catch(e) {
		//nothing here
	}
}

//helper functions below
function tb_showIframe(){
	$("#TB_load").remove();
	$("#TB_window").css({display:"block"});
}

function tb_remove() {
 	$("#TB_imageOff").unbind("click");
	$("#TB_closeWindowButton").unbind("click");
	$("#TB_window").fadeOut("fast",function(){$('#TB_window,#TB_overlay,#TB_HideSelect').trigger("unload").unbind().remove();});
	$("#TB_load").remove();
	if (typeof document.body.style.maxHeight == "undefined") {//if IE 6
		$("body","html").css({height: "auto", width: "auto"});
		$("html").css("overflow","");
	}
	document.onkeydown = "";
	document.onkeyup = "";
	return false;
}

function tb_position() {
$("#TB_window").css({marginLeft: '-' + parseInt((TB_WIDTH / 2),10) + 'px', width: TB_WIDTH + 'px'});
	if ( !(jQuery.browser.msie && jQuery.browser.version < 7)) { // take away IE6
		$("#TB_window").css({marginTop: '-' + parseInt((TB_HEIGHT / 2),10) + 'px'});
	}
}

function tb_parseQuery ( query ) {
   var Params = {};
   if ( ! query ) {return Params;}// return empty object
   var Pairs = query.split(/[;&]/);
   for ( var i = 0; i < Pairs.length; i++ ) {
      var KeyVal = Pairs[i].split('=');
      if ( ! KeyVal || KeyVal.length != 2 ) {continue;}
      var key = unescape( KeyVal[0] );
      var val = unescape( KeyVal[1] );
      val = val.replace(/\+/g, ' ');
      Params[key] = val;
   }
   return Params;
}

function tb_getPageSize(){
	var de = document.documentElement;
	var w = window.innerWidth || self.innerWidth || (de&&de.clientWidth) || document.body.clientWidth;
	var h = window.innerHeight || self.innerHeight || (de&&de.clientHeight) || document.body.clientHeight;
	arrayPageSize = [w,h];
	return arrayPageSize;
}

function tb_detectMacXFF() {
  var userAgent = navigator.userAgent.toLowerCase();
  if (userAgent.indexOf('mac') != -1 && userAgent.indexOf('firefox')!=-1) {
    return true;
  }
}

function addit(property_id, block, rstat_id) {
    var cat_val = $('#rstat-cat-' + rstat_id + '-id').val() ;
    var rt_types ;
    
    for (ind=0; ind < rt_cats.length; ind++) {
        if (rt_cats[ind].id == cat_val) {
            rt_types = rt_cats[ind].types ;
        }
    }
    
    cat_options = {
                autocomplete_data : rt_cats,
                autocomplete_options : {
                    source   : rt_cats,
                    autoFill : false,
                    delay    : 10,
                    matchContains: true,
                    minLength    : 0,
                    mustMatch    : true,                // Don't allow new entries to be added from here
                    max          : 0,                   // SHow all matches
                    // extraParams : {cl_id : getclient},
                    // parse: rt_contact_parse,
                
                    //                     matchSubset: my_matchSubset,
                    formatItem:  rt_c_formatItem,                                    
                    formatMatch: rt_c_formatMatch,
            
                    change : function (event, ui) {                  // If click the save button, not triggered until AFTER the form is submitted
                        on_cat_change ($(this), this.value, ui.item) ;
                    },

                    select: function (event, ui) {
                        var id = event.target.id ;
                        $('#resp_id').val(ui.item.id) ;
                        on_cat_change ($(this), ui.item.id, ui.item) ;
                    },

                    open: function(event, ui) {
                      $(".ui-autocomplete li.ui-menu-item:odd").addClass("ui-menu-item-alternate ac_odd");
                    },

                    selectable: function (row) {
                        $('#resp_id').val(row.data.id) ;
                        return true ;
                    }
                    
                }
                
                } ;

    type_options = {
                autocomplete_data : rt_cats,
                autocomplete_options : {
                    source   : rt_types,
                    autoFill : false,
                    delay    : 10,
                    matchContains: true,
                    minLength    : 0,
                    mustMatch    : true,                // Don't allow new entries to be added from here
                    max          : 0,                   // SHow all matches

                    // change : function (event, ui) {                  // If click the save button, not triggered until AFTER the form is submitted
                    //     on_type_change ($(this), this.value, ui.item) ;
                    // },
                    
                    formatItem:  rt_t_formatItem,                                    
                    formatMatch: rt_t_formatMatch,
            
                    select: function (event, ui) {
                        var id = event.target.id ;
                        $('#resp_id').val(ui.item.tid) ;
                        on_type_change ($(this), this.value, ui.item) ;
                    },

                    open: function(event, ui) {
                      $(".ui-autocomplete li.ui-menu-item:odd").addClass("ui-menu-item-alternate ac_odd");
                    },

                    selectable: function (row) {
                        $('#resp_id').val(row.data.id) ;
                        return true ;
                    }
                }
             } ;

    $('input.rstat-cat',  block).autocomplete(  cat_options.autocomplete_options)
        .focus(function(){
		    $(this).trigger('keydown.autocomplete');
        });
    $('input.rstat-type', block).autocomplete(  type_options.autocomplete_options) 
        .focus(function(){
		    $(this).trigger('keydown.autocomplete');
        });

    // $('input.rstat-type', block)[0].type_options = type_options.autocomplete_options ;
    // $('input.rt-type', block).autocomplete( type_options);

    $('select', '#tim-' + rstat_id).click(function() { check_action(rstat_id) } ) ;
    $('#rstat-al-' + rstat_id).click(function() { check_action(rstat_id) } ) ;

    aprop_recstat (property_id, block) ;
    
    function check_action(rstat_id) {
        if ($('#rstat-al-' + rstat_id).attr('checked')) {
            var show = 0 ; 
            $('select', '#tim-' + rstat_id).each(function () {if ($(this).val()) {show++}}) ;
            if (show==2) {
                $('#al-now-' + rstat_id).hide() ;
                $('#al-when-' + rstat_id).show() ;
            } else {
                $('#al-now-' + rstat_id).show() ;
                $('#al-when-' + rstat_id).hide() ;
            }
        } else {
            $('#al-now-' + rstat_id).hide() ;
            $('#al-when-' + rstat_id).hide() ;            
        }
    }
    
}

// -----------------------------------------------------------------------
// ON_CAT_CHANGE
// =============
// Called when the user enters a new string, this updates the local copies
// for valid values and updates (or adds) the type autocompleter.
// 
// The passed 'input' reers to the input tag for the category name, which
// has an id in the format rt-cat-<real-id>.
// 
// This relies on the various fields being named in a specific manner :-
//      input                           format 'rt-cat-rct-<id>' 
//      outputs from the main page
//          hidden cat text string      format 'rct-<id>-c'
//          hidden cat id value         format 'rct-<id>-cv'
//          hidden type text string     format 'rct-<id>-c'
//          hidden type id value        format 'rct-<id>-cv'
// 
//      outputs on the generated form
//          hidden cat id value         format 'rct-cat-<id>'
//          hidden type id value        format 'rct-type-<id>'
// 
// When called, 'this' refers to the input tag
// -----------------------------------------------------------------------
on_cat_change = function (input, value, data) {
    var parts = input.attr('id').split('-') ;
    var cat_id, type_name_id, type_name, types, t_name ;

    cat_id  = $('#' + parts.join('-') + '-id') ;
    parts[1] = 'type' ;
    type_name_id ='#' + parts.join('-') ;
    
    // -------------------------------------------------------------------
    // If an unrecognised string, colour the text red
    // -------------------------------------------------------------------
    if (!data) {
        $(type_name_id).css('color', 'red') ;
        
    } else {
        input.css('color', '') ;
        $(type_name_id).css('color', '') ;
        
        // data = data[0].data ;
        types = data.types ;
        
        // ---------------------------------------------------------------
        // If the category value has changed, check if the current name 
        // exists in the new type list.
        // ---------------------------------------------------------------
        if (data.id != $(cat_id).val()) {
            cat_id.val(data.id) ;

            type_name = $(type_name_id).val() ;
    
            matched = -1 ;
            
            // -----------------------------------------------------------
            // We check the name rather than the id in-case the same name
            // exists in multiple categories but with different ids
            // -----------------------------------------------------------
            for (var ind=0; ind < types.length; ind++) {
                if (type_name == types[ind].type) {
                    matched = ind ;
                    break ;
                }
            }

            // ---------------------------------------------------------------
            // If no matching name was found, colour the item red, else back to black.
            // ---------------------------------------------------------------
            if (matched < 0) {
                $(type_name_id).css('color', 'red') ;
                
            } else {
                $(type_name_id).css('color', '') ;
            }

        }
        // ---------------------------------------------------------------
        // ---------------------------------------------------------------
        // $(type_name_id).unautocomplete() ;
        $(type_name_id).autocomplete('option', 'source', types) ;
        // $(type_name_id).autocomplete(opts) ;
    }
}

// -----------------------------------------------------------------------
// 11 May 09 NW: Removed check for 1 entry long as this prevented us 
// returning an id value when the firstof multiple possible matches is
// selected
// -----------------------------------------------------------------------
on_type_change = function (input, value, data) {
    var type_id = $('#' + input.attr('id') + '-id') ;
    
    if (data) {
        input.css('color', '') ;
        // if (data.length == 1) {
            type_id.val(data.tid) ;
            
            var parts = input.attr('id').split('-') ;
            parts[1] = 'retest' ;
            $('#' + parts.join('-')).val(data.retest) ;
            parts[1] = 'al' ;
            $('#' + parts.join('-')).attr('checked', (data.autoa ? 'checked' : false)) ;
        // }
    } else {
        input.css('color', 'red') ;
        type_id.val('') ;
    }
}

function aprop_recstat(property_id, block) {
    $('input.rstat-email',  block).autocomplete(
                                    {
                                        source: '/proprst/' + property_id + '/propadd',
                                        matchContains: true,
    		                            parse: sp_parse,
                                        minLength : 0,
                                        max          : 0,                   // SHow all matches
		                            
                                        // matchSubset: sp_matchSubset,
                                        // formatItem:  sp_formatItem,                                    
                                        // formatMatch: sp_formatMatch,
                                
                                        open: function(event, ui) {
                                          $(".ui-autocomplete li.ui-menu-item:odd").addClass("ui-menu-item-alternate ac_odd");
                                        },

                                        select: function (event, ui) {
                                            var id = event.target.id ;
                                            $('#' + id + '-id').val(ui.item.id) ;
                                            $('#' + id + '-type').val(ui.item.type) ;

                                        }

                                        // selectable: function (row, input) {
                                        //     $('#' + input.id + '-id').val(row.data.id) ;
                                        //     $('#' + input.id + '-type').val(row.data.type) ;
                                        //     return true ;
                                        // }
                                    }) ;
    $('input.rstat-email',  block).data( "autocomplete" )._renderItem = function( ul, item ) {
                					return $( "<li></li>" )
                						.data( "item.autocomplete", item )
                						.append('<a>' + sp_formatItem(item) + '</a>')
                						.appendTo( ul )                                            
                            }
                                    
}
sp_matchSubset = function(s, sub, options) {
    s = s.value ;                   // Noel : Allow external versions to access any info

	if (!options.matchCase)
		s = s.toLowerCase();
	var i = s.indexOf(sub);
	if (i == -1) return false;
	return i == 0 || options.matchContains;
} ;

sp_formatItem = function(row) {                                		
    var lines = '<div class="srch_name">' + row.label + '</div>' ;
    if (row.company) {
        lines += '<p class="srch_client">' + row.company + '</p>';
    }

    var extra = '' ;
    if (row.image) {
        extra += row.image ;
    }
    if (row.subline) {
        extra += '<span class="srch_subl">'+ row.subline + '</span>' ;
    }
    if (row.desc) {
        extra += '<span class="srch_desc">'+ row.desc + '</span>' ;
    }
    if (extra) {
        lines += '<div class="srch-detail clearfix">' + extra + '</div>';
    }

	return lines ;
} ;

sp_formatMatch = function(row, i, max) {
    return row.name ;
} ;


function sp_parse (data) {
    var rows = data.split("\n");
    var index ;
	var parsed = [];

    for (var i=0; i < rows.length; i++) {
         var row = $.trim(rows[i]);
         if (row) {
             row = eval ('(' + row + ')') ;
             index = parsed.length ;
             parsed[index] = {} ;                 
             parsed[index].data     = row ;
             parsed[index].value    = row.company ;
             parsed[index].result   = row.company + ' (' + row.name + ')' ;
             parsed[index].data.name = row.company + 
                            (row.name ? ' <span class="srch_client">' + (row.jtitle ? row.jtitle + ': ' : '') + row.name + '</span>' : '') ;
         }
    }

	return parsed;
}


/*
 * jQuery.splitter.js - two-pane splitter window plugin
 *
 * version 1.51 (2009/01/09) 
 * 
 * Dual licensed under the MIT and GPL licenses: 
 *   http://www.opensource.org/licenses/mit-license.php 
 *   http://www.gnu.org/licenses/gpl.html 
 */

/**
 * The splitter() plugin implements a two-pane resizable splitter window.
 * The selected elements in the jQuery object are converted to a splitter;
 * each selected element should have two child elements, used for the panes
 * of the splitter. The plugin adds a third child element for the splitbar.
 * 
 * For more details see: http://methvin.com/splitter/
 *
 *
 * @example $('#MySplitter').splitter();
 * @desc Create a vertical splitter with default settings 
 *
 * @example $('#MySplitter').splitter({type: 'h', accessKey: 'M'});
 * @desc Create a horizontal splitter resizable via Alt+Shift+M
 *
 * @name splitter
 * @type jQuery
 * @param Object options Options for the splitter (not required)
 * @cat Plugins/Splitter
 * @return jQuery
 * @author Dave Methvin (dave.methvin@gmail.com)
 */
 ;(function($){
 
 $.fn.splitter = function(args){
	args = args || {};
	return this.each(function() {
		var zombie;		// left-behind splitbar for outline resizes
		function startSplitMouse(evt) {
			if ( opts.outline )
				zombie = zombie || bar.clone(false).insertAfter(A);
			panes.css("-webkit-user-select", "none");	// Safari selects A/B text on a move
			bar.addClass(opts.activeClass);
			A._posSplit = A[0][opts.pxSplit] - evt[opts.eventPos];
			$(document)
				.bind("mousemove", doSplitMouse)
				.bind("mouseup", endSplitMouse);
		}
		function doSplitMouse(evt) {
			var newPos = A._posSplit+evt[opts.eventPos];
			if ( opts.outline ) {
				newPos = Math.max(0, Math.min(newPos, splitter._DA - bar._DA));
				bar.css(opts.origin, newPos);
			} else 
				resplit(newPos);
		}
		function endSplitMouse(evt) {
			bar.removeClass(opts.activeClass);
			var newPos = A._posSplit+evt[opts.eventPos];
			if ( opts.outline ) {
				zombie.remove(); zombie = null;
				resplit(newPos);
			}
			panes.css("-webkit-user-select", "text");	// let Safari select text again
			$(document)
				.unbind("mousemove", doSplitMouse)
				.unbind("mouseup", endSplitMouse);
		}
		function resplit(newPos) {
			// Constrain new splitbar position to fit pane size limits
			newPos = Math.max(A._min, splitter._DA - B._max, 
					Math.min(newPos, A._max, splitter._DA - bar._DA - B._min));
			// Resize/position the two panes
			bar._DA = bar[0][opts.pxSplit];		// bar size may change during dock
			bar.css(opts.origin, newPos).css(opts.fixed, splitter._DF);
			A.css(opts.origin, 0).css(opts.split, newPos).css(opts.fixed,  splitter._DF);
			B.css(opts.origin, newPos+bar._DA)
				.css(opts.split, splitter._DA-bar._DA-newPos).css(opts.fixed,  splitter._DF);
			// IE fires resize for us; all others pay cash
			if ( !$.browser.msie )
				panes.trigger("resize");
		}
		function dimSum(jq, dims) {
			// Opera returns -1 for missing min/max width, turn into 0
			var sum = 0;
			for ( var i=1; i < arguments.length; i++ )
				sum += Math.max(parseInt(jq.css(arguments[i])) || 0, 0);
			return sum;
		}
		
		// Determine settings based on incoming opts, element classes, and defaults
		var vh = (args.splitHorizontal? 'h' : args.splitVertical? 'v' : args.type) || 'v';
		var opts = $.extend({
			activeClass: 'active',	// class name for active splitter
			pxPerKey: 8,			// splitter px moved per keypress
			tabIndex: 0,			// tab order indicator
			accessKey: '',			// accessKey for splitbar
			anchoring: false,
			resizeing: false
			
		},{
			v: {					// Vertical splitters:
				keyLeft: 39, keyRight: 37, cursor: "e-resize",
				splitbarClass: "vsplitbar", outlineClass: "voutline",
				type: 'v', eventPos: "pageX", origin: "left",
				split: "width",  pxSplit: "offsetWidth",  side1: "Left", side2: "Right",
				fixed: "height", pxFixed: "offsetHeight", side3: "Top",  side4: "Bottom"
			},
			h: {					// Horizontal splitters:
				keyTop: 40, keyBottom: 38,  cursor: "n-resize",
				splitbarClass: "hsplitbar", outlineClass: "houtline",
				type: 'h', eventPos: "pageY", origin: "top",
				split: "height", pxSplit: "offsetHeight", side1: "Top",  side2: "Bottom",
				fixed: "width",  pxFixed: "offsetWidth",  side3: "Left", side4: "Right"
			}
		}[vh], args);

		// Create jQuery object closures for splitter and both panes
		var splitter = $(this).css({position: "relative"});
		var panes = $(">*", splitter[0]).css({
			position: "absolute", 			// positioned inside splitter container
			"z-index": "1",					// splitbar is positioned above
			"-moz-outline-style": "none"	// don't show dotted outline
		});
		var A = $(panes[0]);		// left  or top
		var B = $(panes[1]);		// right or bottom

		// Focuser element, provides keyboard support; title is shown by Opera accessKeys
		var focuser = $('<a href="javascript:void(0)"></a>')
			.attr({accessKey: opts.accessKey, tabIndex: opts.tabIndex, title: opts.splitbarClass})
			.bind($.browser.opera?"click":"focus", function(){ this.focus(); bar.addClass(opts.activeClass) })
			.bind("keydown", function(e){
				var key = e.which || e.keyCode;
				var dir = key==opts["key"+opts.side1]? 1 : key==opts["key"+opts.side2]? -1 : 0;
				if ( dir )
					resplit(A[0][opts.pxSplit]+dir*opts.pxPerKey, false);
			})
			.bind("blur", function(){ bar.removeClass(opts.activeClass) });
			
		// Splitbar element, can be already in the doc or we create one
		var bar = $(panes[2] || '<div></div>')
			.insertAfter(A).css("z-index", "100").append(focuser)
			.attr({"class": opts.splitbarClass, unselectable: "on"})
			.css({position: "absolute",	"user-select": "none", "-webkit-user-select": "none",
				"-khtml-user-select": "none", "-moz-user-select": "none"})
			.bind("mousedown", startSplitMouse);
		// Use our cursor unless the style specifies a non-default cursor
		if ( /^(auto|default|)$/.test(bar.css("cursor")) )
			bar.css("cursor", opts.cursor);

		// Cache several dimensions for speed, rather than re-querying constantly
		bar._DA = bar[0][opts.pxSplit];
		splitter._PBF = $.boxModel? dimSum(splitter, "border"+opts.side3+"Width", "border"+opts.side4+"Width") : 0;
		splitter._PBA = $.boxModel? dimSum(splitter, "border"+opts.side1+"Width", "border"+opts.side2+"Width") : 0;
		A._pane = opts.side1;
		B._pane = opts.side2;
		$.each([A,B], function(){
			this._min = opts["min"+this._pane] || dimSum(this, "min-"+opts.split);
			this._max = opts["max"+this._pane] || dimSum(this, "max-"+opts.split) || 9999;
			this._init = opts["size"+this._pane]===true ?
				parseInt($.curCSS(this[0],opts.split)) : opts["size"+this._pane];
		});
		
		// Determine initial position, get from cookie if specified
		var initPos = A._init;
		if ( !isNaN(B._init) )	// recalc initial B size as an offset from the top or left side
			initPos = splitter[0][opts.pxSplit] - splitter._PBA - B._init - bar._DA;
		if ( opts.cookie ) {
			if ( !$.cookie )
				alert('jQuery.splitter(): jQuery cookie plugin required');
			var ckpos = parseInt($.cookie(opts.cookie));
			if ( !isNaN(ckpos) )
				initPos = ckpos;
			$(window).bind("unload", function(){
				var state = String(bar.css(opts.origin));	// current location of splitbar
				$.cookie(opts.cookie, state, {expires: opts.cookieExpires || 365, 
					path: opts.cookiePath || document.location.pathname});
			});
		}
		if ( isNaN(initPos) )	// King Solomon's algorithm
			initPos = Math.round((splitter[0][opts.pxSplit] - splitter._PBA - bar._DA)/2);

		// Resize event propagation and splitter sizing
		if ( opts.anchorToWindow && !opts.anchoring) {
			// Account for margin or border on the splitter container and enforce min height
			splitter._hadjust = dimSum(splitter, "borderTopWidth", "borderBottomWidth", "marginBottom");
			splitter._hmin = Math.max(dimSum(splitter, "minHeight"), 20);
			$(window).bind("resize", function(){
			    if (!opts.anchoring) {
    			    opts.anchoring = true ;
    				var top = splitter.offset().top;
    				var wh = $(window).height();
    				splitter.css("height", Math.max(wh-top-splitter._hadjust, splitter._hmin)+"px");
    				if ( !$.browser.msie ) splitter.trigger("resize");
    			    opts.anchoring = false ;
                }
			}).trigger("resize");
		}
		else if ( opts.resizeToWidth && !$.browser.msie )
			$(window).bind("resize", function(){
				splitter.trigger("resize"); 
			});

		// Resize event handler; triggered immediately to set initial position
		splitter.bind("resize", function(e, size){
			// Custom events bubble in jQuery 1.3; don't Yo Dawg
			if ( e.target != this || opts.resizeing) return;
			opts.resizeing = true ;
			// Determine new width/height of splitter container
			splitter._DF = splitter[0][opts.pxFixed] - splitter._PBF;
			splitter._DA = splitter[0][opts.pxSplit] - splitter._PBA;
			// Bail if splitter isn't visible or content isn't there yet
			if ( splitter._DF <= 0 || splitter._DA <= 0 ) return;
			// Re-divvy the adjustable dimension; maintain size of the preferred pane
			resplit(!isNaN(size)? size : (!(opts.sizeRight||opts.sizeBottom)? A[0][opts.pxSplit] :
				splitter._DA-B[0][opts.pxSplit]-bar._DA));
			opts.resizeing = false ;
		}).trigger("resize" , [initPos]);
	});
};

})(jQuery);

/*
 * nyroModal - jQuery Plugin
 * http://nyromodal.nyrodev.com
 *
 * Copyright (c) 2008 Cedric Nirousset (nyrodev.com)
 * Licensed under the MIT license
 *
 * $Date: 2008-06-24 (Tue, 24 Jun 2008) $
 * $version: 1.2.8
 */
jQuery(function($) {

	// -------------------------------------------------------
	// Private Variables
	// -------------------------------------------------------
	
	var isIE6 = ($.browser.msie && parseInt($.browser.version.substr(0,1)) < 7);
	var body = $('body');
	
	var currentSettings;
	
	// To know if the fix for the Issue 10 should be applied (or has been applied)
	var fixFF = false;
	
	// Used for retrieve the content from an hidden div
	var contentElt;
	var contentEltLast;
	
	// Contains info about nyroModal state and all div references
	var modal = {
		ready: false,
		dataReady: false,
		anim: false,
		loadingShown: false,
		transition: false,
		error: false,
		full: null,
		bg: null,
		loading: null,
		tmp: null,
		content: null,
		wrapper: null,
		contentWrapper: null,
		scripts: new Array()
	};
	
	// Indicate of the height or the width was resized, to reinit the currentsettings related to null
	var resized = {
		width: false,
		height: false
	};
	
	// -------------------------------------------------------
	// Public function
	// -------------------------------------------------------
	
	// jQuery extension function. A paramater object could be used to overwrite the default settings
	$.fn.nyroModal = function(settings) {
		if (!this)
			return false;
		return this.each(function(){
			if (this.nodeName.toLowerCase() == 'form') {
				$(this).submit(function(e) {
					if (this.enctype == 'multipart/form-data') {
						processModal($.extend(settings, {
							from: this
						}));
						return true;
					}
					e.preventDefault();
					processModal($.extend(settings, {
						from: this
					}));
					return false;
				});
			} else {
				$(this).click(function(e) {
					e.preventDefault();
					processModal($.extend(settings, {
						from: this
					}));
					return false;
				});
			}
		});
	};
	
	// jQuery extension function to call manually the modal. A paramater object could be used to overwrite the default settings
	$.fn.nyroModalManual = function(settings) {
		if (!this.length)
			processModal(settings);
		return this.each(function(){
			processModal($.extend(settings, {
				from: this
			}));
		});
	};
	
	$.nyroModalManual = function(settings) {
		processModal(settings);
	};
	
	// Update the current settings
	// object settings
	// string deep1 first key where overwrite the settings
	// string deep2 second key where overwrite the settings
	$.nyroModalSettings = function(settings, deep1, deep2) {
		setCurrentSettings(settings, deep1, deep2);
		if (!deep1 && modal.ready) {
			if (settings.bgColor)
				currentSettings.updateBgColor(modal, currentSettings, function(){});
			
			if ((modal.dataReady && !modal.anim && !modal.transition) && (settings.width || settings.height)) {
				calculateSize(true);
				
				if (fixFF)
					modal.content.css({position: ''});
				currentSettings.resize(modal, currentSettings, function() {
					if (fixFF)
						modal.content.css({position: 'fixed'});
					if ($.isFunction(currentSettings.endResize))
						currentSettings.endResize(modal, currentSettings);
				});
			}
		}
	};
	
	// Remove the modal function
	$.nyroModalRemove = function() {
		removeModal();
	};
	
	// Go to the next image for a gallery
	// return false if nothing was done
	$.nyroModalNext = function() {
		if (currentSettings.type == 'gallery') {
			var gallery = $('[rel="'+currentSettings.from.rel+'"]');
			var currentIndex = gallery.index(currentSettings.from);
			if (currentIndex < gallery.length-1) {
				return gallery.eq(currentIndex+1).nyroModalManual(currentSettings);
			}
		}
		return false;
	};
	
	// Go to the previous image for a gallery
	// return false if nothing was done
	$.nyroModalPrev = function() {
		if (currentSettings.type == 'gallery') {
			var gallery = $('[rel="'+currentSettings.from.rel+'"]');
			var currentIndex = gallery.index(currentSettings.from);
			if (currentIndex > 0) {
				return gallery.eq(currentIndex-1).nyroModalManual(currentSettings);
			}
		}
		return false;
	};

	
	// -------------------------------------------------------
	// Default Settings
	// -------------------------------------------------------
	
	$.fn.nyroModal.settings = {
		debug: false, // Show the debug in the background
		
		modal: false, // Esc key or click backgrdound enabling or not
	
		type: '', // nyroModal type (form, formData, iframe, image, etc...)
		from: '', // Dom object where the call come from
		hash: '', // Eventual hash in the url
		
		processHandler: null, // Handler just before the real process
		
		selIndicator: 'nyroModalSel', // Value added when a form or Ajax is sent with a filter content
		
		formIndicator: 'nyroModal', // Value added when a form is sent
		
		content: null, // Raw content if type content is used

		bgColor: '#000000', // Background color
		
		ajax: {}, // Ajax option (url, data, type, success will be overwritten for a form, url and success only for an ajax call)
		
		width: null, // default Width If null, will be calculate automatically
		height: null, // default Height If null, will be calculate automatically
		
		minWidth: 400, // Minimum width
		minHeight: 300, // Minimum height
		
		resizeable: true, // Indicate if the content is resizable. Will be set to false for swf
		autoSizable: true, // Indicate if the content is auto sizable. If not, the min size will be used
		
		padding: 20, // padding for the max modal size
		
		extImg: 'jpg|jpeg|png|tiff|gif|bmp', // Images extensions seperate by | (regexp using)
		defaultImgAlt: 'Image', // Default alt attribute for the images
		setWidthImgTitle: true, // Set the width to the image title
		
		css: { // Default CSS option for the nyroModal Div. Some will be overwritten or updated when using IE6
			bg: {
				zIndex: 100,
				position: 'fixed',
				top: 0,
				left: 0,
				height: '100%',
				width: '100%'
			},
			wrapper: {
				zIndex: 101,
				position: 'fixed',
				top: '50%',
				left: '50%'
			},
			wrapper2: {
			},
			content: {
				overflow: 'auto'
			},
			loading: {
				zIndex: 102,
				position: 'fixed',
				top: '50%',
				left: '50%',
				marginTop: '-50px',
				marginLeft: '-50px'
			}
		},
		
		wrap: { // Wrapper div used to style the modal regarding the content type
			div: '<div class="wrapper"></div>',
			ajax: '<div class="wrapper"></div>',
			form: '<div class="wrapper"></div>',
			formData: '<div class="wrapper"></div>',
			image: '<div class="wrapperImg"></div>',
			gallery: '<div class="wrapperImg"><a href="#" class="nyroModalPrev">Prev</a><a href="#"  class="nyroModalNext">Next</a></div>', // Use .nyroModalPrev and .nyroModalNext to set the navigation link
			swf: '<div class="wrapperSwf"></div>',
			iframe: '<div class="wrapperIframe"></div>',
			manual: '<div class="wrapper"></div>'
		},
		
		closeButton: '<a href="#" class="nyroModalClose" id="closeBut" title="close">Close</a>', // Adding automaticly as the first child of #nyroModalWrapper 
		
		openSelector: '.nyroModal', // selector for open a new modal. will be used to parse automaticly at page loading
		closeSelector: '.nyroModalClose', // selector to close the modal
		
		contentLoading: '<a href="#" class="nyroModalClose">Cancel</a>', // Loading div content
		
		errorClass: 'error', // CSS Error class added to the loading div in case of error
		contentError: 'The requested content cannot be loaded.<br />Please try again later.<br /><a href="#" class="nyroModalClose">Close</a>', // Content placed in the loading div in case of error 
	
		handleError: null, // Callback in case of error
		
		showBackground: showBackground, // Show background animation function
		hideBackground: hideBackground, // Hide background animation function
		
		endFillContent: null, // Will be called after filling and wraping the content, before parsing closeSelector and openSelector and showing the content
		showContent: showContent, // Show content animation function
		endShowContent: null, // Will be called once the content is shown
		hideContent: hideContent, // Hide content animation function
		
		showTransition: showTransition, // Show the transition animation (a modal is already shown and a new one is requested)
		hideTransition: hideTransition, // Hide the transition animation to show the content
		
		showLoading: showLoading, // show loading animation function
		hideLoading: hideLoading, // hide loading animation function
		
		resize: resize, // Resize animation function
		endResize: null, // Will be called one the content is resized
		
		updateBgColor: updateBgColor, // Change background color animation function
		
		endRemove: null // Will be called once the modal is totally gone
	};

	
	// -------------------------------------------------------
	// Private function
	// -------------------------------------------------------
	
	// Main function
	function processModal(settings) {
		if (modal.loadingShown || modal.transition || modal.anim)
			return;
		debug('processModal');
		setDefaultCurrentSettings(settings);
		modal.error = false;
		modal.dataReady = false;
		modal.scripts = new Array();
		
		currentSettings.type = fileType();
		
		if ($.isFunction(currentSettings.processHandler))
			currentSettings.processHandler(currentSettings);

		from = currentSettings.from;
		
		if (currentSettings.type == 'swf') {
			// Swf is transforming as a raw content
			currentSettings.resizable = false;
			currentSettings.content = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="'+currentSettings.width+'" height="'+currentSettings.height+'"><param name="movie" value="'+currentSettings.url+'"></param><param name="wmode" value="transparent"></param><embed src="'+currentSettings.url+'" type="application/x-shockwave-flash" wmode="transparent" width="'+currentSettings.width+'" height="'+currentSettings.height+'"></embed></object>';
		}
		
		if (from) {
			if (currentSettings.type == 'form') {
				currentSettings.selector = getHash(from.action);
				var url = from.action.substring(0, from.action.length-currentSettings.selector.length);
				var data = $(from).serializeArray();
				data.push({name: currentSettings.formIndicator, value: 1});
				if (currentSettings.selector)
					data.push({name: currentSettings.selIndicator, value: currentSettings.selector.substring(1)});
				$.ajax($.extend({}, currentSettings.ajax, {
						url: url,
						data: data,
						type: from.method,
						success: ajaxLoaded,
						error: loadingError
					}));
				debug('Form Ajax Load: '+from.action);
				showModal();
			} else if (currentSettings.type == 'formData') {
				// Form with data. We're using a hidden iframe
				initModal();
				from.target = 'nyroModalIframe';
				currentSettings.selector = getHash(from.action);
				var url = from.action.substring(0, from.action.length - currentSettings.selector.length);
				from.action = url;
				$(from).prepend('<input type="hidden" name="'+currentSettings.formIndicator+'" value="1" />');
				if (currentSettings.selector)
					$(from).prepend('<input type="hidden" name="'+currentSettings.selIndicator+'" value="'+currentSettings.selector.substring(1)+'" />');
				modal.tmp.html('<iframe frameborder="0" hspace="0" name="nyroModalIframe"></iframe>');
				$('iframe', modal.tmp)
					.css({
						width: currentSettings.width,
						height: currentSettings.height
					})
					.error(loadingError)
					.load(formDataLoaded);
				debug('Form Data Load: '+from.action);
				showModal();
				showContentOrLoading();
			} else if (currentSettings.type == 'image' || currentSettings.type == 'gallery') {
				var title = from.title || currentSettings.defaultImgAlt;
				initModal();
				modal.tmp.html('<img id="nyroModalImg" alt="'+title+'" />');
				debug('Image Load: '+from.href);
				$('img', modal.tmp)
					.error(loadingError)
					.load(function() {
						debug('Image Loaded: '+this.src);
						$(this).unbind('load');
						var w = modal.tmp.width();
						var h = modal.tmp.height();
						setCurrentSettings({
							width: w,
							height: h,
							imgWidth: w,
							imgHeight: h
						});
						modal.dataReady = true;
						if (modal.loadingShown || modal.transition)
							showContentOrLoading();
					})
					.attr('src', from.href);
				showModal();
			} else if (currentSettings.type == 'iframe') {
				initModal();
				modal.tmp.html('<iframe frameborder="0" hspace="0" src="'+from.href+'" name="nyroModalIframe"></iframe>');
				debug('Iframe Load: '+from.href);
				$('iframe', modal.tmp).eq(0)
					.css({
						width: '100%',
						height: '100%'
					});
				currentSettings.autoSizable = false;
				modal.dataReady = true;
				showModal();
			} else if (currentSettings.type) {
				// Could be every other kind of type or a dom selector
				debug('Content: '+currentSettings.type);
				initModal();
				modal.tmp.html(currentSettings.content);
				var w = modal.tmp.width();
				var h = modal.tmp.height();
				var div = $(currentSettings.type);
				if (div.length) {
					setCurrentSettings({type: 'div'});
					w = div.width();
					h = div.height();
					if (contentElt)
						contentEltLast = contentElt;
					contentElt = div;
					modal.tmp.append(div.contents());
				}
				setCurrentSettings({
					width: w,
					height: h
				});
				if (modal.tmp.html())
					modal.dataReady = true;
				else
					loadingError();
				showModal();
				showContentOrLoading();
			} else {
				debug('Ajax Load: '+currentSettings.url);
				setCurrentSettings({type: 'ajax'});
				var data = {};
				if (currentSettings.selector) {
					data = currentSettings.ajax.data || {};
					data[currentSettings.selIndicator] = currentSettings.selector.substring(1);
				}
				$.ajax($.extend({}, currentSettings.ajax, {
					url: currentSettings.url.substring(0, currentSettings.url.length-currentSettings.selector.length),
					success: ajaxLoaded,
					error: loadingError,
					data: data
				}));
				showModal();
			}
		} else if (currentSettings.content) {
			// Raw content not from a DOM element
			debug('Content: '+currentSettings.type);
			setCurrentSettings({type: 'manual'});
			initModal();
			modal.tmp.html($('<div/>').html(currentSettings.content).contents());
			if (modal.tmp.html())
				modal.dataReady = true;
			else
				loadingError();
			showModal();
		} else {
			// What should we show here? nothing happen
		}
	}
	
	// Update the current settings
	// object settings
	// string deep1 first key where overwrite the settings
	// string deep2 second key where overwrite the settings
	function setDefaultCurrentSettings(settings) {
		debug('setDefaultCurrentSettings');
		currentSettings = $.extend({}, $.fn.nyroModal.settings, settings);
		currentSettings.selector = '',
		currentSettings.borderW = 0,
		currentSettings.borderH = 0,
		currentSettings.resizable = true;
		setMargin();
	}
	
	function setCurrentSettings(settings, deep1, deep2) {
		if (deep1 && deep2) {
			$.extend(currentSettings[deep1][deep2], settings);
		} else if (deep1) {
			$.extend(currentSettings[deep1], settings);
		} else {
			$.extend(currentSettings, settings);
		}
	}

	// Set the margin for postionning the element. Useful for IE6
	function setMarginScroll() {
		if (isIE6) {
			if (document.documentElement) {
				currentSettings.marginScrollLeft = document.documentElement.scrollLeft;
				currentSettings.marginScrollTop = document.documentElement.scrollTop;
			} else {
				currentSettings.marginScrollLeft = document.body.scrollLeft;
				currentSettings.marginScrollTop = document.body.scrollTop;
			}
		} else {
			currentSettings.marginScrollLeft = 0;
			currentSettings.marginScrollTop = 0;
		}
	}
	
	// Set the margin for the content
	function setMargin() {
		setMarginScroll();
		currentSettings.marginLeft = -(currentSettings.width+currentSettings.borderW)/2 + currentSettings.marginScrollLeft;
		currentSettings.marginTop = -(currentSettings.height+currentSettings.borderH)/2 + currentSettings.marginScrollTop;
	}
	
	// Init the nyroModal div by settings the CSS elements and hide needed elements
	function initModal() {
		debug('initModal');
		if (!modal.full) {
			if (currentSettings.debug)
				setCurrentSettings({color: 'white'}, 'css', 'bg');
		
			var iframeHideIE = '';
			if (isIE6) {
				body.css({
					height: body.height()+'px',
					width: body.width()+'px',
					position: 'static',
					overflow: 'hidden'});
				$('html').css({overflow: 'hidden'});
				setCurrentSettings({
					position: 'absolute',
					height: '110%',
					width: '110%',
					top: currentSettings.marginScrollTop+'px',
					left: currentSettings.marginScrollLeft+'px'
				}, 'css', 'bg');
				
				setCurrentSettings({position: 'absolute'}, 'css', 'loading');
				setCurrentSettings({position: 'absolute'}, 'css', 'wrapper');
				
				iframeHideIE = $('<iframe id="nyroModalIframeHideIe"></iframe>')
								.css($.extend({},
									currentSettings.css.bg, {
										opacity: 0,
										zIndex: 50,
										border: 'none'
									}));
			}
		
			body.append($('<div id="nyroModalFull"><div id="nyroModalBg"></div><div id="nyroModalWrapper"><div id="nyroModalContent"></div></div><div id="nyrModalTmp"></div><div id="nyroModalLoading"></div></div>').hide());
			
			modal.full = $('#nyroModalFull').show();
			modal.bg = $('#nyroModalBg')
				.css($.extend({
						backgroundColor: currentSettings.bgColor
					}, currentSettings.css.bg))
				.before(iframeHideIE);
			if (!currentSettings.modal)
				modal.bg.click(removeModal);
			modal.loading = $('#nyroModalLoading')
				.css(currentSettings.css.loading)
				.hide();
			modal.contentWrapper = $('#nyroModalWrapper')
				.css(currentSettings.css.wrapper)
				.hide();
			modal.content = $('#nyroModalContent');
			modal.tmp = $('#nyrModalTmp').hide();
			
			// To stop the mousewheel if the the plugin is available
			if ($.isFunction($.fn.mousewheel)) {
				modal.content.mousewheel(function(e, d) {
					var elt = modal.content.get(0);
					if ((d > 0 && elt.scrollTop == 0) ||
							(d < 0 && elt.scrollHeight - elt.scrollTop == elt.clientHeight)) {
						e.preventDefault();
						e.stopPropagation();
					}
				});
			}
			
			$(document).keydown(keyHandler);
			modal.content.css({width: 'auto', height: 'auto'});
			modal.contentWrapper.css({width: 'auto', height: 'auto'});
		}
	}
	
	// Show the modal (ie: the background and then the loading if needed or the content directly)
	function showModal() {
		debug('showModal');
		if (!modal.ready) {
			initModal();
			modal.anim = true;
			currentSettings.showBackground(modal, currentSettings, endBackground);
		} else {
			modal.anim = true;
			modal.transition = true;
			currentSettings.showTransition(modal, currentSettings, function(){endHideContent();modal.anim=false;showContentOrLoading();});
		}
	}
	
	// Used for the escape key or the arrow in the gallery type
	function keyHandler(e) {
		if (e.keyCode == 27) {
			if (!currentSettings.modal)
				removeModal();
		} else if (currentSettings.type == 'gallery' && modal.ready && modal.dataReady && !modal.anim && !modal.transition) {
			if (e.keyCode == 39 || e.keyCode == 40) {
				e.preventDefault();
				$('.nyroModalNext', modal.content).eq(0).trigger('click');
				return false;
			} else if (e.keyCode == 37 || e.keyCode == 38) {
				e.preventDefault();
				$('.nyroModalPrev', modal.content).eq(0).trigger('click');
				return false;
			}
		}
	}
	
	// Determine the filetype regarding the link DOM element
	function fileType() {
		var from = currentSettings.from;
		
		var url = currentSettings.url;
		
		if (from && from.nodeName) {
			if (from.nodeName.toLowerCase() == 'form') {
				if (from.enctype == 'multipart/form-data')
					return 'formData';
				return 'form';
			}
			
			if (from.rev == 'modal')
				currentSettings.modal = true;
			
			var image = new RegExp('[^\.]\.('+currentSettings.extImg+')\s*$', 'i');
			if (image.test(from.href)) {
				if (from.rel)
					return 'gallery';
				else
					return 'image';
			}
			
			var swf = new RegExp('[^\.]\.(swf)\s*$', 'i');
			if (swf.test(from.href))
				return 'swf';
			
			if (from.target.toLowerCase() == '_blank' || (from.hostname.replace(/:\d*$/,'') != window.location.hostname.replace(/:\d*$/,'')))
				return 'iframe';
			
			url = from.href;
		}
		
		if (url) {
			if (from)
				currentSettings.url = url;
			else
				currentSettings.from = true;
			var hash = getHash(url);
			var hashLoc = getHash(window.location.href);
			var curLoc = window.location.href.substring(0, window.location.href.length - hashLoc.length);
			var req = url.substring(0, url.length - hash.length);
			
			if (req == curLoc)
				return hash;
			else
				currentSettings.selector = hash;
		}
	}

	// Called when the content cannot be loaded or tiemout reached
	function loadingError() {
		debug('loadingError');
		
		modal.error = true;
		
		if (!modal.ready)
			return;
		
		if ($.isFunction(currentSettings.handleError))
			currentSettings.handleError(modal, currentSettings);
		
		modal.loading
			.addClass(currentSettings.errorClass)
			.html(currentSettings.contentError);
		$(currentSettings.closeSelector, modal.loading).click(removeModal);
	}
	
	// Put the content from modal.tmp to modal.content
	function fillContent() {
		debug('fillContent');
		if (!modal.tmp.html())
			return;
		
		modal.content.html(modal.tmp.contents());
		modal.tmp.empty();
		wrapContent();
		
		if ($.isFunction(currentSettings.endFillContent))
			currentSettings.endFillContent(modal, currentSettings);
		
		modal.content.append(modal.scripts);
		
		var currentSettingsNew = $.extend({}, currentSettings);
		if (resized.width)
			currentSettingsNew.width = null;
		if (resized.height)
			currentSettingsNew.height = null;
		$(currentSettings.closeSelector, modal.contentWrapper).click(removeModal);
		$(currentSettings.openSelector, modal.contentWrapper).nyroModal(currentSettingsNew);
	}
	
	// Wrap the content and update the modal size if needed
	function wrapContent() {
		debug('wrapContent');
		
		var wrap = $(currentSettings.wrap[currentSettings.type]);
		modal.content.append(wrap.children().remove());
		modal.contentWrapper.wrapInner(wrap);
		
		if (currentSettings.type == 'gallery') {
			// Set the action for the next and prev button (or remove them)
			var gallery = $('[rel="'+currentSettings.from.rel+'"]');
			var currentIndex = gallery.index(currentSettings.from);
			if (currentIndex > 0) {
				var linkPrev = gallery.eq(currentIndex-1);
				$('.nyroModalPrev', modal.contentWrapper)
					.attr('href', linkPrev.attr('href'))
					.click(function(e) {
						e.preventDefault();
						linkPrev.nyroModalManual(currentSettings);
						return false;
					});
			} else {
				$('.nyroModalPrev', modal.contentWrapper).remove();
			}
			if (currentIndex < gallery.length-1) {
				var linkNext = gallery.eq(currentIndex+1);
				$('.nyroModalNext', modal.contentWrapper)
					.attr('href', linkNext.attr('href'))
					.click(function(e) {
						e.preventDefault();
						linkNext.nyroModalManual(currentSettings);
						return false;
					});
			} else {
				$('.nyroModalNext', modal.contentWrapper).remove();
			}
		}
		
		calculateSize();
	}
	
	// Calculate the size for the contentWrapper
	function calculateSize(resizing) {
		debug('calculateSize');
		
		if (!modal.wrapper)
			modal.wrapper = modal.contentWrapper.children(':first');
		
		resized.width = false;
		resized.height = false;
		if (currentSettings.autoSizable && (!currentSettings.width || !currentSettings.height)) {
			modal.contentWrapper.css({opacity: 0}).show();
			var tmp = {
				width: 'auto',
				height: 'auto'
			};
			if (currentSettings.width)
				tmp.width = currentSettings.width;
			if (currentSettings.height)
				tmp.height = currentSettings.height;
			modal.content.css(tmp);
			if (!currentSettings.width) {
				currentSettings.width = modal.content.width();
				resized.width = true;
			}
			if (!currentSettings.height) {
				currentSettings.height = modal.content.height();
				resized.height = true;
			}
			modal.contentWrapper.hide().css({opacity: 1});
		}
		
		currentSettings.width = Math.max(currentSettings.width, currentSettings.minWidth);
		currentSettings.height = Math.max(currentSettings.height, currentSettings.minHeight);
		
		var outerWrapper = getOuter(modal.contentWrapper);
		var outerWrapper2 = getOuter(modal.wrapper);
		var outerContent = getOuter(modal.content);
		
		var tmp = {
			content: {
				width: currentSettings.width,
				height: currentSettings.height
			},
			wrapper2: {
				width: currentSettings.width + outerContent.w.total,
				height: currentSettings.height + outerContent.h.total
			},
			wrapper: {
				width: currentSettings.width + outerContent.w.total + outerWrapper2.w.total,
				height: currentSettings.height + outerContent.h.total + outerWrapper2.h.total
			}
		};
		
		if (currentSettings.resizable) {
			var maxHeight = $(window).height()
					- currentSettings.padding*2
					- outerWrapper.h.border
					- (tmp.wrapper.height - currentSettings.height);
			var maxWidth = $(window).width()
					- currentSettings.padding*2
					- outerWrapper.w.border
					- (tmp.wrapper.width - currentSettings.width);
			
			if (tmp.content.height > maxHeight || tmp.content.width > maxWidth) {
				// We're gonna resize the modal as it will goes outside the view port
				if (currentSettings.type == 'image' || currentSettings.type == 'gallery') {
					// An image is resized proportionnaly
					var diffW = tmp.content.width - currentSettings.imgWidth;
					var diffH = tmp.content.height - currentSettings.imgHeight;
						if (diffH < 0) diffH = 0;
						if (diffW < 0) diffW = 0;
					var calcH = maxHeight - diffH;
					var calcW = maxWidth - diffW;
					var ratio = Math.min(calcH/currentSettings.imgHeight, calcW/currentSettings.imgWidth);
					
					calcH = Math.floor(currentSettings.imgHeight*ratio);
					calcW = Math.floor(currentSettings.imgWidth*ratio);
					$('img#nyroModalImg', modal.content).css({
						height: calcH+'px',
						width: calcW+'px'
					});
					tmp.content.height = calcH + diffH;
					tmp.content.width = calcW + diffW;
				} else {
					// For an HTML content, we simply decrease the size
					tmp.content.height = Math.min(tmp.content.height, maxHeight);
					tmp.content.width = Math.min(tmp.content.width, maxWidth);
				}
				tmp.wrapper2 = {
						width: tmp.content.width + outerContent.w.total,
						height: tmp.content.height + outerContent.h.total
					};
				tmp.wrapper = {
						width: tmp.content.width + outerContent.w.total + outerWrapper2.w.total,
						height: tmp.content.height + outerContent.h.total + outerWrapper2.h.total
					};
			}
		}
		
		modal.content.css($.extend({}, tmp.content, currentSettings.css.content));
		modal.wrapper.css($.extend({}, tmp.wrapper2, currentSettings.css.wrapper2));
		
		if (!resizing) {
			modal.contentWrapper.css($.extend({}, tmp.wrapper, currentSettings.css.wrapper));
			if (currentSettings.type == 'image' || currentSettings.type == 'gallery') {
				// Adding the title for the image
				var title = $('img', modal.content).attr('alt');
				$('img', modal.content).removeAttr('alt');
				if (title != currentSettings.defaultImgAlt) {
					var divTitle = $('<div>'+title+'</div>');
					modal.content.append(divTitle);
					if (currentSettings.setWidthImgTitle) {
						var outerDivTitle = getOuter(divTitle);
						divTitle.css({width: (tmp.content.width + outerContent.w.padding - outerDivTitle.w.total)+'px'});
					}
				}
			}
			
			if (!currentSettings.modal)
				modal.contentWrapper.prepend(currentSettings.closeButton);
		}
		tmp.wrapper.borderW = outerWrapper.w.border;
		tmp.wrapper.borderH = outerWrapper.h.border;
		
		setCurrentSettings(tmp.wrapper);
		setMargin();
	}
	
	function removeModal(e) {
		debug('removeModal');
		if (e)
			e.preventDefault();
		if (modal.full && modal.ready) {
			modal.ready = false;
			modal.anim = true;
			if (modal.loadingShown || modal.transition) {
				currentSettings.hideLoading(modal, currentSettings, function() {
						modal.loading.hide();
						modal.loadingShown = false;
						modal.transition = false;
						currentSettings.hideBackground(modal, currentSettings, endRemove);
					});
			} else {
				if (fixFF)
					modal.content.css({position: ''}); // Fix Issue #10, remove the attribute
				modal.wrapper.css({overflow: 'hidden'}); // Used to fix a visual issue when hiding
				modal.content.css({overflow: 'hidden'}); // Used to fix a visual issue when hiding
				currentSettings.hideContent(modal, currentSettings, function() {
						endHideContent();
						currentSettings.hideBackground(modal, currentSettings, endRemove);
					});
			}
		}
		if (e)
			return false;
	}
	
	function showContentOrLoading() {
		debug('showContentOrLoading');
		if (modal.ready && !modal.anim) {
			if (modal.dataReady) {
				if (modal.tmp.html()) {
					modal.anim = true;
					if (modal.transition) {
						fillContent();
						currentSettings.hideTransition(modal, currentSettings, function() {
							modal.loading.hide();
							modal.transition = false;
							modal.loadingShown = false;
							endShowContent();
						});
					} else {
						currentSettings.hideLoading(modal, currentSettings, function() {
								modal.loading.hide();
								modal.loadingShown = false;
								fillContent();
								currentSettings.showContent(modal, $.extend({}, currentSettings), endShowContent);
							});
					}
				}
			} else if (!modal.loadingShown && !modal.transition) {
				modal.anim = true;
				modal.loadingShown = true;
				if (modal.error)
					loadingError();
				else
					modal.loading.html(currentSettings.contentLoading);
				$(currentSettings.closeSelector, modal.loading).click(removeModal);
				currentSettings.showLoading(modal, currentSettings, function(){modal.anim=false;showContentOrLoading();});
			}
		}
	}


	// -------------------------------------------------------
	// Private Data Loaded callback
	// -------------------------------------------------------
	
	function ajaxLoaded(data) {
		debug('AjaxLoaded: '+this.url);
		modal.tmp.html(currentSettings.selector
			?filterScripts($('<div>'+data+'</div>').find(currentSettings.selector).contents())
			:filterScripts(data));
		if (modal.tmp.html()) {
			modal.dataReady = true;
			showContentOrLoading();
		} else
			loadingError();
	}
	
	function formDataLoaded() {
		debug('formDataLoaded');
		currentSettings.from.action += currentSettings.selector;
		currentSettings.from.target = '';
		$('input[name='+currentSettings.formIndicator+']', currentSettings.from).remove();
		var iframe = modal.tmp.children('iframe');
		var iframeContent = iframe.unbind('load').contents().find(currentSettings.selector || 'body').not('script[src]');
		iframe.attr('src', 'about:blank'); // Used to stop the loading in FF
		modal.tmp.html(iframeContent.html());
		if (modal.tmp.html()) {
			modal.dataReady = true;
			showContentOrLoading();
		} else
			loadingError();
	}


	// -------------------------------------------------------
	// Private Animation callback
	// -------------------------------------------------------
	
	function endHideContent() {
		debug('endHideContent');
		modal.anim = false;
		
		if (contentEltLast) {
			contentEltLast.append(modal.content.contents());
			contentEltLast= null;
		} else if (contentElt) {
			contentElt.append(modal.content.contents());
			contentElt= null;
		}
		modal.content.empty();
		modal.contentWrapper
			.empty()
			.removeAttr('style')
			.hide()
			.css(currentSettings.css.wrapper)
			.append(modal.content);
		showContentOrLoading();
	}
	
	function endRemove() {
		debug('endRemove');
		$(document).unbind('keydown', keyHandler);
		modal.anim = false;
		modal.full.remove();
		modal.full = null;
		if (isIE6) {
			body.css({height: '', width: '', position: '', overflow: ''});
			$('html').css({overflow: ''});
		}
		if ($.isFunction(currentSettings.endRemove))
			currentSettings.endRemove(modal, currentSettings);
	}
	
	function endBackground() {
		debug('endBackground');
		modal.ready = true;
		modal.anim = false;
		showContentOrLoading();
	}
	
	function endShowContent() {
		debug('endShowContent');
		modal.anim = false;
		modal.contentWrapper.css({opacity: ''}); // for the close button in IE
		fixFF = $.browser.mozilla && parseFloat($.browser.version) < 1.9 && currentSettings.type != 'gallery' && currentSettings.type != 'image';
		if (fixFF)
			modal.content.css({position: 'fixed'}); // Fix Issue #10
		if ($.isFunction(currentSettings.endShowContent))
			currentSettings.endShowContent(modal, currentSettings);
		if (resized.width)
			setCurrentSettings({width: null});
		if (resized.height)
			setCurrentSettings({height: null});
	}


	// -------------------------------------------------------
	// Utilities
	// -------------------------------------------------------
	
	// Get the selector from an url (as string)
	function getHash(url) {
		var hashPos = url.indexOf('#');
		if (hashPos > -1)
			return url.substring(hashPos);
		return '';
	}
	
	// Filter an html content to remove the script[src]
	function filterScripts(data) {
		// Removing the body, head and html tag
		if (typeof data == 'string')
			data = data.replace(/<\/?(html|head|body)([^>]*)>/gi, '');
		var tmp = new Array();
		$.each($.clean({0:data}, this.ownerDocument), function() {
			if ($.nodeName(this, "script")) {
				if (!this.src || $(this).attr('rel') == 'forceLoad')
					modal.scripts.push(this);
			} else
				tmp.push(this);
		});
		return tmp;
	}
	
	// Get the vertical and horizontal margin, padding and border dimension
	function getOuter(elm) {
		elm = elm.get(0);
		var ret = {
			h: {
				margin: getCurCSS(elm, 'marginTop') + getCurCSS(elm, 'marginBottom'),
				border: getCurCSS(elm, 'borderTopWidth') + getCurCSS(elm, 'borderBottomWidth'),
				padding: getCurCSS(elm, 'paddingTop') + getCurCSS(elm, 'paddingBottom')
			},
			w: {
				margin: getCurCSS(elm, 'marginLeft') + getCurCSS(elm, 'marginRight'),
				border: getCurCSS(elm, 'borderLeftWidth') + getCurCSS(elm, 'borderRightWidth'),
				padding: getCurCSS(elm, 'paddingLeft') + getCurCSS(elm, 'paddingRight')
			}
		};
		
		ret.h.outer = ret.h.margin + ret.h.border;
		ret.w.outer = ret.w.margin + ret.w.border;
		
		ret.h.inner = ret.h.padding + ret.h.border;
		ret.w.inner = ret.w.padding + ret.w.border;
		
		ret.h.total = ret.h.outer + ret.h.padding;
		ret.w.total = ret.w.outer + ret.w.padding;
		
		return ret;
	}
	
	function getCurCSS(elm, name) {
		var ret = parseInt($.curCSS(elm, name, true));
		if (isNaN(ret))
			ret = 0;
		return ret;
	}
	
	// Show the message in the background if possible.
	function debug(msg) {
		//alert(msg);
		if (currentSettings && currentSettings.debug && modal.full)
			modal.bg.prepend(msg+'<br />');
	}
	
	// -------------------------------------------------------
	// Default animation function
	// -------------------------------------------------------
	
	function showBackground(elts, settings, callback) {
		elts.bg.css({opacity:0}).fadeTo(500, 0.75, callback);
	}
	
	function hideBackground(elts, settings, callback) {
		elts.bg.fadeOut(300, callback);
	}
	
	function showLoading(elts, settings, callback) {
		var h = elts.loading.height();
		var w = elts.loading.width();
		elts.loading
			.css({
				height: h+'px',
				width: w+'px',
				marginTop: (-h/2 + settings.marginScrollTop)+'px',
				marginLeft: (-w/2 + settings.marginScrollLeft)+'px',
				opacity: 0
			})
			.show()
			.animate({
				opacity: 1
			}, {complete: callback, duration: 400});
	}
	
	function hideLoading(elts, settings, callback) {
		callback();
	}
	
	function showContent(elts, settings, callback) {
		var h = elts.loading.height();
		var w = elts.loading.width();
		elts.loading
			.css({
				height: h+'px',
				width: w+'px',
				marginTop: (-h/2 + settings.marginScrollTop)+'px',
				marginLeft: (-w/2 + settings.marginScrollLeft)+'px'
			})
			.show()
			.animate({
				width: settings.width+'px',
				height: settings.height+'px',
				marginTop: (settings.marginTop)+'px',
				marginLeft: (settings.marginLeft)+'px'
			}, {duration: 350, complete: function() {
				elts.contentWrapper
					.css({
						width: settings.width+'px',
						height: settings.height+'px',
						marginTop: (settings.marginTop)+'px',
						marginLeft: (settings.marginLeft)+'px'
					})
					.show();
					elts.loading.fadeOut(200, callback);
				}
			});
	}
	
	function hideContent(elts, settings, callback) {
		elts.contentWrapper
			.animate({
				height: '50px',
				width: '50px',
				marginTop: 25+settings.marginScrollTop+'px',
				marginLeft: 25+settings.marginScrollLeft+'px'
			}, {duration: 350, complete: function() {
				elts.contentWrapper.hide();
				callback();
			}});
	}
	
	function showTransition(elts, settings, callback) {
		// Put the loading with the same dimensions of the current content
		elts.loading
			.css({
				marginTop: elts.contentWrapper.css('marginTop'),
				marginLeft: elts.contentWrapper.css('marginLeft'),
				height: elts.contentWrapper.css('height'),
				width: elts.contentWrapper.css('width'),
				opacity: 0
			})
			.show()
			.fadeTo(400, 1, function() {
					elts.contentWrapper.hide();
					callback();
				});
	}
	
	function hideTransition(elts, settings, callback) {
		// Place the content wrapper underneath the the loading with the right dimensions
		elts.contentWrapper
			.css({
				width: settings.width+'px',
				marginLeft: (settings.marginLeft)+'px',
				height: settings.height+'px',
				marginTop: (settings.marginTop)+'px',
				opacity: 1
			});
		elts.loading
			.animate({
				width: settings.width+'px',
				marginLeft: (settings.marginLeft)+'px',
				height: settings.height+'px',
				marginTop: (settings.marginTop)+'px'
			}, {complete: function() {
					elts.contentWrapper.show();
					elts.loading.fadeOut(400, function() {
						elts.loading.hide();
						callback();
					});
				}, duration: 350});
	}
	
	function resize(elts, settings, callback) {
		elts.contentWrapper
			.animate({
				width: settings.width+'px',
				marginLeft: (settings.marginLeft)+'px',
				height: settings.height+'px',
				marginTop: (settings.marginTop)+'px'
			}, {complete: callback, duration: 400});
	}
	
	function updateBgColor(elts, settings, callback) {
		if (!$.fx.step.backgroundColor) {
			elts.bg.css({backgroundColor: settings.bgColor});
			callback();
		} else
			elts.bg
				.animate({
					backgroundColor: settings.bgColor
				}, {complete: callback, duration: 400});
	}
	
	// -------------------------------------------------------
	// Default initialization
	// -------------------------------------------------------
	
	$($.fn.nyroModal.settings.openSelector).nyroModal();	
});

init_alst = function (showing_complete, client_id) {
    jQuery('form', '#aldet-body').unbind('submit').submit(function() {
        var id = $(this).attr('id').split('-')[1] ;
        var tdate = $('#dcdd-' + id).text() ;
        var odate = $('#ocddh-' + id).val() ;
        if (tdate != odate) {
            if ($('#com-'+id).val() == '') {
                alert('You must add a comment when changing the due date') ;
                return false;
            }
        }
        jQuery.ajax({url : this.action + '/uacts', type : 'post', data : 'uacts=1&' + jQuery(this).serialize()}) ;
        return false;
    }) ;
    
    jQuery('#fixme a.fr').unbind('click').bind('click', function () {
        var link = $(this) ;
        
        if (link.hasClass('exp')) {
            $('div.actlsum').hide() ;
            $('div.actlfull').show() ;
        } else {
            $('div.actlsum').show() ;
            $('div.actlfull').hide() ;
        }
        return false; 
    })

    jQuery('#aldet-body td.reqa a.more, #aldet-body td.obs a.more').unbind('click').bind('click', function () {
        var link = $(this) ;
        var div, sum, full ;
        var aid = $(this).attr('id').substring(1) ;
        
        sum = link.parents('div.actlsum') ;
        
        if (sum.length == 1) {
            full = sum.next() ;
            
        } else {
            full = link.parents('div.actlfull') ;
            sum = full.prev() ;
        }
        
        if (sum.is(':visible')) {
            $('#s-' + aid).attr('rel', 'lightbox-sum') ;
            $('#f-' + aid).attr('rel', 'lightbox') ;
            sum.hide() ;
            full.show() ;
            
        } else {
            $('#s-' + aid).attr('rel', 'lightbox') ;
            $('#f-' + aid).attr('rel', 'lightbox-full') ;
            sum.show() ;
            full.hide() ;
        }
    })

    $('#rform input[type=radio]').unbind('click').click( function () {
        var property_id = $('#property_id').val() ;
        showrisks(this, property_id, $('#open-comp').val());
        this.blur() ;
        return false;
    }) ;

    // $('#d_risks').unbind('change').change( function () {
    //     var property_id = $('#property_id').val() ;
    //     var doc_id = $('#d_risks').val() ;
    //     rlst('cp_alst', property_id, doc_id, '')
    // } ) ;

    $('#sr-comp').unbind('click').click( function () {
        var property_id = $('#property_id').val() ;
        showrisks(this, property_id, 'comp');
        this.blur() ;
        return false;
    }) ;
    $('#sr-open').unbind('click').click( function () {
        var property_id = $('#property_id').val() ;
        showrisks(this, property_id, 'open');
        this.blur() ;
        return false;
    }) ;
    $('#dl-csv, #dl-csva').unbind('click').click( function () {
        var property_id = $('#property_id').val() ;
        dlrisks(this, property_id, 'open');
        this.blur() ;
        return false;
    }) ;
    
    
    
    // $('#dl-csv').unbind('click').click( function () {
    //     var open_comp = $('#open-comp').val() ;
    //     var href = $(this).attr('href') + '/' + open_comp ;
    //     $.get(href) ;
    //     this.blur() ;
    //     return false;
    // }) ;
    
    
    $('select[name=act_status]').unbind('change').change(function () {
        var num = $(this).find('option').length ;
        var max = $(this).find('option:eq(' + (num-1) + ')').val() ;
        var id = $(this).attr('id').split('-')[1]
        
        if ($(this).val() == max) {
            var nid = '#tdd-' + id ;
            $(nid).click() ;            // Show calendar.
            
        } else {
            $('#cd-' + id).html('') ;
            $('#dcd-' + id).val('') ;
        }
    })
    
    var timer = setInterval(function() {
        if (typeof($().nyroModal) == 'function') {
            clearInterval(timer) ;
            
            jQuery("a[rel*=lightbox]","#aldet-body").nyroModal() ; // Select all links that contains lightbox in the attribute rel
    
            $('a#aownact').nyroModal({width: '500', height: '350'}) ;

            $('a.remlink', '#aldet-body').unbind('click').click(remlink_click) ;

            $('img.cal').unbind('click').click(function () {
                var id = $(this).attr('id').split('-')[1] ;
                showCalendar('dcd-' + id, '%d-%b-%Y', 'dcd-' + id, null, null, function (c, d) {compconf('cd-' + id, d)});
            }) ;

            $('img.cddcal').unbind('click').click(function () {
                var id = $(this).attr('id').split('-')[1] ;
                showCalendar('dcdd-' + id, '%d-%b-%Y', 'dcdd-' + id, null, null, function (c, d) {cddconf(id, d)});
            }) ;

            init_al(client_id) ;
        }
    }, 100) ;
}
    

dlrisks = function(what, property_id, open_comp) {
    var typeValue = $('#rform input[type=radio][name=rstat]:checked').val() ;
    var overdue = $('#overdue:checked').val() ;
    // var doc = jQuery('#d_risks').val() ;
    var group ;
    
    var users = $('#filtulst').val() ;
    var sps   = $('#filtsplst').val() ;

    if (users == 'all removed') {
        users = '' ;
    }
    if (sps == 'all removed') {
        sps = '' ;
    }


    open_comp = $('#open-comp').val() ;
    group = typeof(typeValue) == 'undefined' || typeValue == '' ? 'any' : typeValue ;
    overdue = typeof(overdue) == 'undefined' || overdue == '' ? '' : 'od';
    open_comp = typeof(open_comp) == 'undefined' ? $('#open-comp').val() : open_comp ;

    var url = what.href +'0/' + group + '/' + (open_comp ? open_comp : '') + (overdue ? '/od' : '') ;
    // var url = '/cp_alst/' + property_id + '/0/' + group + '/' + (open_comp ? open_comp : '') + (overdue ? '/od' : '') ;

    var docs = $('input[name="d_risks[]"]').serialize() 
         +  '&users=' + users
         +  '&sps=' + sps ;
        
    document.location.href = url + '?' + docs ;
    
    $(what).blur();
    return false ;
}

showrisks = function(what, property_id, open_comp) {
    var typeValue = $('#rform input[type=radio][name=rstat]:checked').val() ;
    var overdue = $('#overdue:checked').val() ;

    var users = $('#filtulst').val() ;
    var sps   = $('#filtsplst').val() ;
    if (users == 'all removed') {
        users = '' ;
    }
    if (sps == 'all removed') {
        sps = '' ;
    }

    if (open_comp) {
        $('#open-comp').val(open_comp) ;
    } else {
        open_comp = $('#open-comp').val() ;
    }

    var group = typeof(typeValue) == 'undefined' || typeValue == '' ? 'any' : typeValue ;
    overdue = typeof(overdue) == 'undefined' || overdue == '' ? '' : 'od';
    open_comp = typeof(open_comp) == 'undefined' ? $('#open-comp').val() : open_comp ;
    
    var url = '/cp_alst/' + property_id + '/0/' + group + '/' + (open_comp ? open_comp : '') + (overdue ? '/od' : '') ;

    var docs = $('input[name="d_risks[]"]').serialize() ;
    docs += '&container=cp_alst-body' 
         +  '&users=' + users
         +  '&sps=' + sps ;
    
    $.get(url, docs) ;          // Use get instead of load to enable taconite processing

    
    $(what).blur();
    return false ;
}

// function rlst(section, property, doc, group, open_comp) {
// 
//     group = typeof(group) == 'undefined' || group == '' ? 'any' : group ;
//     open_comp = typeof(open_comp) == 'undefined' ? $('#open-comp').val() : open_comp ;
//     
//     var url = '/' + section + '/' + property + '/' + doc + '/' + group + (open_comp ? '/' + open_comp : '') ;
//     var upd_div = section +'-body' ;
// 
//     $.get(url, {container: upd_div}) ;          // Use get instead of load to enable taconite processing
//     // jQuery('#' + upd_div).load(url) ;
// }



// ===========================================================================
// NEW ACTION HANDLING FOLLOWS
// ===========================================================================

// ---------------------------------------------------------------------------
// ADD ACHKL
// =========
// Called when the user requests the insertion of a new audit checklist block.
// It starts by hiding the button, to prevent them attempting to add a second
// block below this, then issues an ajax request for the block contents.
// ---------------------------------------------------------------------------
function cladd_action   (property_id) {
    // var where = jQuery('#cl-actover') ;
    // var ownacts = jQuery('#ownacts') ;
    // var row ;
    // 
    // 
    // // -----------------------------------------------------------------------
    // // First, check if there are any actionlists.If not, we can't add an action
    // // -----------------------------------------------------------------------
    // if (where.length) {
    //     // -------------------------------------------------------------------
    //     // If no owner entries exist as yet, look for the action table and, if
    //     // found start adding at the end.
    //     // -------------------------------------------------------------------
    //     if (!ownacts.length) {
    //         where.append('<tr id="ownacts"><th colspan="2" class="xref" style="color:mauve">Client Added Actions</th></tr>') ;
    //         ownacts = jQuery('#ownacts') ;
    //     }
    // 
    //     // -------------------------------------------------------------------
    //     // Now scroll the owner actions into view, then attempt to add a blank
    //     // row at the bottom. If one already exists, just give up.
    //     // -------------------------------------------------------------------
    //     if (ownacts.length) {
    //         ownacts[0].scrollIntoView() ;
    // 
    //         row = jQuery('#ownacts-tr-0') ;
    //         if (row.length == 0) {
    //             where.append('<tr id="ownacts-tr-0"><td colspan="2" style="text-align:center">Please wait while we prepare the form...</td></tr>') ;
    //         }
    //     }
    // }
    return false;
}

// ===========================================================================
// DELEGATE HANDLING FOLLOWS
// ===========================================================================
init_al = function(client_id) {
    var alst_id ;
    var div ;
    var contents ;
    var multiSelect_timer ;
      
    div = $('#alst-clist') ;
    if (div.length) {
        div.fadeOut() ;
    }

    $('input.facs.userlist', '#filters').multi_select ('/cl_users/' + client_id,
                                                            {
                                                                current_values  : getFilteredUsers,
                                                                add_value       : addUserFilter,
                                                                remove_value    : removeUserFilter,
                                                                container_id    : 'filt-users',
                                                                type            : 'emp',
                                                                cbPrefix        : 'f',
                                                                use_alert       : true
                                                            }) ;
    
    $('input.facs.sprovlist', '#filters').multi_select ('/cl_sprovs/' + client_id,
                                                            {
                                                                current_values  : getFilteredSps,
                                                                add_value       : addSpFilter,
                                                                remove_value    : removeSpsFilter, 
                                                                container_id    : 'filt-sprovs',
                                                                format_list     : format_sp_list,
                                                                type            : 'spr',
                                                                width           : '300px',
                                                                cbPrefix        : 'f',
                                                                use_alert       : true
                                                            }) ;

    
    $('input.acs.userlist', '#aldet-body').multi_select ('/cl_users/' + client_id,
                                                            {
                                                                current_values  : get_cur_users,
                                                                add_value       : add_cur_user,
                                                                remove_value    : remove_cur_user,
                                                                container_id    : 'alst-users',
                                                                type            : 'emp'
                                                            }) ;
    
    $('input.acs.sprovlist', '#aldet-body').multi_select ('/cl_sprovs/' + client_id,
                                                            {
                                                                current_values  : get_cur_sps,
                                                                add_value       : add_cur_sps,
                                                                remove_value    : remove_cur_sps, 
                                                                container_id    : 'alst-sprovs',
                                                                format_list     : format_sp_list,
                                                                type            : 'spr',
                                                                width           : '300px'
                                                            }) ;
    
}

// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
remlink_click = function () {
        var litem =  $(this).parent() ;
        var parts = $(this).attr('id').split('-') ;
        var name = $('span:eq(0)', litem).html() ;
        
        if (confirm('Do you really want to remove ' + name + ' from the delegation list?')) {
            litem.removeAndFade() ;
        
            if (parts[1] == 'emp') {
                remove_cur_user('u-' + parts[3], parts[2]) ;
                
            } else if (parts[1] == 'spr') {
                remove_cur_sps('s-' + parts[3], parts[2]) ;
                
            }
        }
    } ;


// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
function get_cur_sps (cur_item_id) {
    var alst_id = cur_item_id.split('-')[1] ;
    
    return $('#delegated-sprovs-'+ alst_id).val().split(',') ;    
}

function getFilteredSps() {
    return $('#filtsplst').val().split(',') ;
}


function addSpFilter (cur_item_id, newId, data) {
    var item ;
    
    for (var ind=0; ind < data.length; ind++) {
        if (data[ind].id == newId) {
            item = data[ind] ;
            break ;
        }
    }
    
    if (item) {
        var users = $('#filtsplst').val() ;        
        users = (users == 'all removed' ? '' : users) ;        
        users += (users != '' ? ',' : '' ) + newId ;
        
        var count = users.split(',').length ;
        $('#filtsplst').val(users) ;
        $('#filtspcount').text(count+ ' selected').addClass('changed') ;
    }
}

function removeSpsFilter (cur_item_id, old_id, data) {
    var users = $('#filtsplst').val().split(',') ;
    var new_users = [] ;
    for (var ind=0; ind < users.length; ind++) {
        if (users[ind] != old_id) {
            new_users[new_users.length] = users[ind] ;
        }
    }
    $('#filtsplst').val(new_users.join(',')) ;
    var count = new_users.length ;
    var text = (count) ? count + ' selected' : 'all removed' ;
    $('#filtspcount').text(text).addClass('changed') ;
}



function add_cur_sps (cur_item_id, new_id, data) {
    var alst_id = cur_item_id.split('-')[1] ;
    var item ;
    
    for (var ind=0; ind < data.length; ind++) {
        if (data[ind].id == new_id) {
            item = data[ind] ;
            break ;
        }
    }
    
    if (item) {
        var users = $('#delegated-sprovs-'+ alst_id).val() ;
        $('#delegated-sprovs-'+ alst_id).val(users + (users != '' ? ',' : '') + new_id) ;
        // $(this).next().css('color', 'grey') ;
        var text = item.fullname + (item.position ? ' (' + item.position + ')' : '') + (item.company ? ' <span class="company">' + item.company + '</span>' : '');
    
        show_it(alst_id, 'sprov', new_id, text) ;
    }
}



function remove_cur_sps (cur_item_id, old_id, data) {
    var alst_id = cur_item_id.split('-')[1] ;
    
    var users = $('#delegated-sprovs-'+ alst_id).val().split(',') ;
    var new_users = '' ;
    for (var ind=0; ind < users.length; ind++) {
        if (users[ind] != old_id) {
            new_users += ',' + users[ind]
        }
    }
    $('#delegated-sprovs-'+ alst_id).val(new_users) ;
    // $(this).next().css('color', 'black') ;

    var rowid = 'd-sprov-' + old_id + '-' + alst_id ;
    $('#' + rowid).parent().fadeOut().remove() ;
    
    list_is_empty(alst_id) ;
}

// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
function get_cur_users (cur_item_id) {
    var alst_id = cur_item_id.split('-')[1] ;
    
    return $('#delegated-users-'+ alst_id).val().split(',') ;
}

function getFilteredUsers() {
    return $('#filtulst').val().split(',') ;
}

function addUserFilter(curItemId, newId, data) {
    var item ;
    
    for (var ind=0; ind < data.length; ind++) {
        if (data[ind].id == newId) {
            item = data[ind] ;
            break ;
        }
    }
    
    if (item) {
        var users = $('#filtulst').val() ;        
        users = (users == 'all removed' ? '' : users) ;        
        users += (users != '' ? ',' : '' ) + newId ;
        
        var count = users.split(',').length ;
        $('#filtulst').val(users) ;
        $('#filtucount').text(count+ ' selected').addClass('changed') ;
    }
}

function removeUserFilter (cur_item_id, old_id, data) {
    var users = $('#filtulst').val().split(',') ;
    var new_users = [] ;
    for (var ind=0; ind < users.length; ind++) {
        if (users[ind] != old_id) {
            new_users[new_users.length] = users[ind] ;
        }
    }
    $('#filtulst').val(new_users.join(',')) ;
    var count = new_users.length ;
    var text = (count) ? count + ' selected' : 'all removed' ;
    $('#filtucount').text(text).addClass('changed') ;
}








function add_cur_user (cur_item_id, new_id, data) {
    var alst_id = cur_item_id.split('-')[1] ;
    var item ;
    
    for (var ind=0; ind < data.length; ind++) {
        if (data[ind].id == new_id) {
            item = data[ind] ;
            break ;
        }
    }
    
    if (item) {
        var users = $('#delegated-users-'+ alst_id).val() ;
        
        $('#delegated-users-'+ alst_id).val(users + (users != '' ? ',' : '' ) + new_id) ;
        // $(this).next().css('color', 'grey') ;
        
        var text = item.fullname + (item.position ? ' (' + item.position + ')' : '') ;
        
        show_it(alst_id, 'emp', new_id, text) ;
    }
}

function remove_cur_user (cur_item_id, old_id, data) {
    var alst_id = cur_item_id.split('-')[1] ;
    
    var users = $('#delegated-users-'+ alst_id).val().split(',') ;
    var new_users = [] ;
    for (var ind=0; ind < users.length; ind++) {
        if (users[ind] != old_id) {
            new_users[new_users.length] = users[ind] ;
        }
    }
    $('#delegated-users-'+ alst_id).val(new_users.join(',')) ;
    // $(this).next().css('color', 'black') ;    

    var rowid = 'd-emp-' + old_id + '-' + alst_id ;
    $('#' + rowid).parent().fadeOut().remove() ;

    list_is_empty(alst_id) ;
}

function format_sp_list (data, prefix) {
    var list = $('<div />') ;
    var prefix = prefix + 'cb-' ;
    
    $(data).each (function (index, user) {
            $('<input type="checkbox" name="spr" id="' + prefix + 'spr-' + user.id + '" value="' + user.id + '" />').appendTo(list) ;
            $('<label for="' + prefix + 'spr-' + user.id + '" style="color:#006666">&#160;' + user.fullname + 
                (user.position ? '&#160;<span class="alst_position" style="color:#A3A3A3;font-style:oblique;">(' + user.position + ')</span>' : '') +
                (user.company  ? '<br /><span class="alst_position" style="color:#638E6F;font-size:110%;font-weight:bold">' + user.company + '</span>' : '') +
            
            '</label>').appendTo(list) ;
            $('<br />').appendTo(list) ;
    }) ;
    
    return list ;
}

function list_is_empty(alst_id) {
    if ($('#lcs-' + alst_id + ' ol li').length == 0) {
        $('#ch-details-' + alst_id).fadeOut() ;        
    }    
}

// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
function show_it(the_id, item_type, new_id, text) {
    var list = $('#lcs-' + the_id + ' ol') ;
    
    var rowid = 'd-' + item_type + '-' + new_id + '-' + the_id ;
    
    if ($('#' + rowid).length > 0) {
        alert("already added") ;
        return false ;
    }
    
    // -----------------------------------------------------------
    // Build the display row. This is an LI containing the name
    // of the delegate (in a span) and a right aligned link to allow
    // it's removal.
    // -----------------------------------------------------------
    var removeLink = $('<a></a>')
        .addClass('remlink')
        .attr('id', rowid)
        .click(remlink_click) ;

    var span = $('<span>' + text + '</span>' ) ;

    var item = $('<li />')
            .addClass('ch-item-' + item_type)
            .append(span)
            .append(removeLink).
            hide() ;


    list.append(item).fadeIn() ;
    item.fadeIn('2000') ;

    $('#ch-details-' + the_id).fadeIn() ;

    return false ;
}



// ---------------------------------------------------------------------------
// MULTI SELECT
// ============
// ---------------------------------------------------------------------------
$.fn.multi_select = function(url, options) {
 
    var settings = {
            url             : null,
            current_values  : null,
            add_value       : null,
            remove_value    : null,
            container_id    : 'alst-clist',
            width           : '200px',
            current_cell    : 0,
            use_alert       : false,
            data            : null,
            onchange        : null
    }
 
    if(options) {
        $.extend(settings, options);
    }
    settings.url = url + (url.substr(url.length-1) != '/' ? '/' : '');
    settings.data = null ;
    
	this.each(function() {
		var input = this;
	    new $.alst_multi_select (input, settings) ;
	}); 
}

// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
$.alst_multi_select = function (input, options) {
        var div ;
        var contents ;
        var multiSelect_timer ;
        var current_cell ;
        var pos ;
        
        // -------------------------------------------------------------------
        // -------------------------------------------------------------------
        $(input).unbind('click').click(function  (e) {
            var td = $(this).parent() ;
            
            options.alst_id = this.id
            
            e.preventDefault(); 
            e.stopPropagation(); 

            current_cell = options.current_cell ;
            
            // -----------------------------------------------------------------------
            // If showing the list (or loading text) in another cell, restore that.
            // -----------------------------------------------------------------------
            if (typeof(current_cell) == 'object') {
                current_cell.removeClass('subdued-overlay') ;
            }
            current_cell = null ;
            if (_find_container()) {
                init_container () ;
                load_container () ;
            }
            options.current_cell = current_cell ;
            
            // --------- END OF LOGIC ----------
            
            
            // -----------------------------------------------------------------------
            // Locate the current cell and if found, flag it as subdued and find where
            // on the page it's positioned
            // -----------------------------------------------------------------------
            function _find_container() {
                var result = false ;
                
                while (td && td[0].tagName != 'TD') {
                    td = $(td).parent() ;
                }    
                if (td && td.length > 0) {
                    current_cell = td ;
            
                    td.addClass('subdued-overlay') ;
                    if (options.use_alert) {
                       pos = {top:0, left:0} ;
                    } else {
                        pos = findPos(td[0]) ;
                    }
                    result = true ;
                }
                return result ;
            }
            
            function _useDialog() {
                
            }
            

            // -------------------------------------------------------------------
            // INIT CONTAINER
            // ==============
            // Check if this is the first call and if so, create the container.
            // In either case, position it over the parent table cell.
            // -------------------------------------------------------------------
            function init_container () {
                div = $('#' + options.container_id) ;
                if (div.length == 0) {

                    div = document.createElement('div') ;
                    div = $(div) ;

                    div.attr('id', options.container_id) ;
                    div.html('Loading the list...') ;
                }
                // -------------------------------------------------------------------
                // Hide the container, if visible, then position to the top-left of
                // the new cell, followed by appending to the DOM and showing it.
                // -------------------------------------------------------------------
                div.hide().addClass('ac_loading').css({
                    position: (options.use_alert == false || $.browser.msie && parseInt($.browser.version) <= 6 ) ? 'absolute' : 'fixed',
                    top:  pos.y + "px",
                    left: pos.x + "px",
                    width: options.width,
                    backgroundColor: '#FFFFE0',
                    paddingBottom: '2px',
                    border: '2px outset lightgrey',
                    zIndex: 99999
                });
                $("body").append(div);
            }

            // -------------------------------------------------------------------
            // LOAD CONTAINER
            // ==============
            // -------------------------------------------------------------------
            function load_container () {
                // -------------------------------------------------------------------
                // Final step - request the proper contents, unless already loaded.
                // -------------------------------------------------------------------
                if (options.data && typeof(options.data) == 'object') {
                    reinit_alst_users (options.alst_id) ;
                    if (options.use_alert) {
                        _reposition() ;
                    }
                    div.fadeIn() ;

                } else {
                    $.getJSON(options.url + options.alst_id, function (data) {
                        options.data = data ;
                        
                        fill_container();
                        add_event_handlers()

                        var header = $('<h3>Please select as many as required</h3>').css({backgroundColor:'#A2CBAF',
                                                                            marginLeft: '0px',
                                                                            padding: '6px 4px 4px 4px',
                                                                            border: '1px outset darkgreen',
                                                                            lineHeight: '1'
                                                                        })


                        div.empty().append(header).append(contents) ;

                        reinit_alst_users (options.alst_id) ;
                        if (options.use_alert) {
                            _reposition() ;
                        }
                        div.fadeIn() ;
                    })
                }
                
        		function _reposition () {
					$("BODY").append('<div id="popup_overlay"></div>');
					$("#popup_overlay").css({
						position: 'absolute',
						zIndex: 99998,
						top: '0px',
						left: '0px',
						width: '100%',
						height: $(document).height(),
						background: '#000',
						opacity: 0.4
					}).show();
        		    
        		    
        			var top = (($(window).height() / 2) - ($(div).outerHeight() / 2)) + 0 ;
        			var left = (($(window).width() / 2) - ($(div).outerWidth() / 2)) + 0 ;
        			if( top < 0 ) top = 0;
        			if( left < 0 ) left = 0;

        			// IE6 fix
        			if( $.browser.msie && parseInt($.browser.version) <= 6 ) top = top + $(window).scrollTop();

        			$(div).css({
        				top: top + 'px',
        				left: left + 'px'
        			});
        			$('#popup_overlay').height( $(document).height() );
        		}

                
            }
            
            // -------------------------------------------------------------------
            // -------------------------------------------------------------------
            function reinit_alst_users(alst_id) {
                var users = $.isFunction(options.current_values) ? options.current_values(alst_id) : [] ;                
                
                $('input[type=checkbox]', '#' + options.container_id).attr('checked', false) ;

                for (var ind=0; ind < users.length; ind++) {
                   $('#' + options.cbPrefix + 'cb-' + options.type + '-' + users[ind]).attr('checked', 'checked') ; //.next().css('color', 'grey') ;
                }

                multiSelect_timer = setTimeout (hide_alst, 4000)
            }
            
            // -------------------------------------------------------------------
            // HIDE ALST
            // =========
            // -------------------------------------------------------------------
            function hide_alst () {
                if(multiSelect_timer != null) {
                    clearTimeout(multiSelect_timer);
                    multiSelect_timer = null;
                    div.fadeOut() ;
                    $('#popup_overlay').hide();
                    if (typeof(current_cell) == 'object') {
                        current_cell.removeClass('subdued-overlay') ;
                    }
                }
            }
            
            // -------------------------------------------------------------------
            // ADD EVENT HANDLERS
            // ==================
            // -------------------------------------------------------------------
            function add_event_handlers () {
                $('input', contents).click(function() {

                    var new_id = this.id.split('-')[2] ;

                    if ($(this).is(':checked')) {

                        // $(this).next().css('color', 'grey') ;
                        if ($.isFunction(options.add_value)) {
                            options.add_value(options.alst_id, new_id, options.data) ;
                        }

                    } else {
                        // $(this).next().css('color', 'grey') ;
                        if ($.isFunction(options.add_value)) {
                            options.remove_value(options.alst_id, new_id, options.data) ;
                        }

                        // $(this).next().css('color', 'black') ;
                    }

                }) ;

                div.mouseout(function() {
                    multiSelect_timer = setTimeout(function() {
                        hide_alst () ;
                    }, 500);
                }).mouseover(function() {
                    clearTimeout(multiSelect_timer);
                    multiSelect_timer = null;
                });                        

            }
            
            // -------------------------------------------------------------------
            // FILL CONTAINER
            // ==============
            // -------------------------------------------------------------------
            function fill_container() {
                contents = $('<div>') ;
                contents.css({
                        width: 'auto',
                        height: '150px',
                        textAlign: 'left',
                        paddingLeft: '5px',
                        overflowY: 'scroll'
                    }) ;

                if ($.isFunction(options.format_list)) {
                    options.format_list(options.data, options.cbPrefix).appendTo (contents) ;
                    
                } else {
                    $(options.data).each (function (index, user) {
                            $('<input type="checkbox" name="' + options.type + '" id="' + options.cbPrefix + 'cb-' + options.type + '-' + user.id + '" value="' + user.id + '" />').appendTo(contents) ;
                            $('<label for="' + options.cbPrefix + 'cb-' + options.type + '-' + user.id + '" style="color:#006666">&#160;' + user.fullname + '</label>').appendTo(contents) ;
                            $('<br />').appendTo(contents) ;
                    })
                }

            }
            
            
        })
}


function findPos(obj) {
	var curleft = obj.offsetLeft || 0;
	var curtop = obj.offsetTop || 0;
	while (obj = obj.offsetParent) {
		curleft += obj.offsetLeft
		curtop += obj.offsetTop
	}
	return {x:curleft,y:curtop};
}

// $.taconite.debug=1
// ---------------------------------------------------------------------------
// This block adds an indicator for all ajax calls
// ---------------------------------------------------------------------------
jQuery(document).ready(function($) {
    $(function() {
        var $headline = $('#cl-full-name');

        $(document).ajaxSend(function() {
            $headline
                .removeClass('activity')
                .addClass('activity');
        });

        $(document).ajaxStop(function() {
            $headline.removeClass('activity') ;
        });

    })
}) ;


compconf = function (id, date) {
    var parts, v ;

    parts = id.split('-') ;
    var cost = $('#c-'+ parts[1]).val() ;
    if (cost == '') {
        cost = 0.00 ;
    }
    
    if (confirm("Please confirm that the risk was completed on the " + date + " at a cost of Â£" + cost +
                ".\n\nOnce saved, this entry will be locked against any further changes and will subsequently only be visible as an archived item. ")) {
        $('#' + id).html(date) ;
        $('#d' + id).val(date) ;
    } else {
        $('#' + id).html('') ;
        $('#d' + id).val('') ;

        id = parts[1] ;
        var sel = $('#act_status-' + id) ;

        var num = sel.find('option').length ;
        var val = sel.find('option:eq(' + (num-2) + ')').val() ;
        sel.val(val) ;                                  // Set status down 1 point (away from complete.)
    }
}

cddconf = function (aid, date) {
    var parts;

    if ($('#com-'+ aid).val() == '') {
        $('#dcdd-' + aid).html($('#dcddh-' + aid).val()) ;        
        alert('You must enter a comment before you can alter the due date') ;
        
    } else {
        $('#dcdd-' + aid).html(date) ;
        $('#dcddh-' + aid).val(date) ;
    }
}

var cluetipClose ;                              // Required to allow code to close the pop-up
function init_serv() {
    
    var timer= setInterval(function () {
        if (typeof($().cluetip) == 'function') {
            clearInterval(timer) ;
            $('#survr img.cluetip').cluetip({local :true, cursor : 'pointer', arrows : true, fx : {open : 'show'}, splitTitle : '~', 
                                    titleAttribute : 'alt'});
            $('#survr img.tpr').cluetip({local :true, cursor : 'pointer', showTitle : false, arrows : true, fx : {open : 'show'}, splitTitle : '~'                        , 
                                                            titleAttribute : 'alt',
                    onShow : function (ct, c, closeFunction) {
                        cluetipClose = closeFunction ;
                    }
                });
        
            $("#survr a.tpr").unbind('click').click(function() {
                var href = this.href ;
                var row = $(this).parent() ;
            
                if (cluetipClose) {
                    cluetipClose() ;
                }
                while (row && row[0].tagName != 'TR') {
                    row = row.parent() ;
                }
                if (row) {
                    $('td', row).addClass('ac_loading') ;
                }
            
                $.get(href, {}, function () {
                    if (row) {
                        $('td', row).removeClass('ac_loading') ;
                        $('#survr').fadeOut();
                    }
                
                }) ;
            
                return false;
            }) ;
        }
        
    }, 50) ;
    
    
}

// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
function init_ccd() {    
    $('#cdoc-list a.thickbox').unbind('click')
    
    tb_init('#cdoc-list a.thickbox') ;
    stripe ('#cdoc-list tbody');
    
    $('#cdoc-list a[class=fancy_close]').unbind('click').click (function () {
        var row = $(this).parent() ;
        var max = 15 ;
        
        while (row.length > 0 && row[0].tagName != 'TR') {
            row = row.parent() ;
            if (max <= 0) {
                break ;
            }
        }

        $('#cdoc-list tr').not(row[0]).addClass('subdued') ;
        $('#cdoc-list tr').not(row[0]).find('img').css('visibility','hidden') ;
        
        if (confirm('Do you really want to delete this document ' + $(this).parent().attr('title'))) {
            $.post($(this).attr('href'), function () {

            })
        }
        $('#cdoc-list tr').not(row[0]).find('img').css('visibility','visible') ;
        $('#cdoc-list tr').removeClass('subdued') ;
        return false ;
    })
}

function rstat_edit_init (what, property_id) {
    stripe ('#rstat', true);
    $(what).unbind('click')
        .click(
            function () {
                var tag = $(this) ;
                tag.unbind('click') ;               // Protect against a double click
                
                while (tag.length > 0 && tag[0].tagName != 'TR') {
                    tag = tag.parent() ;
                }
                // -----------------------------------------------------------
                // If we found a match, remove the click handler from the 
                // other cells in the row. If not, we'll be adding a second one
                // when the displayed form is hidden, so we'll trigger 2 clicks
                // -----------------------------------------------------------
                if (tag.length) {
                    
                    tag.unbind('click') ;           
                    $('td', tag).addClass('ac_loading') ;
                    
                    var parts = tag[0].id.split('-') ;
                    $.get('/proprst/' + property_id + '/edit/' + parts[parts.length-1], function() { $('td', tag).removeClass('ac_loading') ; }) ;
                }
            }
        ) ;
}

// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
function manage(item, pdet, toggle) {
    var url   = item.href ;
    var parts = url.split('/') ;
    var pid   = parts[parts.length-1] ;

    item = $(item) ;

    if (pdet == null) {
        pdet  = 'rdet-' + pid ;
    }
    pdet = $('#' +pdet) ;

    if (typeof(toggle) == 'undefined' && pdet.css('display') == 'block') {
        pdet.fadeOut() ;        
        var old_text = item.attr('old_value') ;

        item.html (old_text ? old_text : (pid == 0 ? 'New' : 'View')) ;

    } else {
        pdet.load(url) ;
        if (item.html() != 'Hide') {
            item.attr('old_value', item.html()) ;
            item.html( 'Hide') ;
        }
        pdet.fadeIn() ;
    }
    return false ;
}

// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
function tgluprop (item, form_id, adding) {
    var iid   = item.id ;
    var parts = iid.split('-') ;
    var url   = $('#' + form_id).attr('action') ;

    $(item).parent().html('<span id="' + iid + '">Updating...</span>') ;
    
    params = item.name + '=' + (item.checked ? item.value : '')  + '&update_div=' + iid ;
    $.post (url, params)
    // $.post (url, {item.name : (item.checked ? item.value : ''), 'update_div' : iid})


    // ajax = new Ajax.Request (url, 
    //                 {parameters : params, onComplete : showResponse} ) ;

    return false ;
}


// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
function ch_serv(row, input) {
    $(input).blur() ;
    $(input).next().focus() ;

    setTimeout(function(){
            }, 100) ;
    
    var psid = input.id.split('-')[1] ;
    var list = $('#lcs-' + psid + ' ol') ;
    
    $('#acs-' + psid ).val('') ;
    
    var rowid = 'aora-' + psid + '-' + row.data.id ;
    
    if ($('#' + rowid).length > 0) {
        alert("already added") ;
        return false ;
    }
    
    // -----------------------------------------------------------
    // Append this option to the currently selected list
    // -----------------------------------------------------------
    var ids = $('#' + $(input).attr('id') + '-ids') .val() ;
    ids += row.data.id + ',' ;
    $('#' + $(input).attr('id') + '-ids') .val(ids) ;

    // -----------------------------------------------------------
    // Build the display row. This is an LI containing the name
    // of the service (in a span) and a right aligned a (link) to allow
    // it's removal.
    // -----------------------------------------------------------
    var removeLink = $('<a></a>')
        .addClass('remlink')
        .unbind('click')
        .click(remlink_click) ;

    var span = $('<span id="chs-' + psid + '-' + row.data.id + '">' + row.data.name + '</span><span class="allorreview">' +
                    '<label for="aora-' + psid + '-' + row.data.id + '">All items</label>' +
                    '<input type="radio" name="allorreview[' + row.data.id + ']" id="aora-' + psid + '-' + row.data.id + '" value="all" checked="checked" />&#160;' +
                    '<label for="aorr-' + psid + '-' + row.data.id + '">or review only</label>' +
                    '<input type="radio" name="allorreview[' + row.data.id + ']" id="aorr-' + psid + '-' + row.data.id + '" value="review" />' +
                    '<input type="hidden" name="chs[' + row.data.id + ']" value="' + row.data.id + '" /></span>'
                ) ;


    var item = $('<li />')
            // .attr('id', 'chs-' + psid + '-' + row.data.id)
            .addClass('ch-item')
            .append(span)
            .append(removeLink).
            hide() ;


    list.append(item) ;
    item.fadeIn('2000') ;

    return false ;

    
}

function rlst(section, property, doc, group, open_comp) {

    group = typeof(group) == 'undefined' || group == '' ? 'any' : group ;
    open_comp = typeof(open_comp) == 'undefined' ? $('#open-comp').val() : open_comp ;
    
    var url = '/' + section + '/' + property + '/' + doc + '/' + group + (open_comp ? '/' + open_comp : '') ;
    var upd_div = section +'-body' ;

    $.get(url, {container: upd_div}) ;          // Use get instead of load to enable taconite processing
    // jQuery('#' + upd_div).load(url) ;
}

// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
function stripe(tbody, skip_header) {
    
    // jQuery('table.aud-checklist table#jim>tbody>tr:odd').addClass('alt')
    
    offset = (typeof(skip_header) !== 'undefined' && skip_header ? ':gt(0)' :'')
    
    jQuery('>tr', tbody).removeClass('alt') ;
    jQuery('>tr:odd' + offset, tbody).addClass('alt') ;
    jQuery('>tr' + offset, tbody).mouseover(function() { jQuery(this).addClass('over')})
                              .mouseout(function() { jQuery(this).removeClass('over')}) ;
    
    return false ;
}

// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
function ajaxlink (item, pdet, toggle) {
    item = $(item) ;
    var url   = item.attr('href') ;
    var parts = url.split('/') ;
    var pid   = parts[parts.length-1] ;

    if (pdet == null) {
        pdet  = 'rdet-' + pid ;
    }
    pdet = $('#' + pdet) ;

    if (typeof(toggle) == 'undefined' && pdet.css('display') == 'block') {
        pdet.hide() ;
        
        var old_text = item.attr('old_value') ;

        item.html (old_text ? old_text : (pid == 0 ? 'New' : 'View')) ;

    } else {
        pdet.load (url)    ;
                    
        if (item.html() != 'Hide') {
            item.attr('old_value', item.html()) ;
            item.html ('Hide') ;
        }
        pdet.show() ;
    }
    return false ;
}

function init_manage_links(what, where) {
    $(what, where).unbind('click').click(function () {            
        var href = $(this).attr('href') ;
        var parts = $(this).attr('href').split('/') ;
        var sp_now = parts.length==2 ? parts[1] : '' ;
    
        manage(this, parts[parts.length-1] + '-' + parts[parts.length-2])

        return false ;
    }) ;
}


function edit_services (property_id) {
    
    child_service_options = {
                autocomplete_data : services,
                autocomplete_options : {
                    autoFill : false,
                    delay    : 10,
                    matchContains: true,
                    minChars     : 0,
                    mustMatch    : true,                // Don't allow new entries to be added from here
                    max          : 0,                   // Show all matches

                    matchSubset: my_matchSubset,
            		formatItem:  my_formatItem,                                    
            		formatMatch: my_formatMatch,
            
                    selectable: function (row) {
                        $('#resp_id').val(row.data.id) ;
                        return true ;
                    }
                    
                }
                
            } ;
    
    timing_options = {
                autocomplete_data : timings,
                autocomplete_options : {
                    autoFill : false,
                    delay    : 10,
                    matchContains: true,
                    minChars     : 0,
                    mustMatch    : true,                // Don't allow new entries to be added from here
                    max          : 0,                   // Show all matches
                    width        : 350,

                    matchSubset: my_matchSubset,
            		formatItem:  my_formatItem,                                    
            		formatMatch: my_formatMatch,
            
                    selectable: function (row) {
                        $('#resp_id').val(row.data.id) ;
                        return true ;
                    }
                    
                }
                
           } ;
    
    options = {  type        : 'recservice_item',
                 placeholder : '<span class="new_rs">Add new service entry here</span>', 
                 event: 'click',
                 tooltip : 'Click to edit a service entry',
                 submit    : 'Save',
                 cancel    : 'Reset',
                 submitdata : add_rt_ids,
                 
                 autoc_timing_options   : timing_options,
                 autoc_child_service_options : child_service_options,
                 
                 // autoc_type_options: type_options,
                 onreset : function (original, revert, settings) {
                        var count = $(original).siblings('td').size() ;
                        var colspan = parseInt($(original).attr('colspan')) ;
                        
                         $(original).siblings('td').show() ;
                         $(original).attr('colspan', colspan-count) ;
                     },
                 afterSubmit : function () { return $('#rt-submit-error').val() <= 0 }
    }

    
    $('#srv-tab td').editable('/proprsv/' + property_id + '/update', options) ;
}



// ---------------------------------------------------------------------------
// The following are specific to records status category.
// ---------------------------------------------------------------------------
    my_rt_matchSubset = function(s, sub, options) {
        s = s.value ;                   // Noel : Allow external versions to access any info

		if (!options.matchCase)
			s = s.toLowerCase();
		var i = s.indexOf(sub);
		if (i == -1) return false;
		return i == 0 || options.matchContains;
	} ;
    
	rt_c_formatItem = function(row, i, max) {                                		
        return row.c_name ;
	} ;
    
	rt_c_formatMatch = function(row, i, max) {
        return row.c_name ;
	} ;
	
    function rt_contact_parse (data) {
        var rows = data.split("\n");
        var index ;
		var parsed = [];
        
        for (var i=0; i < rows.length; i++) {
             var row = $.trim(rows[i]);
             if (row) {
                 row = eval ('(' + row + ')') ;
                 index = parsed.length ;
                 parsed[index] = {} ;                 
                 parsed[index].data     = row ;
                 parsed[index].value    = row.name ;
                 parsed[index].result   = row.name ;
                 parsed[index].data.name = row.name + ' <span class="srch_client">' + row.client + '</span>' ;
             }
         }
		return parsed;
    }


// ---------------------------------------------------------------------------
// The following are specific to records status category.
// ---------------------------------------------------------------------------
    
	rt_t_formatItem = function(row, i, max) {                                		
        return row.type ;
	} ;
    
	rt_t_formatMatch = function(row, i, max) {
        return row.type ;
	} ;


    add_rt_ids = function  (submitdata, original, settings) {
        return false;
    }
    
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
var sections =new Array() ;

function tgl(section, secs) {
    var ct = document.getElementById('c_tab') ;
    if (typeof(secs) == 'undefined' ) {
        secs = sections
    }
    for (i=0; i<secs.length;i++) {
        var sn = secs[i] ; 
        var s = document.getElementById(sn) ;
        var t = document.getElementById('tb_' + sn) ;

        if (s) {
            s.style.display = sn == section ? 'block' : 'none' ;
        }
        $(t).removeClass(sn != section ? 'tab_current' : 'tab_block') ;
        $(t).addClass(sn == section ? 'tab_current' : 'tab_block') ;
        if (ct) {
            ct.value = section ;
        }
    }
    return false;
}                                         


// ---------------------------------------------------------------------------
// If not already available, this loads details of the services before switching
// tabs
// ---------------------------------------------------------------------------
function srvrptgl(section, param) {

    if (typeof(services) != 'object' || typeof(timings) != 'object') {
        $.getScript('/srvlist', function() {
            rptgl(section, param) ;
        }) ;
    } else {
        return rptgl(section, param) ;
    }
    return false;
}


// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
function rptgl(section, param) {
    if (1==1 || $('#l-' + section).size() > 0 || typeof(debug) != 'undefined') {
        if (!param) {
            param = '' ;
        }
        var url = '/prop' + section + '/' + param ;
        var upd_div = '#' + section +'-body' ;

        $.post(url, {container: upd_div})
    }
    return tgl (section) ;
}
cl_debug=1;
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
function cltgl(section, param, override) {
    if ($('#l-' + section).size() > 0 || override || typeof(cl_debug) != 'undefined') {
        if (!param) {
            param = '' ;
        }
        var url = '/' + section + '/' + param ;
        var upd_div = section +'-body' ;

        $.get(url, {container: upd_div}) ;        
    }
    return tgl (section) ;
}


// ---------------------------------------------------------------------------
// Used when adding/removing a property from SRM
// ---------------------------------------------------------------------------
function tglprop_in_srm (item, form_id, adding) {
    var iid   = item.id ;
    var parts = iid.split('-') ;
    var url   = $('#' + form_id).attr('action') ;

    item.parentNode.innerHTML = '<span id="' + iid + '">Updating...</span>'
    params = 'name=' + item.name + '&srm=' + (item.checked ? item.value : '')  + '&update_div=' + iid ;

    $.post (url, params) ;

    return false ;
}



// ---------------------------------------------------------------------------
// The following are specific to the selection of contacts.
// ---------------------------------------------------------------------------
    my_matchSubset = function(s, sub, options) {
        s = s.value ;                   // Noel : Allow external versions to access any info

		if (!options.matchCase)
			s = s.toLowerCase();
		var i = s.indexOf(sub);
		if (i == -1) return false;
		return i == 0 || options.matchContains;
	} ;
    
    // -----------------------------------------------------------------------
    // MY FORMAT ITEM
    // ==============
    // Formats a data row for use with the jquery.ui autocomplete module.
    // For this to work, it MUST be called from the renderItem method,
    // which must then append it to the automcplete object using 
    //
    //         $( "<li></li>" )
    //              .data( "item.autocomplete", item )
    //              .append(my_formatItem(item))
    //              .appendTo( ul )
    // 
    // 
    // -----------------------------------------------------------------------
	my_formatItem = function(row) {                                		
        var lines = '<div class="srch_name">' + row.label + '</div>' ;
        var extra = '' ;
        
        if (row.client) {
            extra = '<p class="srch_client">' + row.client + '</p>' ;
        }
        
        if (row.image) {
            extra += row.image ;
        }
        if (row.subline) {
            extra += '<span class="srch_subl">'+ row.subline + '</span>' ;
        }
        if (row.desc) {
            extra += '<span class="srch_desc">'+ row.desc + '</span>' ;
        }
        if (extra) {
            lines += '<div class="srch-detail clearfix">' + extra + '</div>';
        }

		return lines ; // row.name + "<br /><span style=\"font-size:80%;font-style:italic;color:red\"> [" + row.desc + "]</span>";
	} ;
    
	my_formatMatch = function(row, i, max) {
        return row.name ;
	} ;
	
    function contact_parse (data) {
        var rows = data.split("\n");
        var index ;
		var parsed = [];
        
        for (var i=0; i < rows.length; i++) {
             var row = $.trim(rows[i]);
             if (row) {
                 row = eval ('(' + row + ')') ;
                 index = parsed.length ;
                 parsed[index] = {} ;                 
                 parsed[index].data     = row ;
                 parsed[index].value    = row.name ;
                 parsed[index].result   = row.name ;
                 parsed[index].data.name = row.name + (row.client ? ' <p class="srch_client">' + row.client + '</p>' : '') ;
             }
         }
		return parsed;
    }


    $.fn.replaceContentAndFadeIn = function(newContentElements, callback) { 
        return this.each(function() { 
            // for each matching element, remove the current contents, hide the element, 
            // append the new contents and then fadeIn the element 
            var cback = eval(callback) ;
            $(this).empty().hide().append(newContentElements).fadeIn('slow', function() { if(typeof(cback) == 'function') {cback()}   }); 
        }); 
    };
    
    $.fn.replaceAndFadeIn = function(newContentElements, callback) { 
        var cback = '' ;
        if (callback) {
            try {
                eval ('cback = ' + callback) ;
            } catch(e) {

            }
        }

        return this.each(function() { 
            // for each matching element, remove the current contents, hide the element, 
            // append the new contents and then fadeIn the element 

            $(this).fadeOut('slow', function () {
                $(this).replace(newContentElements)
                .fadeIn('slow', function() { if(typeof(cback) == 'function') {cback()}   }) });
        }); 
    };
    
    $.fn.replaceAndRemoveAndFade = function(newContentElements, removeElement, callback) { 
        var cback = '' ;
        if (callback) {
            try {
                eval ('cback = ' + callback) ;
            } catch(e) {

            }
        }

        return this.each(function() { 
            // for each matching element, remove the current contents, hide the element, 
            // append the new contents and then fadeIn the element 
            var row = this ;

            $(removeElement).fadeOut('slow', function () {
                $(removeElement).remove() ;
                $(row).replace(newContentElements)
                .fadeIn('slow', function() { 
                    if(typeof(cback) == 'function') {
                        cback()
                    }   
                }) 
            });
        }); 
    };
    
    $.fn.replaceAndRemoveAndFadeAfter = function(newContentElements, removeElement, callback) { 
        var cback = '' ;
        if (callback) {
            try {
                eval ('cback = ' + callback) ;
            } catch(e) {

            }
        }

        // for each matching element, remove the current contents, hide the element, 
        // append the new contents and then fadeIn the element 
        return this.each(function() { 
            var row = this ;

            if ($(removeElement).length) {
                $(removeElement).fadeOut('slow', function () {
                    $(removeElement).remove() ;
                    $(row).after(newContentElements)
                    .fadeIn('slow', function() { 
                        $(removeElement).fadeIn('slow', function () {
                            if(typeof(cback) == 'function') {
                                cback()
                            }
                        }) ;
                    }) 
                });
            } else {
                $(row).after(newContentElements)
                .fadeIn('slow', function() { 
                    $(removeElement).fadeIn('slow', function () {
                        if(typeof(cback) == 'function') {
                            cback()
                        }
                    }) ;
                }) 
            }
        }); 
    };
    
    $.fn.beforeParent = function(newContentElements) { 
        return this.each(function() { 
            // for each matching element, remove the current contents, hide the element, 
            // append the new contents and then fadeIn the element 
            $(this).parent().before(newContentElements).fadeIn('slow'); 
        }); 
    };
        
    $.fn.appendAndFadeIn = function(newContentElements, callback) { 
        var cback = '' ;
        if (callback) {
            try {
                eval ('cback = ' + callback) ;
            } catch(e) {

            }
        }
        return this.each(function() { 
            $(this).append(newContentElements).fadeIn('slow', function () {
                if(typeof(cback) == 'function') {
                    cback()
                }
            } ); 
        }); 
    };
        
    $.fn.fadeInBefore = function(newContentElements, callback) { 
        var cback = '' ;
        if (callback) {
            try {
                eval ('cback = ' + callback) ;
            } catch(e) {

            }
        }
        return this.each(function() { 
            $(this).before(newContentElements).fadeIn('slow', function () {
                $(this).hide() ;
                if(typeof(cback) == 'function') {
                    cback()
                }
            } ); 
        }); 
    };
        
    $.fn.removeAndFade = function(callback) { 
        var cback = '' ;

        if (callback) {
            try {
                eval ('cback = ' + callback) ;
            } catch(e) {

            }
        }
        return this.each(function() { 
            $(this).fadeOut('slow', function() {$(this).remove(); if(typeof(cback) == 'function') {cback()} }) ;
        }); 
    };    
    
    $.fn.removeParent = function() { 
        return this.each(function() { 
            $(this).parent().fadeOut('slow', function() {$(this).remove()}) ;
        }); 
    };        
    
    $.fn.showMessageBelow = function(text) {
        return this.each(function() {
            $('<div class="rc-err" />')
                    .replaceContent(text)
                    .insertAfter(jQuery(this))
                    .hide()
                    .fadeIn('slow')
                    .animate({opacity: 1.0}, 150)
                    .fadeOut(8000, function() {
                        jQuery(this).remove();
                    }) ;
        }) ;
    };        

    $.fn.showMessageBelowAsRow = function(text, colspan) {
        text = typeof text == 'object' ? text[0] : text ;
        return this.each(function() {
            $('<tr>')
                    .replaceContent($('<td class="rc-err" colspan="' + colspan + '">').replaceContent(text))
                    .insertAfter(jQuery(this))
                    .hide()
                    .fadeIn('slow')
                    .animate({opacity: 1.0}, 150)
                    .fadeOut(8000, function() {
                        jQuery(this).remove();
                    }) ;
        }) ;
    }; 
    
    
    $.fn.flash = function( color, duration ) {

        var current = this.css( 'color' );

        // this.animate( { color: 'rgb(' + color + ')' }, duration / 2 );
        this.animate( { color: color }, duration / 2 );
        this.animate( { color: current }, duration / 2 );

    }
           
// ---------------------------------------------------------------------------    
// jQuery(document).ready (function () {

 

// 
// /*
//  * Timepicker for Jeditable
//  *
//  * Copyright (c) 2008 Mika Tuupola
//  *
//  * Licensed under the MIT license:
//  *   http://www.opensource.org/licenses/mit-license.php
//  *
//  * Project home:
//  *   http://www.appelsiini.net/projects/jeditable
//  *
//  * Revision: $Id$
//  *
//  */
//  
// $.editable.addInputType('time', {
//     /* Create input element. */
//     element : function(settings, original) {
//         /* Create and pulldowns for hours and minutes. Append them to */
//         /* form which is accessible as variable this.                 */        
//         var hourselect = $('<select id="hour_">');
//         var minselect  = $('<select id="min_">');
//         
//         for (var hour=1; hour <= 24; hour++) {
//             if (hour < 10) {
//                 hour = '0' + hour;
//             }
//             var option = $('<option>').val(hour).append(hour);
//             hourselect.append(option);
//         }
//         $(this).append(hourselect);
// 
//         for (var min=0; min <= 45; min = parseInt(min)+15) {
//             if (min < 10) {
//                 min = '0' + min;
//             }
//             var option = $('<option>').val(min).append(min);
//             minselect.append(option);
//         }
//         $(this).append(minselect);
//                 
//         /* Last create an hidden input. This is returned to plugin. It will */
//         /* later hold the actual value which will be submitted to server.   */
//         var hidden = $('<input type="hidden">');
//         $(this).append(hidden);
//         return(hidden);
//     },
//     /* Set content / value of previously created input element. */
//     content : function(string, settings, original) {
//         
//         /* Select correct hour and minute in pulldowns. */
//         var hour = parseInt(string.substr(0,2));
//         var min  = parseInt(string.substr(3,2));
// 
//         $('#hour_', this).children().each(function() {
//             if (hour == $(this).val()) {
//                 $(this).attr('selected', 'selected');
//             }
//         });
//         $('#min_', this).children().each(function() {
//             if (min == $(this).val()) {
//                 $(this).attr('selected', 'selected')
//             }
//         });
// 
//     },
//     /* Call before submit hook. */
//     submit: function (settings, original) {
//         /* Take values from hour and minute pulldowns. Create string such as    */
//         /* 13:45 from them. Set value of the hidden input field to this string. */
//         var value = $('#hour_').val() + ':' + $('#min_').val();
//         $('input', this).val(value);
//     }
// });
// }) ;

var sp_active = false ;
var d=0
var sp_now='' ;

    // -----------------------------------------------------------------------
    // AJAX SUBMIT
    // ===========
    // Very basic form submission. Result should be a taconite string.
    // -----------------------------------------------------------------------
    function ajaxSubmit (frm) {
        var url   = frm.action ;
        if (url == '') {
            url = document.URL ;
        }
        $.post (url, $(frm).serialize() ) ;

        return false;
    }

    function reinit_users() {
        user_last = null ;

        setTimeout(function() {
            init_manage_links('a.user, a.lincounts, a.props', '#ausers ') ;
            init_manage_links('a#add_user', '') ;
        }, 100) ;
    }
    
    
    function reinit_sp(){
        sp_last = null ;

        setTimeout(function() {
            $('#sp-filter').keypress(function(event) {
                            setTimeout('filter()', 250)
                        }) ;
                    
            $('#sp-filt-form a:not(.dload)').unbind('click').click(function () {            

                if (!sp_active) {
                    var href = $(this).attr('href') ;
                    var parts = $(this).attr('href').split('=') ;
                    sp_now = parts.length==2 ? parts[1] : '' ;
                
                    if (sp_last != sp_now) {
                        sp_active = true ;
                        sp_last = sp_now ;
                        $('#sp-partial').load(href, { let:  sp_now}, function() {
                                sp_active = false
                        }) ;
                    }
                }
                return false ;
            }) ;
            init_manage_links('a.sp', '#abook') ;
            init_manage_links('#esp-0', '') ;
            
        }, 100) ;
    }

    function filter() {
        var sp_now = $('#sp-filter').val() ;
        var client_id = $('#sp_client_id').length > 0 ? $('#sp_client_id').val() : '' ;
        
        if (!sp_active) {
            if (sp_last != sp_now) {
                sp_active = true ;

                sp_last = sp_now
                $('#sp-partial').load('/spro/' + client_id + '/' + 'filter?', {q : sp_now}, function() {
                        sp_active = false
                    }) ;
            }
        }
    }

    function reinit_pnav_links () {
        $('#sp-pnav a').unbind('click').click(function () {            
            var href = $(this).attr('href') ;
            var parts = $(this).attr('href').split('=') ;
            
            // var sp_now = parts.length==2 ? parts[1] : '' ;
            //         
            // sp_active = true ;
            // sp_last = sp_now ;
            $('#sp-partial').load(href, { let:  sp_now}, function() {
                    sp_active = false
            }) ;
            return false ;
        }) ;
    }

    function update_sp (value, settings) {
       $.taconite(value); 
    }

    function getSpValues () {
        return {sp_id : $('#aservp_id').val()} ;
    }

    function aservice_provider(client_id) {
        jQuery('#aservp').editable ('/spro/' + client_id + '/add', {
                                        submitdata : getSpValues,
                                        event     : "mousedown", 
                                        width: "280px",
                                        submit : 'OK',
                                        cancel : 'cancel',
                                        onblur : '',
                                        type   : "autocomplete",
                                        placeholder: 'Click to include an existing service provider',
                                        // callback : update_sp,

                                        autocomplete_data : '/spro/' + client_id + '/addmore',
                                        autocomplete_options : {
                                            matchContains: true,
        		                            parse: asp_parse,
                                            minChars : 0,
                                            minLength: 0,
                                            max          : 0,                   // SHow all matches
    		                            
                                            matchSubset: asp_matchSubset,
                                    		formatItem:  asp_formatItem,                                    
                                    		formatMatch: asp_formatMatch,
                                    
                                            selectable: function (row) {
                                                $('#aservp_id').val(row.data.id) ;
                                                return true ;
                                            },

                                            select: function (event, ui) {
                                                $('#aservp_id').val(ui.item.id) ;
                                                return true ;
                                            },
                                            renderItem: function (ul, item) {
                            					return $( "<li></li>" )
                            						.data( "item.autocomplete", item )
                            						.append('<a>' + sp_formatItem(item) + '</a>')
                            						.appendTo( ul )                                            
                            				}
                                        }
                                    }) ;
                                    
        reinit_sp() ;
        reinit_pnav_links () ;
    }
    
    // -----------------------------------------------------------------------
    // SP FORMAT ITEM
    // ==============
    // -----------------------------------------------------------------------
    sp_formatItem = function (row) {
        return result = 
            '<div class="srch_name">' + 
            '<span class="srch_client">' + row.label +
            (row.client ? ' ' + row.client : '') +
            (row.jtitle ? ' - ' + row.jtitle : '') +
            (row.name   ? ' - ' + row.name   : '') +
            '</span>' +
            '</div>' ;
    }
    
    
    asp_matchSubset = function(s, sub, options) {
        s = s.value ;                   // Noel : Allow external versions to access any info

		if (!options.matchCase)
			s = s.toLowerCase();
		var i = s.indexOf(sub);
		if (i == -1) return false;
		return i == 0 || options.matchContains;
	} ;
    
	asp_formatItem = function(row, i, max) {                                		
        var lines = '<div class="srch_name">' + row.name + '</div>' ;

        var extra = '' ;
        if (row.image) {
            extra += row.image ;
        }
        if (row.subline) {
            extra += '<span class="srch_subl">'+ row.subline + '</span>' ;
        }
        if (row.desc) {
            extra += '<span class="srch_desc">'+ row.desc + '</span>' ;
        }
        if (extra) {
            lines += '<div class="srch-detail clearfix">' + extra + '</div>';
        }

		return lines ;
	} ;
    
	asp_formatMatch = function(row, i, max) {
        return row.name ;
	} ;
	
    // -----------------------------------------------------------------------
    // name is show in the drop down (and can be formatted)
    // result is entered into the input box when the entry is selected
    // value is returned to the server
    // -----------------------------------------------------------------------
    function asp_parse (data) {
        var rows = data.split("\n");
        var index ;
		var parsed = [];

        for (var i=0; i < rows.length; i++) {
             var row = $.trim(rows[i]);
             if (row) {
                 row = eval ('(' + row + ')') ;
                 index = parsed.length ;
                 parsed[index] = {} ;                 
                 parsed[index].data     = row ;
                 parsed[index].value    = row.company ;
                 parsed[index].result   = row.company + ' ' +
                                (row.name ? 
                                    (row.client ? row.client + ' - ' : '') +
                                    (row.jtitle ? row.jtitle + ': ' : '') + row.name : '') ;
                 parsed[index].data.name = row.company + 
                                (row.name ? ' <span class="srch_client">' +
                                    (row.client ? row.client + ' - ' : '') +
                                    (row.jtitle ? row.jtitle + ': ' : '') + row.name + '</span>' : '') ;
             }
        }

		return parsed;
    }



/*
 * jQuery clueTip plugin
 * Version 0.9.8  (05/22/2008)
 * @requires jQuery v1.1.4+
 * @requires Dimensions plugin (for jQuery versions < 1.2.5)
 *
 * Dual licensed under the MIT and GPL licenses:
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.gnu.org/licenses/gpl.html
 *
 */
;(function($) { 
/*
 * @name clueTip
 * @type jQuery
 * @cat Plugins/tooltip
 * @return jQuery
 * @author Karl Swedberg
 *
 * @credit Inspired by Cody Lindley's jTip (http://www.codylindley.com)
 * @credit Thanks to the following people for their many and varied contributions:
      Shelane Enos, Glen Lipka, Hector Santos, Torben Schreiter, Dan G. Switzer, JÃ¶rn Zaefferer 
 * @credit Thanks to Jonathan Chaffer, as always, for help with the hard parts. :-)
 */

 /**
 * 
 * Displays a highly customizable tooltip when the user hovers (default) or clicks (optional) the matched element. 
 * By default, the clueTip plugin loads a page indicated by the "rel" attribute via ajax and displays its contents.
 * If a "title" attribute is specified, its value is used as the clueTip's heading.
 * The attribute to be used for both the body and the heading of the clueTip is user-configurable. 
 * Optionally, the clueTip's body can display content from an element on the same page.
 * * Just indicate the element's id (e.g. "#some-id") in the rel attribute.
 * Optionally, the clueTip's body can display content from the title attribute, when a delimiter is indicated. 
 * * The string before the first instance of the delimiter is set as the clueTip's heading.
 * * All subsequent strings are wrapped in separate DIVs and placed in the clueTip's body.
 * The clueTip plugin allows for many, many more options. Pleasee see the examples and the option descriptions below...
 * 
 * 
 * @example $('#tip).cluetip();
 * @desc This is the most basic clueTip. It displays a 275px-wide clueTip on mouseover of the element with an ID of "tip." On mouseout of the element, the clueTip is hidden.
 *
 *
 * @example $('a.clue').cluetip({
 *  hoverClass: 'highlight',
 *  sticky: true,
 *  closePosition: 'bottom',
 *  closeText: '<img src="cross.png" alt="close" />',
 *  truncate: 60,
 *  ajaxSettings: {
 *    type: 'POST'
 *  }
 * });
 * @desc Displays a clueTip on mouseover of all <a> elements with class="clue". The hovered element gets a class of "highlight" added to it (so that it can be styled appropriately. This is esp. useful for non-anchor elements.). The clueTip is "sticky," which means that it will not be hidden until the user either clicks on its "close" text/graphic or displays another clueTip. The "close" text/graphic is set to diplay at the bottom of the clueTip (default is top) and display an image rather than the default "Close" text. Moreover, the body of the clueTip is truncated to the first 60 characters, which are followed by an ellipsis (...). Finally, the clueTip retrieves the content using POST rather than the $.ajax method's default "GET."
 * 
 * More examples can be found at http://plugins.learningjquery.com/cluetip/demo/
 * 
 * Full list of options/settings can be found at the bottom of this file and at http://plugins.learningjquery.com/cluetip/
 */

  var $cluetip, $cluetipInner, $cluetipOuter, $cluetipTitle, $cluetipArrows, $dropShadow, imgCount;
  $.fn.cluetip = function(js, options) {
    if (typeof js == 'object') {
      options = js;
      js = null;
    }
    return this.each(function(index) {
      var $this = $(this);      
      
      // support metadata plugin (v1.0 and 2.0)
      var opts = $.extend(false, {}, $.fn.cluetip.defaults, options || {}, $.metadata ? $this.metadata() : $.meta ? $this.data() : {});

      // start out with no contents (for ajax activation)
      var cluetipContents = false;
      var cluezIndex = parseInt(opts.cluezIndex, 10)-1;
      var isActive = false, closeOnDelay = 0;

      // create the cluetip divs
      if (!$('#cluetip').length) {
        $cluetipInner = $('<div id="cluetip-inner"></div>');
        $cluetipTitle = $('<h3 id="cluetip-title"></h3>');        
        $cluetipOuter = $('<div id="cluetip-outer"></div>').append($cluetipInner).prepend($cluetipTitle);
        $cluetip = $('<div id="cluetip"></div>').css({zIndex: opts.cluezIndex})
        .append($cluetipOuter).append('<div id="cluetip-extra"></div>')[insertionType](insertionElement).hide();
        $('<div id="cluetip-waitimage"></div>').css({position: 'absolute', zIndex: cluezIndex-1})
        .insertBefore('#cluetip').hide();
        $cluetip.css({position: 'absolute', zIndex: cluezIndex});
        $cluetipOuter.css({position: 'relative', zIndex: cluezIndex+1});
        $cluetipArrows = $('<div id="cluetip-arrows" class="cluetip-arrows"></div>').css({zIndex: cluezIndex+1}).appendTo('#cluetip');
      }
      var dropShadowSteps = (opts.dropShadow) ? +opts.dropShadowSteps : 0;
      if (!$dropShadow) {
        $dropShadow = $([]);
        for (var i=0; i < dropShadowSteps; i++) {
          $dropShadow = $dropShadow.add($('<div></div>').css({zIndex: cluezIndex-i-1, opacity:.1, top: 1+i, left: 1+i}));
        };
        $dropShadow.css({position: 'absolute', backgroundColor: '#000'})
        .prependTo($cluetip);
      }
      var tipAttribute = $this.attr(opts.attribute), ctClass = opts.cluetipClass;
      if (!tipAttribute && !opts.splitTitle && !js) return true;
      // if hideLocal is set to true, on DOM ready hide the local content that will be displayed in the clueTip      
      if (opts.local && opts.hideLocal) { $(tipAttribute + ':first').hide(); }
      var tOffset = parseInt(opts.topOffset, 10), lOffset = parseInt(opts.leftOffset, 10);
      // vertical measurement variables
      var tipHeight, wHeight;
      var defHeight = isNaN(parseInt(opts.height, 10)) ? 'auto' : (/\D/g).test(opts.height) ? opts.height : opts.height + 'px';
      var sTop, linkTop, posY, tipY, mouseY, baseline;
      // horizontal measurement variables
      var tipInnerWidth = isNaN(parseInt(opts.width, 10)) ? 275 : parseInt(opts.width, 10);
      var tipWidth = tipInnerWidth + (parseInt($cluetip.css('paddingLeft'))||0) + (parseInt($cluetip.css('paddingRight'))||0) + dropShadowSteps;
      var linkWidth = this.offsetWidth;
      var linkLeft, posX, tipX, mouseX, winWidth;
            
      // parse the title
      var tipParts;
      var tipTitle = (opts.attribute != 'title') ? $this.attr(opts.titleAttribute) : '';
      if (opts.splitTitle) {
        if(tipTitle == undefined) {tipTitle = '';}
        tipParts = tipTitle.split(opts.splitTitle);
        tipTitle = tipParts.shift();
      }
      var localContent;

/***************************************      
* ACTIVATION
****************************************/
    
//activate clueTip
    var activate = function(event) {
      if (!opts.onActivate($this)) {
        return false;
      }
      isActive = true;
      $cluetip.removeClass().css({width: tipInnerWidth});
      if (tipAttribute == $this.attr('href')) {
        $this.css('cursor', opts.cursor);
      }
      $this.attr('title','');
      if (opts.hoverClass) {
        $this.addClass(opts.hoverClass);
      }
      linkTop = posY = $this.offset().top;
      linkLeft = $this.offset().left;
      mouseX = event.pageX;
      mouseY = event.pageY;
      if ($this[0].tagName.toLowerCase() != 'area') {
        sTop = $(document).scrollTop();
        winWidth = $(window).width();
      }
// position clueTip horizontally
      if (opts.positionBy == 'fixed') {
        posX = linkWidth + linkLeft + lOffset;
        $cluetip.css({left: posX});
      } else {
        posX = (linkWidth > linkLeft && linkLeft > tipWidth)
          || linkLeft + linkWidth + tipWidth + lOffset > winWidth 
          ? linkLeft - tipWidth - lOffset 
          : linkWidth + linkLeft + lOffset;
        if ($this[0].tagName.toLowerCase() == 'area' || opts.positionBy == 'mouse' || linkWidth + tipWidth > winWidth) { // position by mouse
          if (mouseX + 20 + tipWidth > winWidth) {  
            $cluetip.addClass(' cluetip-' + ctClass);
            posX = (mouseX - tipWidth - lOffset) >= 0 ? mouseX - tipWidth - lOffset - parseInt($cluetip.css('marginLeft'),10) + parseInt($cluetipInner.css('marginRight'),10) :  mouseX - (tipWidth/2);
          } else {
            posX = mouseX + lOffset;
          }
        }
        var pY = posX < 0 ? event.pageY + tOffset : event.pageY;
        $cluetip.css({left: (posX > 0 && opts.positionBy != 'bottomTop') ? posX : (mouseX + (tipWidth/2) > winWidth) ? winWidth/2 - tipWidth/2 : Math.max(mouseX - (tipWidth/2),0)});
      }
        wHeight = $(window).height();

/***************************************
* load a string from cluetip method's first argument
***************************************/
      if (js) {
        $cluetipInner.html(js);
        cluetipShow(pY);
      }
/***************************************
* load the title attribute only (or user-selected attribute). 
* clueTip title is the string before the first delimiter
* subsequent delimiters place clueTip body text on separate lines
***************************************/

      else if (tipParts) {
        var tpl = tipParts.length;
        for (var i=0; i < tpl; i++){
          if (i == 0) {
            $cluetipInner.html(tipParts[i]);
          } else { 
            $cluetipInner.append('<div class="split-body">' + tipParts[i] + '</div>');
          }            
        };
        cluetipShow(pY);
      }
/***************************************
* load external file via ajax          
***************************************/

      else if (!opts.local && tipAttribute.indexOf('#') != 0) {
        if (cluetipContents && opts.ajaxCache) {
          $cluetipInner.html(cluetipContents);
          cluetipShow(pY);
        }
        else {
          var ajaxSettings = opts.ajaxSettings;
          ajaxSettings.url = tipAttribute;
          ajaxSettings.beforeSend = function() {
            $cluetipOuter.children().empty();
            if (opts.waitImage) {
              $('#cluetip-waitimage')
              .css({top: mouseY+20, left: mouseX+20})
              .show();
            }
          };
         ajaxSettings.error = function() {
            if (isActive) {
              $cluetipInner.html('<i>sorry, the contents could not be loaded</i>');
            }
          };
          ajaxSettings.success = function(data) {
            cluetipContents = opts.ajaxProcess(data);
            if (isActive) {
              $cluetipInner.html(cluetipContents);
            }
          };
          ajaxSettings.complete = function() {
          	imgCount = $('#cluetip-inner img').length;
        		if (imgCount && !$.browser.opera) {
        		  $('#cluetip-inner img').load(function() {
          			imgCount--;
          			if (imgCount<1) {
          				$('#cluetip-waitimage').hide();
          			  if (isActive) cluetipShow(pY);
          			}
        		  }); 
        		} else {
      				$('#cluetip-waitimage').hide();
        		  if (isActive) cluetipShow(pY);    
        		} 
          };
          $.ajax(ajaxSettings);
        }

/***************************************
* load an element from the same page
***************************************/
      } else if (opts.local){
        var $localContent = $(tipAttribute + ':first');
        var localCluetip = $.fn.wrapInner ? $localContent.wrapInner('<div></div>').children().clone(true) : $localContent.html();
        $.fn.wrapInner ? $cluetipInner.empty().append(localCluetip) : $cluetipInner.html(localCluetip);
        cluetipShow(pY);
      }
    };

// get dimensions and options for cluetip and prepare it to be shown
    var cluetipShow = function(bpY) {
      $cluetip.addClass('cluetip-' + ctClass);
      
      if (opts.truncate) { 
        var $truncloaded = $cluetipInner.text().slice(0,opts.truncate) + '...';
        $cluetipInner.html($truncloaded);
      }
      function doNothing() {}; //empty function
      tipTitle ? $cluetipTitle.show().html(tipTitle) : (opts.showTitle) ? $cluetipTitle.show().html('&nbsp;') : $cluetipTitle.hide();
      if (opts.sticky) {
        var $closeLink = $('<div id="cluetip-close"><a href="#">' + opts.closeText + '</a></div>');
        (opts.closePosition == 'bottom') ? $closeLink.appendTo($cluetipInner) : (opts.closePosition == 'title') ? $closeLink.prependTo($cluetipTitle) : $closeLink.prependTo($cluetipInner);
        $closeLink.click(function() {
          cluetipClose();
          return false;
        });
        if (opts.mouseOutClose) {
          if ($.fn.hoverIntent && opts.hoverIntent) { 
            $cluetip.hoverIntent({
              over: doNothing, 
              timeout: opts.hoverIntent.timeout,  
              out: function() { $closeLink.trigger('click'); }
            });
          } else {
            $cluetip.hover(doNothing, 
            function() {$closeLink.trigger('click'); });
          }
        } else {
          $cluetip.unbind('mouseout');
        }
      }
// now that content is loaded, finish the positioning 
      var direction = '';
      $cluetipOuter.css({overflow: defHeight == 'auto' ? 'visible' : 'auto', height: defHeight});
      tipHeight = defHeight == 'auto' ? Math.max($cluetip.outerHeight(),$cluetip.height()) : parseInt(defHeight,10);   
      tipY = posY;
      baseline = sTop + wHeight;
      if (opts.positionBy == 'fixed') {
        tipY = posY - opts.dropShadowSteps + tOffset;
      } else if ( (posX < mouseX && Math.max(posX, 0) + tipWidth > mouseX) || opts.positionBy == 'bottomTop') {
        if (posY + tipHeight + tOffset > baseline && mouseY - sTop > tipHeight + tOffset) { 
          tipY = mouseY - tipHeight - tOffset;
          direction = 'top';
        } else { 
          tipY = mouseY + tOffset;
          direction = 'bottom';
        }
      } else if ( posY + tipHeight + tOffset > baseline ) {
        tipY = (tipHeight >= wHeight) ? sTop : baseline - tipHeight - tOffset;
      } else if ($this.css('display') == 'block' || $this[0].tagName.toLowerCase() == 'area' || opts.positionBy == "mouse") {
        tipY = bpY - tOffset;
      } else {
        tipY = posY - opts.dropShadowSteps;
      }
      if (direction == '') {
        posX < linkLeft ? direction = 'left' : direction = 'right';
      }
      $cluetip.css({top: tipY + 'px'}).removeClass().addClass('clue-' + direction + '-' + ctClass).addClass(' cluetip-' + ctClass);
      if (opts.arrows) { // set up arrow positioning to align with element
        var bgY = (posY - tipY - opts.dropShadowSteps);
        $cluetipArrows.css({top: (/(left|right)/.test(direction) && posX >=0 && bgY > 0) ? bgY + 'px' : /(left|right)/.test(direction) ? 0 : ''}).show();
      } else {
        $cluetipArrows.hide();
      }

// (first hide, then) ***SHOW THE CLUETIP***
      $dropShadow.hide();
      $cluetip.hide()[opts.fx.open](opts.fx.open != 'show' && opts.fx.openSpeed);
      if (opts.dropShadow) $dropShadow.css({height: tipHeight, width: tipInnerWidth}).show();
      if ($.fn.bgiframe) { $cluetip.bgiframe(); }
      // trigger the optional onShow function
      if (opts.delayedClose > 0) {
        closeOnDelay = setTimeout(cluetipClose, opts.delayedClose);
      }
      opts.onShow($cluetip, $cluetipInner, cluetipClose);
      
    };

/***************************************
   =INACTIVATION
-------------------------------------- */
    var inactivate = function() {
      isActive = false;
      $('#cluetip-waitimage').hide();
      if (!opts.sticky || (/click|toggle/).test(opts.activation) ) {
        cluetipClose();
clearTimeout(closeOnDelay);        
      };
      if (opts.hoverClass) {
        $this.removeClass(opts.hoverClass);
      }
      $('.cluetip-clicked').removeClass('cluetip-clicked');
    };
// close cluetip and reset some things
    var cluetipClose = function() {
      $cluetipOuter 
      .parent().hide().removeClass().end()
      .children().empty();
      if (tipTitle) {
        $this.attr(opts.titleAttribute, tipTitle);
      }
      $this.css('cursor','');
      if (opts.arrows) $cluetipArrows.css({top: ''});
    };

/***************************************
   =BIND EVENTS
-------------------------------------- */
  // activate by click
      if ( (/click|toggle/).test(opts.activation) ) {
        $this.click(function(event) {
          if ($cluetip.is(':hidden') || !$this.is('.cluetip-clicked')) {
            activate(event);
            $('.cluetip-clicked').removeClass('cluetip-clicked');
            $this.addClass('cluetip-clicked');

          } else {
            inactivate(event);

          }
          this.blur();
          return false;
        });
  // activate by focus; inactivate by blur    
      } else if (opts.activation == 'focus') {
        $this.focus(function(event) {
          activate(event);
        });
        $this.blur(function(event) {
          inactivate(event);
        });
  // activate by hover
    // clicking is returned false if cluetip url is same as href url
      } else {
        $this.click(function() {
          if ($this.attr('href') && $this.attr('href') == tipAttribute && !opts.clickThrough) {
            return false;
          }
        });
        //set up mouse tracking
        var mouseTracks = function(evt) {
          if (opts.tracking == true) {
            var trackX = posX - evt.pageX;
            var trackY = tipY ? tipY - evt.pageY : posY - evt.pageY;
            $this.mousemove(function(evt) {
              $cluetip.css({left: evt.pageX + trackX, top: evt.pageY + trackY });
            });
          }
        };
        if ($.fn.hoverIntent && opts.hoverIntent) {
          $this.mouseover(function() {$this.attr('title',''); })
          .hoverIntent({
            sensitivity: opts.hoverIntent.sensitivity,
            interval: opts.hoverIntent.interval,  
            over: function(event) {
              activate(event);
              mouseTracks(event);
            }, 
            timeout: opts.hoverIntent.timeout,  
            out: function(event) {inactivate(event); $this.unbind('mousemove');}
          });           
        } else {
          $this.hover(function(event) {
            activate(event);
            mouseTracks(event);
          }, function(event) {
            inactivate(event);
            $this.unbind('mousemove');
          });
        }
      }
    });
  };
  
/*
 * options for clueTip
 *
 * each one can be explicitly overridden by changing its value. 
 * for example: $.fn.cluetip.defaults.width = 200; 
 * would change the default width for all clueTips to 200. 
 *
 * each one can also be overridden by passing an options map to the cluetip method.
 * for example: $('a.example').cluetip({width: 200}); 
 * would change the default width to 200 for clueTips invoked by a link with class of "example"
 *
 */
  
  $.fn.cluetip.defaults = {  // set up default options
    width:            275,      // The width of the clueTip
    height:           'auto',   // The height of the clueTip
    cluezIndex:       97,       // Sets the z-index style property of the clueTip
    positionBy:       'auto',   // Sets the type of positioning: 'auto', 'mouse','bottomTop', 'fixed'
    topOffset:        15,       // Number of px to offset clueTip from top of invoking element
    leftOffset:       15,       // Number of px to offset clueTip from left of invoking element
    local:            false,    // Whether to use content from the same page for the clueTip's body
    hideLocal:        true,     // If local option is set to true, this determines whether local content
                                // to be shown in clueTip should be hidden at its original location
    attribute:        'rel',    // the attribute to be used for fetching the clueTip's body content
    titleAttribute:   'title',  // the attribute to be used for fetching the clueTip's title
    splitTitle:       '',       // A character used to split the title attribute into the clueTip title and divs
                                // within the clueTip body. more info below [6]
    showTitle:        true,     // show title bar of the clueTip, even if title attribute not set
    cluetipClass:     'default',// class added to outermost clueTip div in the form of 'cluetip-' + clueTipClass.
    hoverClass:       '',       // class applied to the invoking element onmouseover and removed onmouseout
    waitImage:        true,     // whether to show a "loading" img, which is set in jquery.cluetip.css
    cursor:           'help',
    arrows:           false,    // if true, displays arrow on appropriate side of clueTip
    dropShadow:       true,     // set to false if you don't want the drop-shadow effect on the clueTip
    dropShadowSteps:  6,        // adjusts the size of the drop shadow
    sticky:           false,    // keep visible until manually closed
    mouseOutClose:    false,    // close when clueTip is moused out
    activation:       'hover',  // set to 'click' to force user to click to show clueTip
                                // set to 'focus' to show on focus of a form element and hide on blur
    clickThrough:     false,    // if true, and activation is not 'click', then clicking on link will take user to the link's href,
                                // even if href and tipAttribute are equal
    tracking:         false,    // if true, clueTip will track mouse movement (experimental)
    delayedClose:     0,        // close clueTip on a timed delay (experimental)
    closePosition:    'top',    // location of close text for sticky cluetips; can be 'top' or 'bottom' or 'title'
    closeText:        'Close',  // text (or HTML) to to be clicked to close sticky clueTips
    truncate:         0,        // number of characters to truncate clueTip's contents. if 0, no truncation occurs

    // effect and speed for opening clueTips
    fx: {             
                      open:       'show', // can be 'show' or 'slideDown' or 'fadeIn'
                      openSpeed:  ''
    },     

    // settings for when hoverIntent plugin is used             
    hoverIntent: {    
                      sensitivity:  3,
              			  interval:     50,
              			  timeout:      0
    },

    // function to run just before clueTip is shown.           
    onActivate:       function(e) {return true;},

    // function to run just after clueTip is shown.
    onShow:           function(ct, c){},
    
    // whether to cache results of ajax request to avoid unnecessary hits to server    
    ajaxCache:        true,  

    // process data retrieved via xhr before it's displayed
    ajaxProcess:      function(data) {
                        data = data.replace(/<s(cript|tyle)(.|\s)*?\/s(cript|tyle)>/g, '').replace(/<(link|title)(.|\s)*?\/(link|title)>/g,'');
                        return data;
    },                

    // can pass in standard $.ajax() parameters, not including error, complete, success, and url
    ajaxSettings: {   
                      dataType: 'html'
    },
    debug: false
  };


/*
 * Global defaults for clueTips. Apply to all calls to the clueTip plugin.
 *
 * @example $.cluetip.setup({
 *   insertionType: 'prependTo',
 *   insertionElement: '#container'
 * });
 * 
 * @property
 * @name $.cluetip.setup
 * @type Map
 * @cat Plugins/tooltip
 * @option String insertionType: Default is 'appendTo'. Determines the method to be used for inserting the clueTip into the DOM. Permitted values are 'appendTo', 'prependTo', 'insertBefore', and 'insertAfter'
 * @option String insertionElement: Default is 'body'. Determines which element in the DOM the plugin will reference when inserting the clueTip.
 *
 */
   
  var insertionType = 'appendTo', insertionElement = 'body';
  $.cluetip = {};
  $.cluetip.setup = function(options) {
    if (options && options.insertionType && (options.insertionType).match(/appendTo|prependTo|insertBefore|insertAfter/)) {
      insertionType = options.insertionType;
    }
    if (options && options.insertionElement) {
      insertionElement = options.insertionElement;
    }
  };
  
})(jQuery);


// This function gets called when the end-user clicks on some date.
function selected(cal, date) {   
        
    if (cal.sel) {
        if (cal.sel.tagName == 'INPUT') {
            cal.sel.value = date; // just update the date in the input field.
        } else {
            cal.sel.innerHTML = date; // just update the date in the input field.
        }
    }
    var update = (cal.dateClicked);
        
    if (update && cal.darea) {
        if (cal.darea.tagName == 'INPUT') {
            cal.darea.value = date; // just update the date in the input field.
        } else {
            cal.darea.innerHTML = date; // just update the date in the input field.
        }
    }

    if (update && cal.onChange) {
        cal.onChange (cal, date) ;
    }

            
    if (update && cal.dateClicked)
        cal.callCloseHandler();    
    
    if (dateIsSpecial(date, cal.date.getFullYear(), cal.date.getMonth(), cal.date.getDate())) {
        alert('Please note that this is a public holiday')
    }
        
        
//  if (cal.dateClicked && (cal.sel.id == "sel1" || cal.sel.id == "sel3"))
    // if we add this call we close the calendar on single-click.
    // just to exemplify both cases, we are using this only for the 1st
    // and the 3rd field, while 2nd and 4th will still require double-click.
//    cal.callCloseHandler();
}

// And this gets called when the end-user clicks on the _selected_ date,
// or clicks on the "Close" button.  It just hides the calendar without
// destroying it.
function closeHandler(cal) {
  cal.hide();                        // hide the calendar
//  cal.destroy();
  _dynarch_popupCalendar = null;
}

// This function shows the calendar under the element having the given id.
// It takes care of catching "mousedown" signals on document and hiding the
// calendar if the click was outside.               

function showCalendar(id, format, displayAreaId, showsTime, showsOtherMonths, onChange) {
  var el = document.getElementById(id);
  var da = document.getElementById(displayAreaId);
  
  if (_dynarch_popupCalendar != null) {
    // we already have some calendar created
    _dynarch_popupCalendar.hide();                 // so we hide it first.
  } else {
    // first-time call, create the calendar.
    var cal = new Calendar(1, null, selected, closeHandler);

    // uncomment the following line to hide the week numbers
    // cal.weekNumbers = false;
    if (typeof showsTime == "string") {
      cal.showsTime = true;
      cal.time24 = (showsTime == "24");
    }
    if (showsOtherMonths) {
      cal.showsOtherMonths = true;
    }
    _dynarch_popupCalendar = cal;                  // remember it in the global var
    cal.setRange(1900, 2070);        // min/max year allowed.
    cal.setDateStatusHandler(dateIsSpecial);
    cal.setDateToolTipHandler(calToolTips) ; 
    cal.create();

    if (onChange && typeof(onChange) == "function") {
        cal.onChange = onChange ;
    }
  }
  _dynarch_popupCalendar.setDateFormat(format);    // set the specified date format
  if (displayAreaId) {
      _dynarch_popupCalendar.parseDate(da.innerHTML);      // try to parse the text in field

  } else if (el.tagName == 'INPUT') {
      _dynarch_popupCalendar.parseDate(el.value);      // try to parse the text in field
  } else { 
      _dynarch_popupCalendar.parseDate(el.innerHTML);      // try to parse the text in field
  }
  _dynarch_popupCalendar.sel = el;                 // inform it what input field we use
  _dynarch_popupCalendar.darea = da ;

  // the reference element that we pass to showAtElement is the button that
  // triggers the calendar.  In this example we align the calendar bottom-right
  // to the button.                
  
  _dynarch_popupCalendar.showAtElement(displayAreaId ? da : el, "Br");        // show the calendar

  return false;
}

var MINUTE = 60 * 1000;
var HOUR = 60 * MINUTE;
var DAY = 24 * HOUR;
var WEEK = 7 * DAY;

// If this handler returns true then the "date" given as
// parameter will be disabled.  In this example we enable
// only days within a range of 10 days from the current
// date.
// You can use the functions date.getFullYear() -- returns the year
// as 4 digit number, date.getMonth() -- returns the month as 0..11,
// and date.getDate() -- returns the date of the month as 1..31, to
// make heavy calculations here.  However, beware that this function
// should be very fast, as it is called for each day in a month when
// the calendar is (re)constructed.
function isDisabled(date) {
  var today = new Date();
  return (Math.abs(date.getTime() - today.getTime()) / DAY) > 10;
}

function flatSelected(cal, date) {
  var el = document.getElementById("preview");
  el.innerHTML = date;
}

// ---------------------------------------------------------------------------
// DATE IS SPECIAL
// ===============
// This works in conjunction with a php produced array of public holdays. If
// the passed date is found in the set, this returns a string of 'special',
// which the calendar uses as part of the CSS for the date cell.
// ---------------------------------------------------------------------------
function dateIsSpecial(date, year, month, day) {
    if (typeof(SPECIAL_DATES) != 'undefined' && typeof(SPECIAL_DATES[year]) != 'undefined') {
        var y = SPECIAL_DATES[year];
        if (typeof(SPECIAL_DATES[year][month]) != 'undefined' && y[month]) {
            var m = y[month] ;
            for(var d=0; d< m.length;d++) {
                if (m[d][0] == day) {
                    return 'special' ;             
                }
            }
        }                            
    }
    return false;
};

function calToolTips(date, year, month, day) {
    if (typeof(SPECIAL_DATES) != 'undefined' && typeof(SPECIAL_DATES[year]) != 'undefined') {
        var y = SPECIAL_DATES[year];
        if (typeof(SPECIAL_DATES[year][month]) != 'undefined' && y[month]) {
            var m = y[month] ;
            for(var d=0; d< m.length;d++) {
                if (m[d][0] == day) {
                    return m[d][1] ;
                }
            }
        }
    }
    return false ;
}

function showFlatCalendar() {
  var parent = document.getElementById("display");

  // construct a calendar giving only the "selected" handler.
  var cal = new Calendar(0, null, flatSelected);

  // hide week numbers
  cal.weekNumbers = false;

  // We want some dates to be disabled; see function isDisabled above
  cal.setDisabledHandler(isDisabled);
  cal.setDateFormat("%A, %B %e");

  // this call must be the last as it might use data initialized above; if
  // we specify a parent, as opposite to the "showCalendar" function above,
  // then we create a flat calendar -- not popup.  Hidden, though, but...
  cal.create(parent);

  // ... we can show it here.
  cal.show();
}

// jQuery Context Menu Plugin
//
// Version 1.00
//
// Cory S.N. LaViska
// A Beautiful Site (http://abeautifulsite.net/)
//
// Visit http://abeautifulsite.net/notebook/80 for usage and more information
//
// Terms of Use
//
// This software is licensed under a Creative Commons License and is copyrighted
// (C)2008 by Cory S.N. LaViska.
//
// For details, visit http://creativecommons.org/licenses/by/3.0/us/
//
// Noel
//      Changed event bind/unbind to use namespacing.
//      Added support for input tags in menu (triggered by pressing return)
//      Added support for an initialisation callback
// 
if(jQuery)( function() {
	$.extend($.fn, {
		
		contextMenu: function(o, callback) {
			// Defaults
			if( o.menu == undefined ) return false;
			if( o.inSpeed == undefined ) o.inSpeed = 150;
			if( o.outSpeed == undefined ) o.outSpeed = 75;
			// 0 needs to be -1 for expected results (no fade)
			if( o.inSpeed == 0 ) o.inSpeed = -1;
			if( o.outSpeed == 0 ) o.outSpeed = -1;
            if (o.init == undefined) {
                o.init = function () {} ;
            }

			// Loop each context menu
			$(this).each( function() {
				var el = $(this);
				var offset = $(el).offset();
				// Add contextMenu class
                // $('#' + o.menu).addClass('contextMenu').
                //     unbind('click.sn_cmenu').
                //     bind('click.sn_cmenu', function () {
                //                      return false;
                //                  }) ;
                
				$('#' + o.menu).addClass('contextMenu') ;
                // $(document).unbind('click.sn_cmenu').
                //     bind('click.sn_cmenu', function () {
                //                      return false;
                //                  }) ;
				
                // if (!shadow) {
                  var shadow = $('<div class="shadow"></div>')
                             .css({backgroundColor:'#000',position:'absolute',opacity:0.2,zIndex:499})
                             .appendTo('body')
                             .hide();
                // }                
				
				
                function getPosition (e) {
            		// Detect mouse position
            		var d = {}, x, y;
            		if( self.innerHeight ) {
            			d.pageYOffset = self.pageYOffset;
            			d.pageXOffset = self.pageXOffset;
            			d.innerHeight = self.innerHeight;
            			d.innerWidth = self.innerWidth;
            		} else if( document.documentElement &&
            			document.documentElement.clientHeight ) {
            			d.pageYOffset = document.documentElement.scrollTop;
            			d.pageXOffset = document.documentElement.scrollLeft;
            			d.innerHeight = document.documentElement.clientHeight;
            			d.innerWidth = document.documentElement.clientWidth;
            		} else if( document.body ) {
            			d.pageYOffset = document.body.scrollTop;
            			d.pageXOffset = document.body.scrollLeft;
            			d.innerHeight = document.body.clientHeight;
            			d.innerWidth = document.body.clientWidth;
            		}
            		(e.pageX) ? x = e.pageX : x = e.clientX + d.scrollLeft;
            		(e.pageY) ? y = e.pageY : x = e.clientY + d.scrollTop;

            		return {x: x, y: y}
                }
				
				
				// Simulate a true right click
				$(this).bind('mousedown.sn_cmenu', function(e) {
					var evt = e;

                    // -------------------------------------------------------
                    // Causes problems!! (eg Prevents buttons being clicked)
                    // -------------------------------------------------------
                    // $(document).unbind('click.sn_cmenu').
                    //     bind('click.sn_cmenu', function () {
                    //         $(document).unbind('click.sn_cmenu').unbind('keypress');
                    //         return false;
                    //     }) ;
					
					$(this).bind('mouseup.sn_cmenu', function(e) {
						var srcElement = $(this);
						$(this).unbind('mouseup.sn_cmenu');
						
						if( evt.button == 2 ) {
							var ele = {element: srcElement, target: $(e.target)} ;

							// Hide context menus that may be showing
							$(".contextMenu").hide();
							$(".shadow").hide();


							// Get this context menu
							var menu = $('#' + o.menu);

                            // -----------------------------------------------
                            // Call the init routine to allow it to update the
                            // menu contents with item specific data., or cancel
                            // the request if in-appropriate.
                            // As we're initalising the object in a generic 
                            // manner, it can't assume the srcElement is the
                            // actual target. Instead, we pass in the target
                            // from the event object as it's more likely to 
                            // be the correct target.
                            // -----------------------------------------------
							if (!o.init(menu, ele)) {
                                return false;
							}
							srcElement = ele.element ;

							menu.appendTo('body') ;
														
							if( $(el).hasClass('disabled') ) return false;
                            pos = getPosition(e) ;
							
							// Show the menu
							$(document).unbind('click.sn_cmenu').unbind('keypress');
							
							$(menu).css({ top: pos.y, left: pos.x }).fadeIn(o.inSpeed);
                            shadow.css({width:menu.width(), 
                                        height:menu.height(),
                                        top: pos.y + 3, left: pos.x + 3 }).show();


							// Hover events
							$(menu).find('A').mouseover( function() {
								$(menu).find('LI.hover').removeClass('hover');
								$(this).parent().addClass('hover');
							}).mouseout( function() {
								$(menu).find('LI.hover').removeClass('hover');
							});
							
							// Keyboard
                            $(document).keypress( function(e) {
                             switch( e.keyCode ) {
                                 case 38: // up
                                     if( $(menu).find('LI.hover').size() == 0 ) {
                                         $(menu).find('LI:last').addClass('hover');
                                     } else {
                                         $(menu).find('LI.hover').removeClass('hover').prevAll('LI:not(.disabled)').eq(0).addClass('hover');
                                         if( $(menu).find('LI.hover').size() == 0 ) $(menu).find('LI:last').addClass('hover');
                                     }
                                     return false ; 
                                 break;
                                 case 40: // down
                                     if( $(menu).find('LI.hover').size() == 0 ) {
                                         $(menu).find('LI:first').addClass('hover');
                                     } else {
                                         $(menu).find('LI.hover').removeClass('hover').nextAll('LI:not(.disabled)').eq(0).addClass('hover');
                                         if( $(menu).find('LI.hover').size() == 0 ) $(menu).find('LI:first').addClass('hover');
                                     }
                                     return false ; 
                                 break;
                                 case 13: // enter
                                     $(menu).find('LI.hover A').trigger('click');
                                     return false;
                                 break;
                                 case 27: // esc
                                     $(document).trigger('click');
                                     return false ; 
                                 break
                             }
                            });

							// When items are selected
							$('#' + o.menu).find('A').unbind('click');
							$('#' + o.menu).find('LI:not(.disabled) A').click( function(event) {
							    if (event.target.tagName == 'A') {
    								$(document).unbind('click.sn_cmenu').unbind('keypress');
    								$(".contextMenu").hide();
									$(shadow).hide();

    								// Callback
    								if( callback ) callback( $(this).attr('href').substr(1), $(srcElement), {x: pos.x - offset.left, y: pos.y - offset.top, docX: pos.x, docY: pos.y} );
								}
								return false;
							});
							
							// Hide bindings
							setTimeout( function() { // Delay for Mozilla
								$(document).bind('click.sn_cmenu', function() {
									$(document).unbind('click.sn_cmenu').unbind('keypress');
									$(menu).fadeOut(o.outSpeed);
									$(shadow).hide();
									return false;
								});
							}, 0);
						}
					});
				});
				
                // // Disable text selection
                // if( $.browser.mozilla ) {
                //  $('#' + o.menu).each( function() { $(this).css({ 'MozUserSelect' : 'none' }); });
                // } else if( $.browser.msie ) {
                //  $('#' + o.menu).each( function() { $(this).bind('selectstart.disableTextSelect', function() { return false; }); });
                // } else {
                //  $('#' + o.menu).each(function() { $(this).bind('mousedown.disableTextSelect', function() { return false; }); });
                // }
				// Disable browser context menu (requires both selectors to work in IE/Safari + FF/Chrome)
				
				$(el).add('UL.contextMenu').bind('contextmenu', function() { return false; });
				
			});
			return $(this);
		},
		

		// Disable context menu items on the fly
		disableContextMenuItems: function(o) {
			if( o == undefined ) {
				// Disable all
				$(this).find('LI').addClass('disabled');
				return( $(this) );
			}
			$(this).each( function() {
				if( o != undefined ) {
					var d = o.split(',');
					for( var i = 0; i < d.length; i++ ) {
						$(this).find('A[href="' + d[i] + '"]').parent().addClass('disabled');
						
					}
				}
			});
			return( $(this) );
		},
		
		// Enable context menu items on the fly
		enableContextMenuItems: function(o) {
			if( o == undefined ) {
				// Enable all
				$(this).find('LI.disabled').removeClass('disabled');
				return( $(this) );
			}
			$(this).each( function() {
				if( o != undefined ) {
					var d = o.split(',');
					for( var i = 0; i < d.length; i++ ) {
						$(this).find('A[href="' + d[i] + '"]').parent().removeClass('disabled');
						
					}
				}
			});
			return( $(this) );
		},
		
		// Disable context menu(s)
		disableContextMenu: function() {
			$(this).each( function() {
				$(this).addClass('disabled');
			});
			return( $(this) );
		},
		
		// Enable context menu(s)
		enableContextMenu: function() {
			$(this).each( function() {
				$(this).removeClass('disabled');
			});
			return( $(this) );
		},
		
		// Destroy context menu(s)
		destroyContextMenu: function() {
			// Destroy specified context menus
			$(this).each( function() {
				// Disable action
				$(this).unbind('mousedown.cn_cmenu').unbind('mouseup.sn_cmenu');
			});
			return( $(this) );
		}
		
	});
})(jQuery);

// jQuery File Tree Plugin
//
// Version 1.01
//
// Cory S.N. LaViska
// A Beautiful Site (http://abeautifulsite.net/)
// 24 March 2008
//
// Visit http://abeautifulsite.net/notebook.php?article=58 for more information
//
// Usage: $('.fileTreeDemo').fileTree( options, callback )
//
// Options:  root           - root folder to display; default = /
//           script         - location of the serverside AJAX file to use; default = jqueryFileTree.php
//           folderEvent    - event to trigger expand/collapse; default = click
//           expandSpeed    - default = 500 (ms); use -1 for no animation
//           collapseSpeed  - default = 500 (ms); use -1 for no animation
//           expandEasing   - easing function to use on expand (optional)
//           collapseEasing - easing function to use on collapse (optional)
//           multiFolder    - whether or not to limit the browser to one subfolder at a time
//           loadMessage    - Message to display while initial tree loads (can be HTML)
//
// History:
//
// 1.10 - N. Walsh. Added support for right and double click. (1 Jan 2009)
//          Double click is both poor and messy (as always), as it's nigh on impossible
//          to detect the double click without also pocessing the single click. The best
//          approach would be to add a short delay via setTimeout, but even that can't
//          guarantee it because the double click delay is variable. Instead, have opted
//          to leave as an immediate response to the single click, but attempt to ignore
//          the result if detect a double. This uses fiddly checks for a 'doubleClicked' 
//          and 'posted' status, but doesn't work well (includes moving setting expanded
//          state to the post event to allow it to be skipped ).
//
//          Small optimisation - moved repeated long selector referenves to variable,
//          although negated by the duplication added to acter for doubleclicking.
// 
//          Moved remove of the loading messge into the post response and deleted the
//          html clear of the same (which was being done after the elemetn was removed)
//          Moved the removeClass statements into the complete state of the slideUp to
// 
//          ensure they remained visible until the end. Added a wait around the collapse.
// 1.01 - updated to work with foreign characters in directory/file names (12 April 2008)
// 1.00 - released (24 March 2008)
//
// 2.00   Noel. Restructured much of the tree. Now process only click event (folderEvent 
//              is redundant) and use a generic event handler so new items can be added
//              without needing to re-iniitalise the tree.
// 
// TERMS OF USE
// 
// jQuery File Tree is licensed under a Creative Commons License and is copyrighted (C)2008 by Cory S.N. LaViska.
// For details, visit http://creativecommons.org/licenses/by/3.0/us/
//

if(jQuery) (function($){
	
	$.extend($.fn, {
		fileTree: function(o, h) {
			// Defaults
			if( !o ) var o = {};
			if( o.root == undefined ) o.root = '/';
			if( o.script == undefined ) o.script = 'jqueryFileTree.php';
			if( o.folderEvent == undefined ) o.folderEvent = 'click';
			if( o.expandSpeed == undefined ) o.expandSpeed= 500;
			if( o.collapseSpeed == undefined ) o.collapseSpeed= 500;
			if( o.expandEasing == undefined ) o.expandEasing = null;
			if( o.collapseEasing == undefined ) o.collapseEasing = null;
			if( o.multiFolder == undefined ) o.multiFolder = true;
			if( o.loadMessage == undefined ) o.loadMessage = 'Loading...';
			if( o.folderEvent == 'dblclick' || o.doubleClick == undefined || !$.isFunction(o.doubleClick)) o.doubleClick = null ;
			if( o.contextMenu == undefined) o.contextMenu = null ;
			if( o.onSelect == undefined) o.onSelect = function () {} ;
			
			$(this).each( function() {
			    var doubleClicked = false ;
				var posted = false ;
				var tree = this ;

				function showTree(c, t, flag) {
                    var ul = $(c).find('UL:hidden:lt(2)')
                    if( o.root == t ) {
                        ul.show(); 
                    
				        bindTree (c) ;

                        var ul = $(c).find('UL:hidden:lt(2)')
                        if( o.root == t ) {
                            ul.show(); 
                        }
                        
				    } else if (!doubleClicked) {
    					$(c).addClass('wait');
    					posted = true ;
    					done = true ;
    					$.post(o.script, { dir: t }, function(data) {
    					    if (!doubleClicked) {
                                $(".jqueryFileTree.start").remove();
                                // $(c).find('.start').html('');
        						$(c).append(data);

                                var ul = $(c).find('UL:hidden:lt(2)')
                                if( o.root == t ) 
                                    ul.show(); 
                                    
                                else if (ul.length > 0) {
                                    done = false;
                                    ul.slideDown({ duration: o.expandSpeed, easing: o.expandEasing, 
                                            complete:function() { $(c).removeClass('wait')} });
                                }
        						bindTree(c);
        						if (flag) {
        						    $(c).removeClass('collapsed').addClass('expanded');
        						}
    						}
    						if (done) {
    						    $(c).removeClass('wait') ;
						    }
                            // posted = doubleClicked = false ;
    						posted = false ;
    					});
					}
				}
				
				function bindTree(t) {
				    if (o.contextMenu) {
                        $(t).find('LI').unbind('contextmenu.fileTree').bind('contextmenu.fileTree', function(event) {
    					    event.stopPropagation() ;           // Cancel default context menu
					        
					        o.contextMenu(event, $(this)) ;
					    
    				    })
				    }
				    // -------------------------------------------------------
				    // DOUBLE CLICK - now rename
				    // The following code was supposed to be client based. 
				    // Unfortunatley, when added as a callback handler, all 
				    // attempts to change the html of the link caused the link
				    // to be deleted. Until that's fixed, it stays here.
				    // -------------------------------------------------------
                    if (o.doubleClick) {
                        $(t).find('LI').unbind('dblclick.fileTree').bind('dblclick.fileTree', function(event) {
                            if (!doubleClicked) {
                                 doubleClicked = true ;
                                 event.stopPropagation() ;
                                 $(this).removeClass('wait');
                                    
                                    // o.doubleClick (event, this) ;
                                    var text = $.trim($('a:eq(0)', this).text()) ;
                                    $(this).data('html', $(this).html()) ;
                                    $(this).data('value', text) ;
                                    var input = $('<input type="text" value="' + text + '" size="12" />') ;
                                    
                                    var link = $('a:eq(0)', this).hide().before(input) ;
                                
                                    $(document).bind('mousedown.tree', function (event) {
                                        if (event.target != input[0]) {
                                            $(document).unbind('mousedown.tree') ;
                                            input.remove() ;
                                            link.show().text(text) ;
                                            doubleClicked = false ;
                                        }
                                    }) ;
                                
                                    input.blur(function() {
                                        $(this).remove() ;
                                        link.show() ;
                                        doubleClicked = false ;
                                        $(document).unbind('mousedown.tree') ;
                                 
                                    }).keypress(function (event){
                                        if (event.keyCode == 13) {
                                            text = $(this).val() ;
                                            $(this).remove() ;
                                            link.show().text(text) ;
                                    
                                            o.doubleClick(event, link) ;
                                            $(document).unbind('mousedown.tree') ;
                                            doubleClicked = false ;
                                    
                                        } else if (event.keyCode == 27) {
                                            $(this).remove() ;
                                            link.show() ;

                                            $(document).unbind('mousedown.tree') ;
                                            doubleClicked = false ;
                                        }
                                    })
                     
                                 setTimeout(function () { 
                                     if (!posted) {
                                            // doubleClicked = false ;
                                     }
                                 }, 1000) ;
                            }
                            return false;
                         })
                    }

                    // $(t).find('LI A').bind('click.select', function() {
					$(t).bind('click.select', function(event) {

                        var target = $(event.target) ;
                        var tag, parent, parentTag ;

                        while (target.length && target[0] != $(t)[0]) {
                            tag = $(target)[0].tagName ;
                            parent = target.parent() ;
                            parentTag = parent ? $(parent)[0].tagName : '' ;
                            
                            if (tag == 'A' && parentTag == 'LI') {
                                $(tree).find('.selected').removeClass('selected') ;
        					    target.addClass('selected') ;
        					    o.onSelect (target) ;

        					    break ;
        					    
                            } else if (tag == 'LI') {
                                ceTree(target) ;
                                break ;
                            }
                            target = parent ;
                        }
					    event.stopPropagation() ;           // Cancel default action
                        return false;

				    })
			
			
                    // -------------------------------------------------------
                    // CollapseExpandTREE
                    // =================
                    // -------------------------------------------------------
                    function ceTree(target) {
                        
                        $('a:eq(0)', target).each (function (event) {
  					        if( $(this).parent().hasClass('directory') ) {
  					            var parent = $(this).parent() ;

    							if( parent.hasClass('collapsed') ) {
    								// Expand
    								if( !o.multiFolder ) {
    									parent.parent().find('UL').slideUp({ duration: o.collapseSpeed, easing: o.collapseEasing }).end
    									               .find('LI.directory').removeClass('expanded').addClass('collapsed');
    								}
                                    // parent.find('UL').remove(); // cleanup
                                    // showTree( parent, escape($(this).attr('rel').match( /.*\// )), true );
    // NW remove dynamic ajax loading
    								var ul = parent.find('UL:eq(0)') ;
    								if (ul.length) {
                    					parent.addClass('wait');
        								ul.slideDown({ duration: o.expandSpeed, easing: o.expandEasing,
        								                            complete: function() {parent.removeClass('wait collapsed').addClass('expanded')}} );
                                    } else {
                                        parent.removeClass('wait expanded').addClass('collapsed') ;
                                    }
    							} else {
    								// Collapse
    								var ul = parent.find('UL:eq(0)') ;
    								if (ul.length) {
                    					parent.addClass('wait');
        								ul.slideUp({ duration: o.collapseSpeed, easing: o.collapseEasing,
        								                            complete: function() {parent.removeClass('wait expanded').addClass('collapsed')}} );
                                    } else {
                                        parent.removeClass('wait expanded').addClass('collapsed') ;
                                    }
    							}
  					            
				            }
			            })
			
				    }


//                  $(t).find('LI').bind(o.folderEvent, function(event) {
//                      if (event.target.tagName.toLowerCase() != 'li') {
//                          return false ;          // Clicks due to bubble on the rename's <input tag
//                      }
// 
//                    $('a:eq(0)', this).each (function (event) {
//                      if( $(this).parent().hasClass('directory') ) {
//                          var parent = $(this).parent() ;
// 
//                          if( parent.hasClass('collapsed') ) {
// 
//                              // Expand
//                              if( !o.multiFolder ) {
//                                  parent.parent().find('UL').slideUp({ duration: o.collapseSpeed, easing: o.collapseEasing }).end
//                                                 .find('LI.directory').removeClass('expanded').addClass('collapsed');
//                              }
//                                 // parent.find('UL').remove(); // cleanup
//                                 // showTree( parent, escape($(this).attr('rel').match( /.*\// )), true );
// // NW remove dynamic ajax loading
//                              var ul = parent.find('UL:eq(0)') ;
//                              if (ul.length) {
//                                  parent.addClass('wait');
//                                  ul.slideDown({ duration: o.expandSpeed, easing: o.expandEasing,
//                                                              complete: function() {parent.removeClass('wait collapsed').addClass('expanded')}} );
//                                 } else {
//                                     parent.removeClass('wait expanded').addClass('collapsed') ;
//                                 }
// 
//                              
//                          } else {
//                              // Collapse
//                              var ul = parent.find('UL:eq(0)') ;
//                              if (ul.length) {
//                                  parent.addClass('wait');
//                                  ul.slideUp({ duration: o.collapseSpeed, easing: o.collapseEasing,
//                                                              complete: function() {parent.removeClass('wait expanded').addClass('collapsed')}} );
//                                 } else {
//                                     parent.removeClass('wait expanded').addClass('collapsed') ;
//                                 }
//                          }
//                         // } else {
//                         //  h($(this).attr('rel'));
//                      }
//                      return false;
//                  });
//                      return false;
//              });
				
					// Prevent A from triggering the # on non-click events
//					if( o.folderEvent.toLowerCase != 'click' ) $(t).find('LI A').bind('click', function() { return false; });
				}
				// Loading message
                // $(this).html('<ul class="jqueryFileTree start"><li class="wait">' + o.loadMessage + '<li></ul>');
				// Get the initial file list
				showTree( $(this), escape(o.root) );
			});
		}
	});
	
})(jQuery);

/*
 * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/
 *
 * Uses the built In easIng capabilities added In jQuery 1.1
 * to offer multiple easIng options
 *
 * Copyright (c) 2007 George Smith
 * Licensed under the MIT License:
 *   http://www.opensource.org/licenses/mit-license.php
 */

// t: current time, b: begInnIng value, c: change In value, d: duration
jQuery.easing['jswing'] = jQuery.easing['swing'];

jQuery.extend( jQuery.easing,
{
	def: 'easeOutQuad',
	swing: function (x, t, b, c, d) {
		//alert(jQuery.easing.default);
		return jQuery.easing[jQuery.easing.def](x, t, b, c, d);
	},
	easeInQuad: function (x, t, b, c, d) {
		return c*(t/=d)*t + b;
	},
	easeOutQuad: function (x, t, b, c, d) {
		return -c *(t/=d)*(t-2) + b;
	},
	easeInOutQuad: function (x, t, b, c, d) {
		if ((t/=d/2) < 1) return c/2*t*t + b;
		return -c/2 * ((--t)*(t-2) - 1) + b;
	},
	easeInCubic: function (x, t, b, c, d) {
		return c*(t/=d)*t*t + b;
	},
	easeOutCubic: function (x, t, b, c, d) {
		return c*((t=t/d-1)*t*t + 1) + b;
	},
	easeInOutCubic: function (x, t, b, c, d) {
		if ((t/=d/2) < 1) return c/2*t*t*t + b;
		return c/2*((t-=2)*t*t + 2) + b;
	},
	easeInQuart: function (x, t, b, c, d) {
		return c*(t/=d)*t*t*t + b;
	},
	easeOutQuart: function (x, t, b, c, d) {
		return -c * ((t=t/d-1)*t*t*t - 1) + b;
	},
	easeInOutQuart: function (x, t, b, c, d) {
		if ((t/=d/2) < 1) return c/2*t*t*t*t + b;
		return -c/2 * ((t-=2)*t*t*t - 2) + b;
	},
	easeInQuint: function (x, t, b, c, d) {
		return c*(t/=d)*t*t*t*t + b;
	},
	easeOutQuint: function (x, t, b, c, d) {
		return c*((t=t/d-1)*t*t*t*t + 1) + b;
	},
	easeInOutQuint: function (x, t, b, c, d) {
		if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
		return c/2*((t-=2)*t*t*t*t + 2) + b;
	},
	easeInSine: function (x, t, b, c, d) {
		return -c * Math.cos(t/d * (Math.PI/2)) + c + b;
	},
	easeOutSine: function (x, t, b, c, d) {
		return c * Math.sin(t/d * (Math.PI/2)) + b;
	},
	easeInOutSine: function (x, t, b, c, d) {
		return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
	},
	easeInExpo: function (x, t, b, c, d) {
		return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
	},
	easeOutExpo: function (x, t, b, c, d) {
		return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
	},
	easeInOutExpo: function (x, t, b, c, d) {
		if (t==0) return b;
		if (t==d) return b+c;
		if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
		return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
	},
	easeInCirc: function (x, t, b, c, d) {
		return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;
	},
	easeOutCirc: function (x, t, b, c, d) {
		return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
	},
	easeInOutCirc: function (x, t, b, c, d) {
		if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
		return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
	},
	easeInElastic: function (x, t, b, c, d) {
		var s=1.70158;var p=0;var a=c;
		if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
		if (a < Math.abs(c)) { a=c; var s=p/4; }
		else var s = p/(2*Math.PI) * Math.asin (c/a);
		return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
	},
	easeOutElastic: function (x, t, b, c, d) {
		var s=1.70158;var p=0;var a=c;
		if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
		if (a < Math.abs(c)) { a=c; var s=p/4; }
		else var s = p/(2*Math.PI) * Math.asin (c/a);
		return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
	},
	easeInOutElastic: function (x, t, b, c, d) {
		var s=1.70158;var p=0;var a=c;
		if (t==0) return b;  if ((t/=d/2)==2) return b+c;  if (!p) p=d*(.3*1.5);
		if (a < Math.abs(c)) { a=c; var s=p/4; }
		else var s = p/(2*Math.PI) * Math.asin (c/a);
		if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
		return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
	},
	easeInBack: function (x, t, b, c, d, s) {
		if (s == undefined) s = 1.70158;
		return c*(t/=d)*t*((s+1)*t - s) + b;
	},
	easeOutBack: function (x, t, b, c, d, s) {
		if (s == undefined) s = 1.70158;
		return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
	},
	easeInOutBack: function (x, t, b, c, d, s) {
		if (s == undefined) s = 1.70158; 
		if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
		return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
	},
	easeInBounce: function (x, t, b, c, d) {
		return c - jQuery.easing.easeOutBounce (x, d-t, 0, c, d) + b;
	},
	easeOutBounce: function (x, t, b, c, d) {
		if ((t/=d) < (1/2.75)) {
			return c*(7.5625*t*t) + b;
		} else if (t < (2/2.75)) {
			return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
		} else if (t < (2.5/2.75)) {
			return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
		} else {
			return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
		}
	},
	easeInOutBounce: function (x, t, b, c, d) {
		if (t < d/2) return jQuery.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b;
		return jQuery.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b;
	}
});

// jQuery Alert Dialogs Plugin
//
// Version 1.1
//
// Cory S.N. LaViska
// A Beautiful Site (http://abeautifulsite.net/)
// 14 May 2009
//
// Visit http://abeautifulsite.net/notebook/87 for more information
//
// Usage:
//		jAlert( message, [title, callback] )
//		jConfirm( message, [title, callback] )
//		jPrompt( message, [value, title, callback] )
// 
// History:
//
//		1.00 - Released (29 December 2008)
//
//		1.01 - Fixed bug where unbinding would destroy all resize events
//
// License:
// 
// This plugin is dual-licensed under the GNU General Public License and the MIT License and
// is copyright 2008 A Beautiful Site, LLC. 
//
(function($) {
	
	$.alerts = {
		
		// These properties can be read/written by accessing $.alerts.propertyName from your scripts at any time
		
		verticalOffset: -75,                // vertical offset of the dialog from center screen, in pixels
		horizontalOffset: 0,                // horizontal offset of the dialog from center screen, in pixels/
		repositionOnResize: true,           // re-centers the dialog on window resize
		overlayOpacity: .01,                // transparency level of overlay
		overlayColor: '#FFF',               // base color of overlay
		draggable: true,                    // make the dialogs draggable (requires UI Draggables plugin)
		okButton: '&nbsp;OK&nbsp;',         // text for the OK button
		cancelButton: '&nbsp;Cancel&nbsp;', // text for the Cancel button
		dialogClass: null,                  // if specified, this class will be applied to all dialogs
		
		// Public methods
		
		alert: function(message, title, callback) {
			if( title == null ) title = 'Alert';
			$.alerts._show(title, message, null, 'alert', function(result) {
				if( callback ) callback(result);
			});
		},
		
		confirm: function(message, title, callback) {
			if( title == null ) title = 'Confirm';
			$.alerts._show(title, message, null, 'confirm', function(result) {
				if( callback ) callback(result);
			});
		},
			
		prompt: function(message, value, title, callback) {
			if( title == null ) title = 'Prompt';
			$.alerts._show(title, message, value, 'prompt', function(result) {
				if( callback ) callback(result);
			});
		},
		
		// Private methods
		
		_show: function(title, msg, value, type, callback) {
			
			$.alerts._hide();
			$.alerts._overlay('show');
			
			$("BODY").append(
			  '<div id="popup_container">' +
			    '<h1 id="popup_title"></h1>' +
			    '<div id="popup_content">' +
			      '<div id="popup_message"></div>' +
				'</div>' +
			  '</div>');
			
			if( $.alerts.dialogClass ) $("#popup_container").addClass($.alerts.dialogClass);
			
			// IE6 Fix
			var pos = ($.browser.msie && parseInt($.browser.version) <= 6 ) ? 'absolute' : 'fixed'; 
			
			$("#popup_container").css({
				position: pos,
				zIndex: 99999,
				padding: 0,
				margin: 0
			});
			
			$("#popup_title").text(title);
			$("#popup_content").addClass(type);
			$("#popup_message").text(msg);
			$("#popup_message").html( $("#popup_message").text().replace(/\n/g, '<br />') );
			
			$("#popup_container").css({
				minWidth: $("#popup_container").outerWidth(),
				maxWidth: $("#popup_container").outerWidth()
			});
			
			$.alerts._reposition();
			$.alerts._maintainPosition(true);
			
			switch( type ) {
				case 'alert':
					$("#popup_message").after('<div id="popup_panel"><input type="button" value="' + $.alerts.okButton + '" id="popup_ok" /></div>');
					$("#popup_ok").click( function() {
						$.alerts._hide();
						callback(true);
					});
					$("#popup_ok").focus().keypress( function(e) {
						if( e.keyCode == 13 || e.keyCode == 27 ) $("#popup_ok").trigger('click');
					});
				break;
				case 'confirm':
					$("#popup_message").after('<div id="popup_panel"><input type="button" value="' + $.alerts.okButton + '" id="popup_ok" /> <input type="button" value="' + $.alerts.cancelButton + '" id="popup_cancel" /></div>');
					$("#popup_ok").click( function() {
						$.alerts._hide();
						if( callback ) callback(true);
					});
					$("#popup_cancel").click( function() {
						$.alerts._hide();
						if( callback ) callback(false);
					});
					$("#popup_ok").focus();
					$("#popup_ok, #popup_cancel").keypress( function(e) {
						if( e.keyCode == 13 ) $("#popup_ok").trigger('click');
						if( e.keyCode == 27 ) $("#popup_cancel").trigger('click');
					});
				break;
				case 'prompt':
					$("#popup_message").append('<br /><input type="text" size="30" id="popup_prompt" />').after('<div id="popup_panel"><input type="button" value="' + $.alerts.okButton + '" id="popup_ok" /> <input type="button" value="' + $.alerts.cancelButton + '" id="popup_cancel" /></div>');
					$("#popup_prompt").width( $("#popup_message").width() );
					$("#popup_ok").click( function() {
						var val = $("#popup_prompt").val();
						$.alerts._hide();
						if( callback ) callback( val );
					});
					$("#popup_cancel").click( function() {
						$.alerts._hide();
						if( callback ) callback( null );
					});
					$("#popup_prompt, #popup_ok, #popup_cancel").keypress( function(e) {
						if( e.keyCode == 13 ) $("#popup_ok").trigger('click');
						if( e.keyCode == 27 ) $("#popup_cancel").trigger('click');
					});
					if( value ) $("#popup_prompt").val(value);
					$("#popup_prompt").focus().select();
				break;
			}
			
			// Make draggable
			if( $.alerts.draggable ) {
				try {
					$("#popup_container").draggable({ handle: $("#popup_title") });
					$("#popup_title").css({ cursor: 'move' });
				} catch(e) { /* requires jQuery UI draggables */ }
			}
		},
		
		_hide: function() {
			$("#popup_container").remove();
			$.alerts._overlay('hide');
			$.alerts._maintainPosition(false);
		},
		
		_overlay: function(status) {
			switch( status ) {
				case 'show':
					$.alerts._overlay('hide');
					$("BODY").append('<div id="popup_overlay"></div>');
					$("#popup_overlay").css({
						position: 'absolute',
						zIndex: 99998,
						top: '0px',
						left: '0px',
						width: '100%',
						height: $(document).height(),
						background: $.alerts.overlayColor,
						opacity: $.alerts.overlayOpacity
					});
				break;
				case 'hide':
					$("#popup_overlay").remove();
				break;
			}
		},
		
		_reposition: function() {
			var top = (($(window).height() / 2) - ($("#popup_container").outerHeight() / 2)) + $.alerts.verticalOffset;
			var left = (($(window).width() / 2) - ($("#popup_container").outerWidth() / 2)) + $.alerts.horizontalOffset;
			if( top < 0 ) top = 0;
			if( left < 0 ) left = 0;
			
			// IE6 fix
			if( $.browser.msie && parseInt($.browser.version) <= 6 ) top = top + $(window).scrollTop();
			
			$("#popup_container").css({
				top: top + 'px',
				left: left + 'px'
			});
			$("#popup_overlay").height( $(document).height() );
		},
		
		_maintainPosition: function(status) {
			if( $.alerts.repositionOnResize ) {
				switch(status) {
					case true:
						$(window).bind('resize', $.alerts._reposition);


					break;
					case false:
						$(window).unbind('resize', $.alerts._reposition);
					break;
				}
			}
		}
		
	}
	
	// Shortuct functions
	jAlert = function(message, title, callback) {
		$.alerts.alert(message, title, callback);
	}
	
	jConfirm = function(message, title, callback) {
		$.alerts.confirm(message, title, callback);
	};
		
	jPrompt = function(message, value, title, callback) {
		$.alerts.prompt(message, value, title, callback);
	};
	
})(jQuery);

//Mouse status  
var imgParentOffset = {left :0, top :0} ;
var activity = {active : false, clickedImage : 0, clonedImage : 0, parentOffsetLeft : 0, parentOffsetTop : 0} ;
var maxID = 0 ;

var selector = $("#selector");
var asb_main = $("#asb-main");
var site_detail = $("#site-detail");
var asb_plan = $("#asb-plan");
var asb_plan1 = $("#asb-plan1");
var asb_tbar = $('#tbar') ;
var asb_zdiv = $('#zin-d') ;
var fplanImage = $('#fplan-image') ;
var asb_detail= $('#asb-detail') ;
var building = $('#building') ;
var noplans  = $('#noplans') ;
var marker = $("#marker");  
var icons  = $(".icon");

var moffset = asb_main.length ? asb_main.offset() : {left : 0, top : 0};
var soffset = selector.length ? selector.offset() : {left : 0, top : 0};

var startPointX = soffset.left - moffset.left ;
var startPointY = soffset.top  - moffset.top ;// + parseInt($('#toolbar').css('padding-top')) ;

asb_plan.css('left', -100000) ;
asb_plan1.show() ;
asb_plan.show() ;
asb_tbar.hide() ;

var maxX = asb_plan.width() ;
var maxY = asb_plan.height() ;

asb_plan.hide() ;
asb_plan1.hide() ;
asb_plan.css('left', asb_main.css('left')) ;

var drawing = false ;
var readOnly = false ;

function prepare_asbestos_editor (property_id, schedule_id, readonly) {
    readOnly = readonly ;

    selector = $("#selector");
    asb_main = $("#asb-main");
    site_detail = $("#site-detail");
    asb_plan = $("#asb-plan");
    asb_plan1 = $("#asb-plan1");
    asb_tbar = $('#tbar') ;
    asb_zdiv = $('#zin-d') ;
    fplanImage = $('#fplan-image') ;
    asb_detail= $('#asb-detail') ;
    building = $('#building') ;
    noplans  = $('#noplans') ;
    marker = $("#marker");  
    icons  = $(".icon");

    moffset = asb_main.length ? asb_main.offset() : {left : 0, top : 0};
    soffset = selector.length ? selector.offset() : {left : 0, top : 0};

    startPointX = soffset.left - moffset.left ;
    startPointY = soffset.top  - moffset.top ;// + parseInt($('#toolbar').css('padding-top')) ;

    
    bind_plans(property_id, schedule_id, '#siteTree' ) ;
    $('#siteTree').fadeIn() ;
    $('#addpoint').fadeIn() ;
    if (!readonly) {
        marker.css({'left': startPointX, 'top': startPointY});
    } else {
        marker.css({'left': -1000, 'top': -1000});
        setTreeOptions() ;
    }
    
    icons.fadeIn(1500);     
    moveicon(icons) ;
}


// ---------------------------------------------------------------------------
// Position the initial image and assign event handlers
// ---------------------------------------------------------------------------
    

// $(document).mousemove (function (e) {
//     if (activity.clickedImage) {
//         activity.clickedImage.css({ 
//                         top: e.pageY - activity.parentOffsetTop, 
//                         left: e.pageX - activity.parentOffsetLeft}) ;
//     }
// })

function setTreeOptions () {
    $('#topts input').unbind('click').bind('click', function () {
        var type = $(this).val() ;
        if ($(this).attr('checked') === true) {
            $('#siteTree a.pt-' + type).show() ;
            if (type == 'no-asb') {
                $('#siteTree a.pt-asb-rem').show() ;
            }
        } else {
            $('#siteTree a.pt-' + type).hide() ;
            if (type == 'no-asb') {
                $('#siteTree a.pt-asb-rem').hide() ;
            }
        }
        asb_detail.hide();
    })
}


function setTreeHover (what) {
    $(what).hover(
        function () {
            var id_parts = $(this).attr('id').split('-') ;

            id_parts[0] = 'pt' ;
            $('#' + id_parts.join('-')).addClass('hover') ;
        },
        function () {
            var id_parts = $(this).attr('id').split('-') ;
            id_parts[0] = 'pt' ;
            $('#' + id_parts.join('-')).removeClass('hover') ;
        }
    ) ;
}

// ---------------------------------------------------------------------------
// MOVE ICON
// =========
// Wrapper around the mouse event handlers to enable this to be called elsewhere.
// ---------------------------------------------------------------------------
function moveicon(which) {

    add_cm_points ($(which).not('#marker')) ;
    if (!readOnly) {    
        add_cm_tree ('#siteTree') ;
    }
    $('#marker').data('tree_id', '--') ;

    setTreeHover ('#' + which.data('tree_id')) ;

    // -----------------------------------------------------------------------
    // Mouse Down
    // Always attempts to initiate dragging for icons on the plan.
    // Only allows the marker to be dragged when the currently selected row
    // in the tree is an area or one of its children.
    // -----------------------------------------------------------------------
    which.mousedown (function (e) {
        if (e.button == 2) {
            // showPopup(e, $(this)) ;
            
        } else if (e.button <= 1) {
            if (activity.clickedImage != 0) {
                activity.clickedImage.removeClass("active") ;
            }
            var target = $('a.selected', '#siteTree') ;

            if  ($(this).hasClass('point') || target.parents('.area:eq(0)').length > 0) {
                activity.clickedImage = $(this) ;
                
                activity.startX = this.offsetLeft ;
                activity.startY = this.offsetTop ;
                
                activity.parentOffsetLeft = e.pageX - this.offsetLeft ; 
                activity.parentOffsetTop  = e.pageY - this.offsetTop ; 
                activity.destination = target ;
                
                // ---------------------------------------------------------------
                // If adding a new image, rather than dragging an existing one,
                // create a clone to remain in the tool bar
                // ---------------------------------------------------------------
                if (activity.clickedImage.attr('id') == 'marker') {
                    activity.clonedImage = activity.clickedImage.
                                                clone(false).
                                                insertBefore(activity.clickedImage).
                                                attr('id', 'clone');
                } else {
                    activity.id = activity.clickedImage.attr('id') ;
                    var id_parts = activity.id.split('-') ;
                    id_parts[0] = 'prp' ;
                    activity.treepoint = $('#' + id_parts.join('-')) ;
                    activity.treepoint.addClass('active-point') ;
                }
                if (!readOnly) {
                    $(document).unbind('mousemove.points').bind('mousemove.points', function (e) {
                        if (activity.clickedImage) {
                            activity.clickedImage.css({ 
                                            top: e.pageY - activity.parentOffsetTop, 
                                            left: e.pageX - activity.parentOffsetLeft}) ;
                        }
                    })
                    activity.clickedImage.css({ opacity: 0.55, 'z-order':10}).
                                    addClass("active") ;
                    drawing = true ;
                }

                $('#hint').hide();
            }

            return false;
        }
        
    // -----------------------------------------------------------------------
    // Mouse Up
    // Only relevant when dragging (activity.clickedImage is set)
    // If dragging an existing image, it is either moved to the new location or
    // deleted (if outside of the plan).
    // If adding a new one, a new clone is taken and positioned on the plan.
    // -----------------------------------------------------------------------
    }).mouseup (function (e) {
        // var maxX = asb_plan.width() ;
        // var maxY = asb_plan.height() ;
        
        var maxX = fplanImage.width() ;
        var maxY = fplanImage.height () ;
        
        var scale = asb_zdiv.data('nwZoom.scale') ;

        if (activity.clickedImage != 0) {
            $(document).unbind('mousemove.points') ;
            
            var actualX = parseInt(activity.clickedImage.css('left')) ;
            var actualY = parseInt(activity.clickedImage.css('top'));
            var curX ;
            var curY ;
            
            if (scale && scale != 1) {
                maxX = maxX / scale ;
                maxY = maxY / scale ;
                curX = actualX / scale ;
                curY = actualY / scale ;
            } else {
                curX = actualX ;
                curY = actualY ;
            }

            // -------------------------------------------------------------------
            // Checks extremes, ignoring any border or padding
            // -------------------------------------------------------------------
            if (curX < 0 && curX > -activity.clickedImage.width() ) {
                curX = 0 ;
            } else if (curX > (maxX - activity.clickedImage.width()) && curX <= maxX) {
                curX = maxX - activity.clickedImage.width() ;
            }

            if (curY < 0 && curY > -activity.clickedImage.height() ) {
                curY = 0 ;
            } else if (curY > (maxY - activity.clickedImage.height()) && curY < maxY) {
                curY = maxY - activity.clickedImage.width() ;
            }

            // -------------------------------------------------------------------
            // If the floor plan has an image (non-zero width and height) and the 
            // icon has been dragged out of it, remove from the display
            // -------------------------------------------------------------------
            if (maxX > 0 && maxY > 0 &&
                    (curX < 0 || curX > maxX || curY < 0 || curY > maxY)) {
                if (activity.clonedImage) {                    
                    activity.clickedImage.css('opacity', 1) ;
                    activity.clickedImage.animate(
                                { top: startPointY,
                                  left: startPointX},
                                  '500', 
                                  'swing', 
                                  function () {
                                    activity.clickedImage.removeClass("active") ;
                                    if (activity.clonedImage) {
                                        activity.clonedImage.remove();
                                    }

                                    activity.clonedImage = 0;  
                                    activity.clickedImage = 0;  
                                  }
                    ).
                    removeClass('active') ;
                    
                } else {

                 jConfirm('Do you really want to delete this point?', 'Point dragged out of plan',
                    function (result) {
                        if (!result) {
                            activity.clickedImage.animate (
                                {
                                 top  : activity.startY,
                                 left : activity.startX
                                }).
                                removeClass('active') ;
                            
                        } else {
                            var id_parts = activity.clickedImage.attr('id').split('-') ;

                            $.getJSON('/asbestos/' + id_parts[1] + '/' + id_parts[2] + '/delete/' + id_parts[3] + '/' + id_parts[4],
                                {type: 'point', 
                                 id: $(activity.clickedImage).attr('id')
                                }, 
                                function (data) {
                                    if (data.errmsg) {
                                        $(activity.clickedImage).showMessageBelow(data.errmsg)
                                    }
                                    if (data.ok) {
                                        var tree_id = '#' + data.tree_id ;

                                        $.taconite(data.tree) ;
                                        
                                        activity.clickedImage.css('opacity', 1) ;
                                        activity.clickedImage.animate(
                                                    { top: startPointY,
                                                      left: startPointX},
                                                      '500', 
                                                      'swing', 
                                                      function () {
                                                        activity.clickedImage.removeClass("active") ;
                                                        if (activity.clonedImage) {
                                                            activity.clonedImage.remove();
                                                        }

                                                        activity.clonedImage = 0;  
                                                        activity.clickedImage = 0;  
                                                      }
                                        ).
                                        removeClass('active') ;
                            
                            
                                        $('#prp-' + id_parts[1] + '-' + id_parts[2] + '-' + id_parts[3] + '-' + id_parts[4]).parent().fadeOut('slow',
                                            function () {
                                                $(this).remove() ;
                                        }) ;
                                    }
                                }) ;
                            }
                        })
                    }
                
            // -------------------------------------------------------------------
            // Inside the plan. Take necessary action then tidy up
            // -------------------------------------------------------------------
            } else {
                if (activity.clonedImage) {
                    // ---------------------------------------------------------------
                    // Added a new icon - create the actual image and release original
                    // ---------------------------------------------------------------
                    var new_icon = activity.clickedImage.clone(false) ;
                    var id_parts = activity.destination.attr('id').split('-') ;

                    $.getJSON('/asbestos/' + id_parts[1] + '/' + id_parts[2] + '/apoint/' + id_parts[4] + '/0',
                                        {x: curX, y: curY}, 
                                        function (data) {
                                            if (data.errmsg) {
                                                $(new_icon).showMessageBelow(data.errmsg)
                                            }
                                            new_icon.attr('id', data.full_id) ;
                                            new_icon.data('point_ref', data.name) ;
                                            new_icon.data('tree_id', data.tree_id) ;
                                            new_icon.data('cur_x', curX) ;
                                            new_icon.data('cur_y', curY) ;

                                            $.taconite(data.tree) ;
                                            setTreeHover('#' + data.tree_id) ;
                                        }) ;

                    moveicon(new_icon.
                                appendTo(asb_plan).
                                attr('id', '').
                                animate({ top: actualY,
                                          left: actualX,
                                          'opacity': 1,
                                          'z-order':1 }).
                                removeClass('active').
                                removeClass('new').
                                addClass('pt-high point').
                                attr('title', 'Drag the icon to re-position the point').
                                unbind('hover').
                                hover(function(){
                                        if (!drawing) {
                                            var name = $(this).data('point_ref') ;
                                            if (name == undefined || name == '') {
                                                name = 'Waiting for point details...' ;
                                            }
                                            $('#hint').text(name).
                                                css( {top : actualY+$(this).height(),
                                                      left : actualX+$(this).width()/2-$('#hint').width()/2}).
                                                show() ;
                                            $(this).addClass('hover') ;
                                            $('#' + $(this).data('tree_id')).addClass('active-point') ;
                                            id_parts[0] = 'pt' ;
                                            $('#' + id_parts.join('-')).addClass('hover') ;

                                        }
                                    }, 
                                    function(){ 
                                        $(this).removeClass('hover')
                                        $('#hint').text(name).hide() ;
                                        $('#' + $(this).data('tree_id')).removeClass('active-point') ;
                                    } )
                                ) ;
                
                    activity.clickedImage.css( { top: startPointY,
                                           left: startPointX,
                                           opacity: 1 }).
                                           removeClass('active') ;
                    activity.clonedImage.remove();

                } else {
                    // ---------------------------------------------------------------
                    // Moved an existing image to a new location. Update the server
                    // and reset the poup details (so they don't have to be checked
                    // each time they're shown)
                    // ---------------------------------------------------------------
                    var id_parts = activity.id.split('-') ;
                    var new_icon = activity.clickedImage  ;

                    activity.treepoint.removeClass('active-point') ;

                    $.getJSON('/asbestos/' + id_parts[1] + '/' + id_parts[2] + '/apoint/' + id_parts[3] + '/' + id_parts[4],
                        {x: curX, y: curY}, 
                        function (data) {
                            if (data.errmsg) {
                                $(new_icon).showMessageBelow(data.errmsg)
                            }
                            new_icon.data('cur_x', curX) ;
                            new_icon.data('cur_y', curY) ;

                            $.taconite(data.tree) ;
                            setTreeHover('#' + data.tree_id) ;
                            activity.treepoint.attr('rel', id_parts[2] + '/' + id_parts[3] + '/'+ id_parts[4] + '/' + curX + '/' + curY)
                        }) ;
                    
                        activity.clickedImage.
                                animate({ top: actualY,
                                          left: actualX,
                                          'opacity': 1,
                                          'z-order':1 }).
                                removeClass('active').
                                addClass('high').
                                unbind('hover'). 
                                hover(function(){
                                        if (!drawing) {
                                            var name = $(this).data('point_ref') ;

                                            if (name == undefined || name == '') {
                                                name = 'Right click to set point' ;
                                            }
                                            $('#hint').text(name).
                                                css( {top : actualY+$(this).height(),
                                                      left : actualX+$(this).width()/2-$('#hint').width()/2}).
                                                show() ;
                                            $(this).addClass('hover') ;
                                        }
                                    }, 
                                    function(){ 
                                        $(this).removeClass('hover')
                                        $('#hint').text(name).hide() ;
                                    } )
                                 ;

                }
                activity.clonedImage = 0;  
                activity.clickedImage = 0;  
                drawing = false;
            }
            // return false;
        }
    })
}

function add_cm_points(where) {
    
    $(where).contextMenu({
        menu: 'myMenu',
        init: init_cmenu
    },
    // -----------------------------------------------------------------------
    // All ids activating this should be in the format 
    //          aaa-<property_id>-<scheduleid>-<nnn>-<mmm>
    // -----------------------------------------------------------------------
    function(action, element, pos) {
        var id_parts = $(element).attr('id').split('-') ;
        var name = $(element).data('point_ref') ;

        switch (action) {
            case 'save':
                name = $('#item_id').val() ;
                if (name) {
                    $(element).data('point_ref', name) ;
                    $.post('/asbestos/' + id_parts[1] + '/' + id_parts[2] + '/' + id_parts[3]  + '/rename/',
                        {name: name, id: element.attr('id')}, function () {
                        }) ;
                }
                break ;
                
            case 'delete':
                jConfirm("Do you really want to delete the point " + name,
                            'Delete Point',
                    function (result) {
                        if (result) {
                            $.getJSON('/asbestos/' + id_parts[1] + '/' + id_parts[2] + '/delete/' + id_parts[3] + '/' + id_parts[4],
                                {type: 'point', 
                                 id: $(element).attr('id')
                                }, 
                                function (data) {
                                    if (data.errmsg) {
                                        $(element).showMessageBelow(data.errmsg)
                                    }
                                    if (data.ok) {
                                        var tree_id = '#' + data.tree_id ;

                                        $.taconite(data.tree) ;

                                        var item = $('a.selected', '#siteTree').parents('li:eq(0)').next().addClass('selected') ;
                                        if (item.length == 0) {
                                            item = $('a.selected', '#siteTree').parents('li:eq(0)').next().addClass('selected') ;
                                            if (item.length == 0) {
                                                $('a.selected', '#siteTree').parents('.area').addClass('selected') ;
                                            }
                                        }
                                        selectFromTree ($('a.selected', '#siteTree')) ;
                                        
                                        $(element).animate (
                                            { top:  startPointY,
                                              left: startPointX 
                                            },
                                            '1500', 
                                            'swing',
                                            function () {
                                                $(element).fadeOut('slow', 'linear', $(element).remove()) ;
                                            }) ;
                                        
                                        $('#prp-' + id_parts[1] + '-' + id_parts[2] + '-' + id_parts[3] + '-' + id_parts[4]).parent().fadeOut('slow',
                                            function () {
                                                $(element).remove() ;
                                        }) ;

                                        
                                    }
                                }) ;
                            
                            
                            
                        }
                    }
                ) ;
                break ;
            
            case 'details':
                var what_id = $(element).attr('id') ;
                var id_parts = what_id.split('-') ;
                id_parts[0] = 'prp' ;
                var tree_id = id_parts.join('-') ;

                $('#' + $('#' + tree_id).parent().attr('id') + ', #asbloading').expose ( {
                    speed:500  
                } ) ;

                building.hide() ;
                noplans.hide() ;
                
                asb_plan1.hide() ;
                asb_tbar.hide() ;
                
                asb_detail.hide() ;
                $('#asbloading').show()
                $.post('/pdetails/' + id_parts[1] + '/' + id_parts[2] + '/' + id_parts[3] + '/' + id_parts[4], 
                    {point_id: what_id}, function () {
                        $('#asbloading').fadeOut('slow', function () {
                            $.unexpose() ;
                            asb_detail.show() ;
                            // $('li.point', '#siteTree').draggable({
                            //     helper: 'clone',
                            //     helper: function(e) { return $(this).css("position", "absolute"); },
                            //     scroll: true,
                            //     scrollSpeed: 40,
                            //     scrollSensitivity: 40,
                            //     zIndex: 10,
                            //     containment: 'window'
                            // }) ;                            
                            // -----------------------------------------------
                            // The next line is a work around for a problem
                            // in the dragdropsort.js module (where the helper
                            // only drags within the container, even though
                            // flagged as absolute)
                            // -----------------------------------------------
                            $('li', '#siteTree').attr('style', 'position', '') ;
                        }) ;
                    }
                ) ;
                
                break ;
            
            // default:
            
        // console.log(
        //     'Action: ' + action + 'nn' + "\n" +
        //     'Item: ' + $('#item_id').val() + "\n" +
        //     'Element ID: ' + $(element).attr('id') + 'nn' +
        //     'X: ' + pos.x + '  Y: ' + pos.y + ' (relative to element)nn' +
        //     'X: ' + pos.docX + '  Y: ' + pos.docY+ ' (relative to document)'
        //     );
        }
    });
    
    $("#myMenu").disableContextMenuItems('#copy') ;
}

function add_cm_tree(where) {
    
    $(where).contextMenu({
        menu: 'treeMenu',
        init: init_tmenu
    },
    function(action, element, pos) {
        var name ;
        
        if ($(element)[0].tagName == 'A' && !$(element).hasClass('disabled')) {
            var parent = $(element).parent('li:eq(0)') ;
            
            name = $(element).text() ;
            var id_parts = $(element).attr('id').split('-') ;

            switch (action) {
                case 'save':
                    name = $('#pitem_id').val() ;
                    if (name) {
                        $(element).text( name ) ;
                        $.post('/asbestos/' + id_parts[1] + '/' + id_parts[2] + '/rename/' + id_parts[2], 
                                {name: name, id: element.attr('id')}, function() {
                                    if (id_parts[0] == 'prp') {
                                        id_parts[0] = 'pt' ;
                                        $('#' + id_parts.join('-')).data('point_ref', name ) ;
                                    }
                                }) ;
                    }
                    break ;
                    
                case 'delete':
                    var type, prompt ;
                    var is_point = false ;
                    
                    switch ((type = $('#tm-title').data('type'))) {
                        case 'building':
                            prompt2 = "\ntogether with all associated floors, areas and points?" ;
                            break ;
                        case 'floor':
                            prompt2 = "\ntogether with all associated areas and points?" ;
                            break ;
                        case 'area':
                            prompt2 = "\ntogether with all associated points?" ;
                            break ;
                        case 'point':
                            prompt2 = '' ;
                            is_point = true ;
                            break ;
                        default:
                            return false;
                    }
                    jConfirm("Do you really want to delete the " + type + "\n<strong style=\"color:red\">" + name + '</strong>' + prompt2,
                                'Delete',
                        function (result) {
                            if (result) {
                                $.getJSON('/asbestos/' + id_parts[1] + '/' + id_parts[2] + '/delete/' + id_parts[3],
                                    {type: type, 
                                     id: $(element).attr('id')
                                    }, 
                                    function (data) {
                                        if (data.errmsg) {
                                            $(element).showMessageBelow(data.errmsg)
                                        }
                                        if (data.ok) {
                                            var tree_id = '#' + data.tree_id ;

                                            $.taconite(data.tree) ;
                                            // -------------------------------
                                            // If deleting the selected item,
                                            // need to refresh the display.
                                            // -------------------------------
                                            var selItem = $('a.selected', '#siteTree') ;                                            

                                            if (selItem[0] == $(element)[0]) {
                                                var item = selItem.parents('li:eq(0)').next().find('a:eq(0)').addClass('selected') ;
                                                if (item.length == 0) {
                                                    item = selItem.parents('li:eq(0)').prev().find('a:eq(0)').addClass('selected') ;
                                                    if (item.length == 0) {
                                                        item = selItem.parents('.area').find('a:eq(0)').addClass('selected') ;
                                                    }
                                                }
                                                selectFromTree ($(item)) ;
                                            }


                                            $(element).parent().fadeOut('slow',
                                                function () {
                                                    $(this).remove() ;
                                            }) ;
                                            if (is_point) {
                                                id_parts[0] = 'pt' ;
                                                $('#' + id_parts.join('-')).fadeOut('slow',
                                                    function () {
                                                        $('#' + id_parts.join('-')).remove() ;
                                                 })
                                            }
                                        }
                                    }) ;
                            }
                        }
                    )
                    break ;
                case 'rfplan':
                    removeFloorPlan(element) ;
                    break ;
                    
                case 'adetails':
                    showArea (element) ;
                    
                    break ;
                    
                case 'limage':
                    var floor = $(element).parents('.floor:eq(0)') ;
                    if (!floor) {
                        alert('Please select the floor or an associated area or point') ;
                        
                    } else {
                        id_parts = floor.attr('id').split('-') ;
                        tb_show('test', '/asbestos/' + id_parts[1] +  '/' + id_parts[2] + '/floorplan/' + id_parts[3] + '/' + id_parts[4] + '?height=128&width=480&nobutton=1', '')                        
                    }
                    break ;
                
                default:
            }
        }
    });
}

function removeFloorPlan (element) {
    var name = $(element).text() ;
    var id_parts = $(element).attr('id').split('-') ;
    
    jConfirm("Do you really want to remove the floorplan\n<strong style=\"color:red\">" + name + '</strong>',
                'Remove',
        function (result) {
            if (result) {
                $.getJSON('/asbestos/' + id_parts[1] + '/' + id_parts[2] + '/rfplan/' + id_parts[3],
                    {id: $(element).attr('id')}, 
                    function (data) {
                        if (data.errmsg) {
                            $(element).showMessageBelow(data.errmsg)
                        }
                        if (data.ok) {
                            var tree_id = '#' + data.tree_id ;

                            $.taconite(data.tree) ;
                            // -------------------------------
                            // If deleting the selected item,
                            // need to refresh the display.
                            // -------------------------------
                            var selItem = $('a.selected', '#siteTree') ;                                            

                            // if (selItem[0] == $(element)[0]) {
                            //     var item = selItem.parents('li:eq(0)').next().find('a:eq(0)').addClass('selected') ;
                            //     if (item.length == 0) {
                            //         item = selItem.parents('li:eq(0)').prev().find('a:eq(0)').addClass('selected') ;
                            //         if (item.length == 0) {
                            //             item = selItem.parents('.area').find('a:eq(0)').addClass('selected') ;
                            //         }
                            //     }
                            //     selectFromTree ($(item)) ;
                            // }
                            
                            var floor = $(element).parents('.floor:eq(0)') ;
                            var property_id = id_parts[1] ;
                            noplans.show() ;
                            asb_plan1.hide() ;
                            asb_tbar.hide() ;
                        }
                    }) ;
            }
        }
    )
}

function showArea(element) {
    var target  = $(element).parents('.area:eq(0)') ;
    var what_id = target.attr('id') ;
    var id_parts = what_id.split('-') ;
    var parent = $(element).parent('li:eq(0)') ;

    $('#' + $(parent).attr('id') + ', #asbloading').expose ( {
        speed:500  
    } ) ;
    
    site_detail.hide() ;
    building.hide() ;
    noplans.hide() ;
    asb_plan1.hide() ;
    asb_tbar.hide() ;
    
    asb_detail.hide() ;
    clearDraggables () ;
    $('#asbloading').show()

    $('.selected', '#siteTree').removeClass('selected') ;
    $('a:eq(0)', target).addClass('selected') ;

    $.post('/asbestos/' + id_parts[1] + '/' + id_parts[2] + '/adetails/' + id_parts[3] + '/' + id_parts[4], 
        {area_id: what_id}, function () {
            $('#asbloading').fadeOut('slow', function () {
                $.unexpose() ;
                asb_detail.show() ;
                // -----------------------------------------------
                // The next line is a work around for a problem
                // in the dragdropsort.js module (where the helper
                // only drags within the container, even though
                // flagged as absolute)
                // -----------------------------------------------
                $('li', '#siteTree').attr('style', 'position', '')                                 
            }) ;
        }
    ) ;
}

function clearDraggables() {
    if ($('li.area.ui-draggable', '#siteTree').length > 0) {
        $('li.area.ui-draggable', '#siteTree').draggable( 'destroy' ) ;
    }
    if ($('li.point.ui-draggable', '#siteTree').length > 0) {
        $('li.point.ui-draggable', '#siteTree').draggable( 'destroy' ) ;
    }
}

// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
function init_cmenu(cmenu, ele_ptr) {
    var name = $(ele_ptr.element).data('point_ref') ;
    if (name == undefined || name =='') {
        name = '--'
    }
    $('#item_id').val(name) ;

    return true ;
}

// ---------------------------------------------------------------------------
// INIT TMENU
// ==========
// 
// Called just before displaying the context menu for the tree, this is used
// to configure the content as appropriate to the selected item.
// ---------------------------------------------------------------------------
function init_tmenu(tmenu, ele_ptr) {
    var title ;
    var type = '' ;
    ele_ptr.element = ele_ptr.target ;

    var element = $(ele_ptr.element) ;
    var parent = element.parent('li:eq(0)') ;

    if ($(ele_ptr.element)[0].tagName == 'A' && parent.length != 0) {
        var name = $(ele_ptr.element).text() ;
        if (name == undefined || name =='') {
            name = '--'
        }    
        $('#pitem_id').val(name) ;
    
        if (element.parents().hasClass('floor')) {
            $('.limage', tmenu).show() ;
            $('.rimage', tmenu).show() ;

        } else {
            $('.limage', tmenu).hide() ;
            $('.rimage', tmenu).hide() ;
        }

        if (element.parents().hasClass('area')) {
            $('#adetails').show() ;
        } else {
            $('#adetails').hide() ;
        }

        if (element.parents().hasClass('point')) {
            $('#lrename').hide() ;
        } else {
            $('#lrename').show() ;
        }

        if (parent.hasClass('build')) {
            title = 'Building Options' ;
            type = 'building' ;
        
        } else if (parent.hasClass('floor')) {
            title = 'Floor Options' ;
            type = 'floor' ;
        
        } else if (parent.hasClass('area')) {
            title = 'Area Options'
            type = 'area' ;

        } else if (parent.hasClass('point')) {
            title = 'Point Options'
            type = 'point' ;
        }

        if  (type) {
            $('#tm-title').text(title).data('type', type) ;
            return true ;
        }
    }
    return false ;
}

// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
function init_toolbar() {
    $('#bbuild').unbind('click.tb').bind('click.tb', function (event) {
        var target = $(event.target) ;

        jPrompt('Enter the new building name:', '', 'Add a new building to the site', function(r) {
            if( r ) {
                $.post('/asbestos/' + $('#siteTree').data('property_id') + '/' + $('#siteTree').data('schedule_id') + '/building/0', {name: r, id: 'asbhead'},
                    function () {
                        
                    })
            } 
        });

    })
    
    $('#pfplans, #pfplansA3').unbind('click.tb').bind('click.tb', function (event) {
        if (!$(this).hasClass('disabled')) {
            window.open($(this).attr('rel')) ;
            // document.location.href = $(this).attr('rel') ;
        }
        
    })
    $('#pcert, #pall').unbind('click.tb').bind('click.tb', function (event) {
        if (!$(this).hasClass('disabled')) {
            window.open($(this).attr('rel')) ;
            // document.location.href = $(this).attr('rel') ;
        }
    })
    $('#edrep').unbind('click.tb').bind('click.tb', function (event) {
        if (!$(this).hasClass('disabled')) {
            window.open($(this).attr('rel')) ;
            // document.location.href = $(this).attr('rel') ;
        }
    })
    
    
    // tb_init('#bfloor') ;    
    
    
    $('#bfloor').unbind('click.tb').bind('click.tb', function (event) {
        var target = $('a.selected', '#siteTree') ;
        var building_link = target.parents('.build:eq(0)').children('a:eq(0)') ;

        if (!$(this).hasClass('disabled') && building_link.length) {
            var id = target.attr('id') ;
            var id_parts = $(building_link).attr('id').split('-') ;

            tb_show($(this).attr('title'), 
                        '/asbestos/' + id_parts[1] + '/' + id_parts[2] + '/floorplan/' + id_parts[3] + '/0?height=128&amp;width=480&amp;nobutton=1',
                        0) ;
        }
    })
    
    $('#barea').unbind('click.tb').bind('click.tb', function (event) {
        var target = $('a.selected', '#siteTree') ;
        var floor_link = target.parents('.floor:eq(0)').children('a:eq(0)') ;

        if (!$(this).hasClass('disabled') && floor_link.length) {
            jPrompt('Enter the new area name:', '', 'Add an area to ' + floor_link.text(), function(r) {
                if( r ) {
                    var id = floor_link.attr('id') ;
                    var id_parts = $(floor_link).attr('id').split('-') ;
                    $.post('/asbestos/' + id_parts[1] + '/' + id_parts[2] + '/area/' + id_parts[4] + '/0', {name: r, id: id},
                        function () {
                            
                        })
                } 
            });

        }
    })
    
    $('#bpoint').unbind('click.tb').bind('click.tb', function (event) {
        var cur_area = $('a.selected', '#siteTree').parents('.area').find('a:eq(0)') ;

        if (!$(this).hasClass('disabled') && cur_area.length) {
            var id_parts = cur_area.attr('id').split('-') ;            

            $.getJSON('/asbestos/' + id_parts[1] + '/' + id_parts[2] + '/apoint/' + id_parts[4] + '/0',
                                {x: -1, y: -1}, 
                function (data) {
                    if (data.errmsg) {
                        $(new_icon).showMessageBelow(data.errmsg)
                    }
                    var tree_id = '#' + data.tree_id ;

                    $.taconite(data.tree) ;
                    setTreeHover(tree_id) ;
                    
                    $('.selected', '#siteTree').removeClass('selected') ;
                    $(tree_id).addClass('selected') ;
                    
                    // ---------------------------------------
                    // Now download the point details
                    // ---------------------------------------
                    building.hide() ;
                    noplans.hide() ;
                    asb_plan1.hide() ;
                    asb_tbar.hide() ;
                    
                    asb_detail.hide() ;
                    // $('li.point', '#siteTree').draggable( 'destroy' ) ;

                    var id_parts = tree_id.split('-') ;
                    id_parts[0] = 'pt' ;
                    
                    $('#asbloading').show() ;
                    $('#' + $(tree_id).parent().attr('id') + ', #asbloading').expose ( {
                        speed:500  
                    } ) ;
                    
                    $.post('/pdetails/' + id_parts[1] + '/' + id_parts[2] + '/' + id_parts[3] + '/' + id_parts[4], 
                        {point_id: data.full_id}, function () {
                            $('#asbloading').fadeOut('slow', function () {
                                $.unexpose() ;
                                asb_detail.show() ;
                            }) ;
                        }
                    ) ;
                        
                }
            ) ;

        }
    })    
}

function reinit_plan(property_id, orig_id, new_id, html) {
    if (orig_id == 0) {
        var branch = $(html).show() ;
        $('#siteTree').append(branch) ;
        bind_plans (property_id, '', branch) ;
    }
}

function bind_plans(property_id, schedule_id, root) {
    $(root).fileTree({ 
        root: 'overview', 
        // script: '/asbestos/' + property_id + '/points/1', 
        folderEvent: 'click', 
        expandSpeed: 750, 
        collapseSpeed: 750, 
        expandEasing: 'easeInBounce', 
        collapseEasing: 'easeOutBounce', 
        loadMessage: 'One moment...',
        // multiFolder: false,
        
        doubleClick: function (event, what) {
            var name ;
            var id_parts = $(what).attr('id').split('-') ;
            id_parts[0] = 'pt' ;
            
            if ((name = what.text()) != '') {
                $.get('/asbestos/' + property_id + '/' + id_parts[2] + '/rename', 
                    {id : what.attr('id'), name : name}, function () {
                        $('#' + id_parts.join('-')).data('point_ref', what.text() ) ;
                }) ;
            } else {
                what.text($('#' + id_parts.join('-')).data('point_ref')) ;
            }
        },

        onSelect: function (what) {
            selectFromTree(what) ;
        }
    },
    function(file) { 
        alert(file);
    });

    $('#skipfp').unbind('change').bind('change', function () {
        var cur_floor_id  = $('a.selected', '#siteTree').parents('.floor').attr('id') ;
        var id_parts = cur_floor_id.split('-') ;

        $.post('/asbestos/' + id_parts[1] + '/' + id_parts[2] + '/fpreq/' + id_parts[3] + '/' + id_parts[4],
            {type: 'fpreq',
             val: $(this).is(':checked') ? 1 : 0 
            }, 
            function (data) {
                if (data.errmsg) {
                    $(element).showMessageBelow(data.errmsg)
                }
            }
        )
        
    } )

    init_toolbar() ;
}

function selectFromTree(what) {
    var what_id = $(what).attr('id') ;
    var id_parts = what_id.split('-') ;
    var property_id = id_parts[1] ;
    
    // -----------------------------------------------
    // The next line is a work around for a problem
    // in the dragdropsort.js module (where the helper
    // only drags within the container, even though
    // flagged as absolute)
    // -----------------------------------------------
    $('li', '#siteTree').attr('style', 'position', '') ;
    var parent = $(what).parent() ;

    if (parent.hasClass('site')) {
        $('#bfloor').addClass('disabled') ;
        $('#barea').addClass('disabled') ;
        $('#bpoint').addClass('disabled') ;

    } else if (parent.hasClass('build')) {
        $('#bfloor').removeClass('disabled') ;
        $('#barea').addClass('disabled') ;
        $('#bpoint').addClass('disabled') ;

    } else {
        $('#bfloor').removeClass('disabled') ;
        $('#barea').removeClass('disabled') ;
        $('#bpoint').addClass('disabled') ;
        if (parent.hasClass('area')) {
            $('#bpoint').removeClass('disabled') ;
        }
    }
    
    if (parent.hasClass('point')) {
        $('#bpoint').removeClass('disabled') ;

        $('#' + $(parent).attr('id') + ', #asbloading').expose ( {
            speed:500  
        } ) ;
        site_detail.hide() ;
        building.hide() ;
        noplans.hide() ;
        asb_plan1.hide() ;
        asb_tbar.hide() ;
        
        // $('li.point', '#siteTree').draggable( 'destroy' ) ;          //-- This breask the drag/drop
        asb_detail.hide() ;
        
        $('#asbloading').show()
        $.post('/pdetails/' + id_parts[1] + '/' + id_parts[2] + '/' + id_parts[3] + '/' + id_parts[4], 
            {point_id: what_id}, function () {
                $('#asbloading').fadeOut('slow', function () {
                    $.unexpose() ;
                    asb_detail.show() ;
                    
                    // $('li.point', '#siteTree').draggable({
                    //     helper: 'clone',
                    //     // helper: function(e) { return $(this).css("position", "absolute"); },
                    //     scroll: true,
                    //     scrollSpeed: 40,
                    //     scrollSensitivity: 40,
                    //     zIndex: 10,
                    //     containment: 'window'
                    // }) ;                            
                    // -----------------------------------------------
                    // The next line is a work around for a problem
                    // in the dragdropsort.js module (where the helper
                    // only drags within the container, even though
                    // flagged as absolute)
                    // -----------------------------------------------
                    $('li', '#siteTree').attr('style', 'position', '') ;
                    
                }) ;
            }
        ) ;

    } else if (parent.hasClass('build')) {
        site_detail.hide() ;
        building.show() ;
        noplans.hide() ;
        asb_plan1.hide() ;
        asb_tbar.hide() ;

        asb_detail.hide() ;
        clearDraggables () ;

    } else if (parent.hasClass('site')) {
        showSiteDetails() ;
        
    } else if (parent.hasClass('area') && readOnly) {
        showSiteDetails() ;
        showArea (what) ;
        
    } else {
        site_detail.hide() ;
        building.hide() ;
        asb_detail.hide() ;
        var floor = $(what).parents('.floor:eq(0)') ;

        show_floor(floor, property_id, false) ;
    }
    
}            

function showSiteDetails () {
    building.hide() ;
    asb_detail.hide() ;
    asb_plan1.hide() ;
    asb_tbar.hide() ;
    site_detail.show() ;    
}
            
function show_floor (floor, property_id, refresh) {
    var what = $('a:eq(0)', floor) ;
    var parent = $(what).parent() ;
    var img_src = $(what).attr('href') ;
    var img_parts = img_src.split('?') ;
    var cur_link = $('a.selected', '#siteTree') ;
    var cur_selection = cur_link.parent() ;

    // -----------------------------------------------------------------------
    // Check the current selection applies to the floor we've been requested
    // to show. Won't necessarily be true if uploaded via a right click. 
    // -----------------------------------------------------------------------
    var cur_floor_id  = $('a.selected', '#siteTree').parents('.floor').attr('id') ;
    if (cur_floor_id != floor.attr('id')) {
        return ;
    }
    var old_floor_id = asb_plan.data('floor') ;
    var scale = asb_zdiv.data('nwZoom.scale') ;
    
    scale = !scale ? 1 : scale ; 
    
    clearDraggables() ;
    
    if (!refresh && cur_selection.attr('id') == asb_plan.data('item') && 
        asb_plan1.is(':visible')) {
        return ;
    }                
    
    asb_plan.data('item', cur_selection.attr('id')) ;
    asb_plan.data('floor', cur_floor_id) ;
    asb_detail.hide() ;
    
    
    if (img_src && img_src !='#' && img_parts.length == 2) {        
        img_src = escape(img_parts[0]) + '?' + img_parts[1]
        noplans.hide() ;
        
        fplanImage.hide () ;
        asb_tbar.hide() ;
        asb_plan.css({
                  'background-image': 'url(/images/lactivity.gif)', 
                  'background-repeat': 'no-repeat',
                  'background-position': 'top center',
                  'opacity': 0.25
                  }).show() ;
        asb_plan1
            .css('width', asb_main.width())
            .show() ;
        asb_plan
            .css('width', asb_plan1.width()-10)
            .css('height', asb_plan1.height()-10) ;

        try {
                asb_plan1.show() ;
                asb_tbar.css('width', asb_plan.width())
        } catch  (err) {
            alert('Failed to set width') ;
            asb_tbar.css('width', asb_plan.width())
        }

        var img = new Image() ;
        $(img).attr('src', img_src)
            .load (function () {
                fplanImage
                        .attr('src', this.src)
                        .css({
                            'width'  : '100%'
                        }).show() ;
                asb_tbar.show() ;
                asb_plan.css({'opacity': 1.0, 'background-image': ''})
                
                var awidth = asb_plan.width () ;
                var aheight= asb_plan.height () ;

// The -30 is a simple minded attempt to allow for scroll bar width/height

                var xscale = awidth < this.width ? (awidth-30) / this.width : 1 ;
                var yscale = aheight < this.height ? (aheight-30) / this.height : 1 ;
                scale = xscale < yscale ? xscale : yscale ;

                var wd = this.width * scale ;
                var ht = this.height * scale ;
                
                // -----------------------------------------------------------
                // Set the container div to the required size, and then the 
                // embedded image to a 100% width/height. This ensures that 
                // it is automatically rescaled when the div is.
                // -----------------------------------------------------------
                asb_zdiv.css({'width' : wd,
                              'height': ht}) ;
                fplanImage.css ({'width' : '100%',
                              'height': '100%'}) ;
                
                asb_zdiv.data('nwZoom.scale', scale) ;
                asb_zdiv.data('nwZoom.initScale',  scale) ;
                
                asb_zdiv.data('nwZoom.init_w', this.width) ;
                asb_zdiv.data('nwZoom.init_h', this.height) ;
                
                positionPoints(property_id, scale, cur_selection) ;
                
            })
            .error(function() {
                alert('Failed to load the image ' + img_src)
            })
            .attr('src', img_src) ;
    } else {
        $('#skipfp').attr('checked', (cur_link.hasClass('n') ? 'checked' : false)) ;
        noplans.show() ;
        asb_plan1.hide() ;
        asb_tbar.hide() ;
        
        fplanImage.css({
                'height' : '100%',
                'width'  : '100%',
                'background-image' : 'none'
                })
                .show() ;
        positionPoints(property_id, scale, cur_selection) ;
    }

    // -----------------------------------------------------------------------
    // Remove any icons currently show on the plan
    // -----------------------------------------------------------------------
    $('.icon.point', asb_plan).fadeOut('slow', function() {$(this).remove()}) ;
}


    // -----------------------------------------------------------------------
    // Now add an icon for each point in the tree below the selected area(parent)
    // -----------------------------------------------------------------------
function positionPoints (property_id, scale, cur_selection) {    
    $('li.point', cur_selection).each (function (what) {
        var link = $('a:eq(0)', $(this)) ;
        var points = link.attr('rel').split('/') ;
        var name = link.text() ;
        var s_id = parseInt(points[0])
        var a_id = parseInt(points[1])
        var p_id = parseInt(points[2])

        var effX = parseInt(points[3]) ;
        var effY = parseInt(points[4])

        var curX = !scale || scale == 1 ? effX : effX * scale ;
        var curY = !scale || scale == 1 ? effY : effY * scale ;

        var pri  = link.hasClass('pt-high') ? 'pt-high' :
                    link.hasClass('pt-medium') ? 'pt-medium' :
                     link.hasClass('pt-low') ? 'pt-low' : 
                       link.hasClass('pt-no-asb') ? 'pt-no-asb' :
                         link.hasClass('pt-asb-rem') ?'pt-asb-rem'  : 'pt-no-pri' ;

        moveicon($('#marker').clone(false).
                insertBefore($('#marker')).
                attr('id', 'pt-'  +property_id + '-' + s_id + '-' + a_id + '-' + p_id).
                removeClass('new').
                addClass('point ' + pri).
                data('point_ref', name).
                data('tree_id', 'prp-'  +property_id + '-' + s_id + '-' + a_id + '-' + p_id).
                data('cur_x', effX).
                data('cur_y', effY).
                attr('title', 'Drag the icon to re-position the point').
                unbind('hover').
                hover(function() {
                        if (!drawing) {
                            name = $(this).data('point_ref') ;
                            curY = parseInt($(this).css('top')) ;
                            curX = parseInt($(this).css('left')) ;

                            $('#hint').text(name).
                                css( {top : curY+$(this).height(),
                                      left : curX+$(this).width()/2-$('#hint').width()/2}).
                                show() ;
                            $(this).addClass('hover') ;

                            $('#' + $(this).data('tree_id')).addClass('active-point') ;
                        }
                    },
                    function(){ 
                        $(this).removeClass('hover')
                        $('#hint').text(name).hide() ;
                        $('#' + $(this).data('tree_id')).removeClass('active-point') ;
                    } ).
                animate({left : curX,
                         top :  curY,
                         'opacity': 1,
                         'z-order':1 }, function () {
                             asb_plan.append($(this))
                         })
        ) ;
    })
}

function rm_simage(what, img_id) {
    var row = jQuery(what).parent().parent().parent().parent() ;

    if (confirm('Are you sure you want to remove this image')) {

        jQuery.get(what.href, {img: img_id}, function(data) {
                if (data['deleted'] == 1) {
                    jQuery(what).parent().parent().remove() ;
                }
                msg = '' ;
                if (data['errmsg']) {
                    msg += data['errmsg'] ;
                }
                if (data['warning']) {
                    msg += (msg ? "\n\n" : '') + data['warning'] ;
                }
                if (msg) {
                    alert(msg) ;
                }
            })

    }
    return false ;
}

// ---------------------------------------------------------------------------
// CHANGE SAMPLE TYPE
// ==================
// If the sample has already been marked as Strongly Presumed and also cloned
// from a previous smaple, we need to check the user really wants to lose their
// current settings.
// Simarlarly, if they move 
// ---------------------------------------------------------------------------
function changeSampleType (which, point_id) {
    var clone = $('#cloned').val() ;
    var message = '';
    var title ;
    var result ;

    if (clone != '') {
        message = 'Do you want to remove the previous Strongly Presumed association?' ;
        title = "This sample has been flagged as Strongly Presumed similar to sample " + clone ;
    }
    
    switch ($(which).val()) {
        case 'strongly_presumed':
            if (clone == '') {
                message = 'Do you really want to mark this as Strongly Presumed to be Asbestos?<br />If so, all Material Assessment items will be set to their maximum value<br />and all Priority Assessment item will be cleared for later setting' ;
                title = 'Setting as Strongly Presumed' ;

            } else {
                title = 'This sample has been flagged as Strongly Presumed to match sample ' + clone
            }
            message += "\n\n<span style=\"font-size:80%;font-style:italic\">(if you want to clone an existing sample, please drag the matching point from the tree.)</span>" ;

            result = flagAsPresumed(which, 'strongly_presumed', message, title) ;
            break ;

        case 'presumed':
            if (clone == '') {
                message = 'Do you really want to mark this as Presumed to be Asbestos?' ; 
                title = 'Setting as Presumed' ;
            } else {
                message += '<br /><br />If so, all items will be set to their maximum value and the textual items, other than the description, cleared' ;
            }
            result = flagAsPresumed(which, 'presumed', message, title) ;
            break ;

        case 'sample':
            getSample (point_id, false) ;
    }
}            

// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
function getSample (point_id, fromNosamp) {
    var message = '';
    var title ;
    var result ;
    
            if (!title) {
                title = 'Adding a sample' ;
                message = 'You are about to add a new sample to this inspection reference' ;
            } else {
                message += '<br /><br />If so, you will add a new sample to this inspection reference.' ;
            }

            jConfirm(message, title, function (result) {
                if (result) {
                    var sampNum = $('#samp-num').val() ;
                    if (sampNum == '') {
                        var id_parts = $('.selected', '#siteTree').attr('id').split('-') ;
                        $.getJSON('/pdetails/' + id_parts[1] + '/' + id_parts[2] + '/' + id_parts[3] + '/' + id_parts[4] + '/new_sample',
                                {point: point_id}, function (data) {
                                if (data.sample_number) {
                                    $('#sample-num').text($('.selected', '#siteTree').text() + ' - ' + data.sample_number) ;
                                    $('#samp-num').val(data.sample_number) ;
                                }
                        }) ;
                    }

                    $(which).parents('div.sample').find('.samp-sel').removeClass('samp-sel') ;
                    $(which).parent().addClass('samp-sel') ;
                    $('#no-sample').css('visibility', 'visible') ;
                    $('#sample-num').css('visibility', 'visible').addClass('samp-sel') ;
                    $("#sample-number").attr('checked', 'checked') ;
                    $('#cloned').val() ;                    
                    
                } else {
                    $('#' + $("#sample-type").val()).attr('checked', 'checked') ;
                    if (fromNosamp) {
                        $('#nosamp').attr('checked', 'checked') ;
                    }
                }
            }) ;
            return result ;
}


// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
function flagAsPresumed (which, sample_type, message, title) {
    var result = false ;
    message += "\n\nNOTE: No changes will be actually made until you click SAVE" ;

    jConfirm(message, title, function (proceed) {
            if (proceed) {
                _flagAsPresumed() ;
                
                var sample_blk = $(which).parents('div.sample') ;
                sample_blk.find('.samp-sel').removeClass('samp-sel') ;
                $('#sample-type').val('presumed') ;
                $(which).parent().addClass('samp-sel') ;
                $(which).attr('checked', 'checked') ;
                $('#no-sample').css('visibility', 'hidden') ;
                $('#sample-num').css('visibility', 'hidden') ;
                $("#" + sample_type).attr('checked', 'checked') ;
                $('#cloned').val() ;

                result = true ;
            } else {
                $('#' + $("#sample-type").val()).attr('checked', 'checked') ;
            }
        }
    )
    return result ;
}

function _flagAsPresumed () {

    $('textarea', '.pquestions').not('#recommendationText').text('').val('') ;             // Why does a textarea have a val()?

    $('select', '.pquestions').each (function (selectIndex) {
        var value = 0 ;
        var index = -1 ;

        $('option', $(this)).each (function (optionIndex) {
            var lvalue = $(this).val() ;

            if (lvalue) {
                lvalue = parseInt(lvalue.split('-')[1]) ;
                if (!isNaN(lvalue) && lvalue > value) {
                    value = lvalue ;
                    index = optionIndex ;
                }
            }
        })
        if (index >= 0) {
            $('option:eq(' + index + ')', this).attr('selected', 'selected') ;
            $(this).parents('td:eq(0)').next().text(value);
        
            var total = 0 ;
            $($(this).parents('table:eq(0)')).find('td.weight').each (function() {
                var value = parseInt($(this).text()) ;
                if (!isNaN(value)) {
                    total += value ;
                }
            })
            $($(this).parents('table:eq(0)')).find('td.aweight').text(parseInt(total)) ;
        }
    })
    $('select', '#rgroup-3 .pquestions').val('')
    $('#rgroup-3 td.weight').text('') ;
    $('#rgroup-3 td.aweight').text('') ;
}



    $.fn.nwZoomer = function(options) {

        var settings = $.extend({}, $.fn.nwZoomer.defaults, options);

        return this.each(function(){
            var $zIn  = $(this) ;
            var zInId = $zIn.attr('id') ;
            var $zOut = $('#' + zInId +'-o') ;
            var $zReset= $('#' + zInId +'-r') ;
            var $zDiv = $('#' + zInId +'-d') ;
            var zdWidth ;
            var zdHeight
            init() ;

            // ---------------------------------------------------------------
            // Record the starting dimensions and positions for later scaling
            // ---------------------------------------------------------------
            function init() {
                // zdWidth = $zDiv.width() ;
                // zdHeight = $zDiv.height() ;
                zdWidth = $zDiv.data('nwZoom.init_w') ;
                zdHeight= $zDiv.data('nwZoom.init_h') ;                
                
                if (zdWidth == 0 || zdHeight == 0) {
                    setTimeout(init, 100) ;
                    
                } else {                    
                    
                    // $zDiv.data('nwZoom.init_w', zdWidth) ;
                    // $zDiv.data('nwZoom.init_h', zdHeight) ;
                    // $zDiv.data('nwZoom.initScale',  settings.curScale) ;

                    $zIn.
                        unbind('moueover.nwzoom').bind('mouseover.nwzoom', function () {
                            settings.inOut = 1 ;
                            settings.timer = setInterval (function () {
                                doZoom () ;
                            }, 100) ;
                    }).
                    unbind('mouseout.nwzoom').bind('mouseout.nwzoom', function () {


                        clearInterval(settings.timer) ;
                    })
    
                    $zOut.
                        unbind('moueover.nwzoom').bind('mouseover.nwzoom', function () {
                            settings.inOut = -1 ;
                            settings.timer = setInterval (function () {
                                doZoom () ;
                            }, 100) ;
                    }).
                    unbind('mouseout.nwzoom').bind('mouseout.nwzoom', function () {
                        clearInterval(settings.timer) ;
                    })


                    $zReset.
                    unbind('click.nwzoom').bind('click.nwzoom', function () {
                        zdWidth = $zDiv.data('nwZoom.init_w') ;
                        zdHeight= $zDiv.data('nwZoom.init_h') ;                
                        
                        settings.curScale = $zDiv.data('nwZoom.initScale') ;
                        $zDiv.width (zdWidth * settings.curScale) ;
                        $zDiv.height (zdHeight * settings.curScale) ;
console.log('Reinit ' + zdWidth + ' * ' + settings.curScale)                        
                        positionIcons ();
                    }) ;        
                }
            }
            
            function doZoom () {
                settings.curScale = asb_zdiv.data('nwZoom.scale') ;
                settings.curScale += settings.zoomfactor * settings.inOut ;

                zdWidth = $zDiv.data('nwZoom.init_w') ;
                zdHeight= $zDiv.data('nwZoom.init_h') ;                

console.log('img scale ' + zdWidth + ' * ' + settings.curScale)                
                $zDiv.width ( zdWidth  * settings.curScale) ;
                $zDiv.height( zdHeight * settings.curScale) ;

                positionIcons() ;
            }
            
            function positionIcons () {
                $zDiv.data('nwZoom.scale', settings.curScale) ;       // For external access
console.log('curs ' + settings.curScale)
                $zDiv.parent().find('.icon').each (function () {
                    var icon = $(this) ;
                    var left = icon.data('cur_x') ;
                    var top  = icon.data('cur_y') ;

                    left *= settings.curScale ;
                    top  *= settings.curScale ;

                    icon.css('left', left) ;
                    icon.css('top',  top) ;

                    left = parseInt(icon.css('left')) ;
                    top = parseInt(icon.css('top')) ;
                })
            }
        });
        
    }    
    
    $.fn.nwZoomer.defaults = {
        zoomfactor : 0.01,         // Enter factor (0.05=5%)
        inOut : 1,                 // -1 to zoom out
        curScale : 1,
        timer : 0
    };


// ---------------------------------------------------------------------------
// INIT POINT DETAILS
// ==================
// Used to edit the point details display
// ---------------------------------------------------------------------------
function initPointDetails (pointId, clientId, verylowPriority, lowPriority, mediumPriority, editable, propertyId, scheduleId, areaId, pointRef) {

    $('select', '.pquestions').change (function (event) {
        var asbVal ;
        var which = $(event.target) ;
        var values = which.val().split('-') ;

        var value = values.length > 1 ? values[1] : '' ;
        which.parents('tr:eq(0)').find('td.weight').text(value);

        // ---------------------------------------------------------------
        // If changing recommendations, alter the action within to match
        // values length 1 == no asbestos
        // ---------------------------------------------------------------
        if ($(this).parent().hasClass('recom')) {
            var actwithin = values.length > 2 ? values[2] : '' ;
            $('#actwithin').val(actwithin) ;
            $('#recommendationText').val($(':selected', which).text()) ;
        }

        var total = 0 ;
        var num = 0

        which.parents('table:eq(0)').find('td.weight').each (function() {
            var value = parseInt($(this).text()) ;
            if (!isNaN(value)) {
                total += value ;
            }
            num++ ;
        })
        if (num && which.parents('.pquestions').hasClass('tt-avg')) {
            total = Math.round(total/= num) ;
        }

        which.parents('table:eq(0)').find('td.aweight').text(parseInt(total)) ;

        var rg = which.parents('.rep-group:eq(0)') ;
        if (rg.length) {
            var rtotal = 0 ;
            var groups = $('.pquestions td.aweight', rg) ;
            if (groups.length == 0) {
                rtotal = total ;       // When only 1, we don't include the aweight cell on the page.
            } else {
                groups.each (function () {rtotal += parseInt($(this).text())}) ;
            }
            $('table.ptotal td.aweight', rg).text(Math.floor(rtotal)) ;
        }

//            $('.pquestions td.aweight', '#point-det-' + pointId).each (function() {gtotal += parseInt($(this).text())}) ;

        var grisk ;
        var gtotal = 0 ;

        // ---------------------------------------------------------------
        // If the asbestos type has been set to 'no asbestos detected',
        // ensure the recommendation is no futher action and action within
        // is set to N/A
        // ---------------------------------------------------------------
        if ((asbVal = ($('[name^="at["]').val())) == 0 && $('[name^="at["]').val() != '') {

            grisk = 'no-asb'
            gtotal = 0 ;
            $('select:not([name^="at["]):not(.none)').val('') ;
            $('#actwithin').val(-1) ;
            $('td.weight').text('') ;
            $('[name^="at["]').parent().parent().find('td.weight').text(0);
            $('td.aweight').text('0') ;
            $('td.gtotal','#point-det-' + pointId).text(0) ;
            $('input.gtotal','#point-det-' + pointId).text(0) ;

            $('.recom select option').each (function () {
                var opts = this.value.split('-') ;                    
                if ($(this).text().toLowerCase().indexOf('no further') >= 0) {
                    $('#recommendationText').val($(this).text()) ;
                    this.selected = true ;
                }
            })
            $('select:not([name^="at["]):not([id=survey]):not([id=units])').attr('disabled','disabled') ;
            
        } else if (asbVal.split('-')[0] == 18) {            // Asbestos removed
            grisk = 'asb-rem'
            gtotal = 0 ;
            $('select:not([name^="at["]):not(.none)').val('') ;
            $('#actwithin').val(-1) ;
            $('td.weight').text('') ;
            $('[name^="at["]').parent().parent().find('td.weight').text(0);
            $('td.aweight').text('0') ;
            $('td.gtotal','#point-det-' + pointId).text(0) ;
            $('input.gtotal','#point-det-' + pointId).text(0) ;


            $('.recom select option').each (function () {
                var opts = this.value.split('-') ;
                if ($(this).text().toLowerCase().indexOf('no further') >= 0) {
                    $('#recommendationText').val($(this).text()) ;
                    this.selected = true ;
                }
            }) ;
            $('select:not([name^="at["]):not([id=survey]):not([id=units])').attr('disabled','disabled') ;

        } else {
            $('select').attr('disabled', false) ;
            
            // NW 12/09/2011 Total assessement score needs to sum both material and priority totals
            // $('td.aweight', 'table.ptotal:not(.optional)').each (function () {gtotal += parseInt($(this).text()) }) ;
            // Now extract the material assessment total directly and also return it to the server.
            rtotal = 0 ;
            $('td.aweight', 'table.ptotal').each (function () {rtotal += parseInt($(this).text()) }) ;
            $('td.aweight', 'div.rep-group.mat table.ptotal').each (function () {gtotal += parseInt($(this).text()) }) ;
            
            var grisk = gtotal <= verylowPriority ? 'Very Low' :  (gtotal <= lowPriority ? 'Low' : (gtotal <= mediumPriority ? 'Medium' : 'High')) ;
            $('td.gtotal','#point-det-' + pointId).text(rtotal) ;
            $('input.gtotal','#point-det-' + pointId).val(rtotal) ;
            $('#matGTotal').val(gtotal) ;
        }
        $('td.grisk','#point-det-' + pointId).text(grisk).parents('table:eq(0)').removeClass('high medium low asb-rem no-asb').addClass(grisk.toLowerCase()) ;
        grisk = grisk == 'very low' ? 'low' : grisk ;
        $('a.selected', '#siteTree').removeClass('pt-very-low pt-low pt-medium pt-high pt-no-pri pt-no-asb pt-asb-rem').addClass('pt-' + grisk.toLowerCase().replace(' ', '-'));

    }) ;
    
    
    
    $('#point-det-' + pointId).submit( function () {
        var button = this ;
        $.post($(this).attr('action'), $(this).serialize(), function () {
            $('input[type=submit]', button).attr('disabled', false).val('Saved') ;
        }) ;
        $('input[type=submit]', button).attr('disabled', 'disabled').val('Saving. Please wait...').blur() ;
        return false;
    })
    
    // -------------------------------------------------------------------
    // Just remove focus after a save
    // -------------------------------------------------------------------
    .find('input[type=submit]').mouseup(function () {blur()})
    .end()
    
    // -------------------------------------------------------------------
    // Handle changes in the sample radio buttons
    // -------------------------------------------------------------------
    .find('div.sample input[type=radio]').bind('change', function () {
        changeSampleType (this, pointId) ;
        return false ;
    }) ;

    $('#survey').change(function (event) {
        var which = $(event.target) ;
        if ($(which).find(':selected').attr('rel') == 1) {
            $('a.selected', '#siteTree').removeClass('pt-low pt-medium pt-high pt-no-pri').addClass('pt-high');
        }
    })

    $('.rgrp-toggle').bind('click.rgrp', function () {
        var container = $(this).parents('.rgrp-header').next('div') ;
        container.toggle();
        return false;
    })


    if (editable) {
        $('#scal').unbind('click').bind('click', function () {
            showCalendar('pdate', '%e-%b-%Y') ;
        }) ;
        
        // -------------------------------------------------------------------
        // Now point dragging to allow setting to strongly presumed
        // -------------------------------------------------------------------
        $('#point-det-' + pointId).find('.point-summary').droppable({
                accept: 'li.point',
                activeClass: 'ui-highlight',
                // hoverClass: 'hover',
                drop: function (ev, ui) {
                    dropPoint(ev, ui, pointRef, propertyId, scheduleId, areaId, pointId) ;
                }
        }) ;
        
        $('li.point:not(#pp-' + propertyId + '-' + scheduleId + '-' + areaId + '-' + pointId + ')', '#siteTree').draggable({
            helper: 'clone',
            // helper: function(e) { return $(this).css("position", "absolute"); },
            scroll: true,
            scrollSpeed: 40,
            scrollSensitivity: 40,
            zIndex: 10,
            containment: 'window'
        }) ;                            
        

        $('#nosamp').unbind('change').bind('click', function () {
            if ($(this).attr('checked')) {
                $('#sample-num').css('visibility', 'hidden') ;
            
            } else {
                getSample (pointId, true) ;
                // $('#sample-num').css('visibility', 'visible') ;
            }
        }) ;

    } else {
        $('#udelegate-' + pointId).multi_select ('/cl_users/' + clientId,
                                                            {
                                                                current_values  : get_cur_users,
                                                                add_value       : add_cur_user,
                                                                remove_value    : remove_cur_user,
                                                                container_id    : 'alst-users-a',
                                                                type            : 'emp'
                                                            }) ;

    }
}


function dropPoint(ev, ui, pointRef, propertyId, scheduleId, areaId, pointId) {
    var point = $('a', ui.draggable).text() ;
    if (point == pointRef) {
        $('#set-sp').showMessageBelowAsRow(["You can't set it to itself"], 3) ;
        
    } else {
        var cur_point = $('.selected', '#siteTree') ;

        jConfirm('Do you want to set this Inspection Reference, <strong style="color:navy">' + cur_point.text() +
                    '</strong>' + "\n" +
        ' as <b>Strongly</b> Presumed equivalent to <strong>point</strong> <span style="color:red;font-weight:bold">' + point + '</span>',
                'Marking as Strongly Presumed',
                function (result) {
                    if (result) {
                        jConfirm('Are you certain?' + "\n" +
                         'If so, <span style="color:red;font-weight:bold">ALL YOUR CURRENT SETTINGS<span> will be replaced by those from ' + point,
                                'Marking as Strongly Presumed',
                                function (result) {
                                    if (result) {
                                        $('#asbloading').show() ;
                                        $('#asb-detail').hide() ;
                                        $('#pp-propertyId-scheduleId-areaId-pointId,' + 
                                          '#' + ui.draggable.attr('id') + ', #asbloading').expose ( {
                                            speed:500  
                                        } ) ;
                                        $.post('/pdetails/' + propertyId + '/' + scheduleId + '/' + areaId + '/' + pointId + '/clone', 
                                            { point_id: $('.selected', '#siteTree').attr('id'),
                                              sp_id:  $(ui.draggable).attr('id')
                                                }, function () {
                                                $('#asbloading').fadeOut('slow', function () {
                                                    $.unexpose() ;
                                                    asb_detail.show() ;
                                                }) ;
                                            }
                                        ) ;
                                    }
                                }
                        )
                    }
                }
        ) ;
    }
}


/**
 * jquery.expose 0.14. Make HTML elements stand out.
 * 
 * http://flowplayer.org/tools/expose.html
 *
 * Copyright (c) 2008 Tero Piirainen (support@flowplayer.org)
 *
 * Released under the MIT License:
 * http://www.opensource.org/licenses/mit-license.php
 * 
 * >> Basically you can do anything you want but leave this header as is <<
 *
 * Since  : 0.10 - 10/06/2008
 * Version: 0.14 - Fri Nov 07 2008 16:51:35 GMT-0000 (GMT+00:00)
 * Noel : Changed it to support 'exposing' multiple elements
 */
(function($) { 
	
	function expose(elements, params) { 
		
		var opts = {
			speed: 1000,
			zIndex: 10,
			opacity: 0.8,
			color:'#333',
			onClose: null
		};
		
		$.extend(opts, params);
		
		/* 
			create the fading "blanket" that sits on top of the document
			CSS settings for this are given in external stylesheet
		*/
		var blanket = $("#blanket");
		
		if (blanket.is(":visible")) {
			return;	
		}
		
		if (!blanket.length) {
			blanket = $('<div id="blanket"></div>').css({				
				position:'absolute', top:0, left:0,
				width:'100%',
				height:$(document).height(),
				display:'none'
			}).css("opacity", 0);
			
			$("body").append(blanket);	
		} 
		
		// these can vary from time to time
		blanket.css({
			backgroundColor:opts.color,
			zIndex:opts.zIndex	
		});

        $(elements).each (function () {
    		// make given element sit on top of the blanket
    		$(this).css({zIndex:opts.zIndex + 1});
    		if (!/relative|absolute/i.test($(this).css("position"))) {
    			$(this).css("position", "relative");		
    		}		 
		 })
		// reveal blanket
		blanket.css("display", "block").fadeTo(opts.speed, opts.opacity);		
		

		function unexpose(fn) {			
			
			if (opts.onClose || fn) {
				if (!fn || fn.target) { fn = opts.onClose; }
				if (fn) { 
				    $(elements).each (function () {
				        fn.call(this); 	
				    })
			    }
			}
			
			blanket.fadeTo(opts.speed, 0, function() {
				blanket.hide();
				$(elements).css({zIndex:opts.zIndex -1});
			});				
			
			blanket.unbind("click.unexpose");
		}
		
		// esc button "unexposes"
		$(document).bind("keypress.unexpose", function(evt) {
			if (evt.keyCode == 27) {
				 unexpose();
				 $(document).unbind("keypress.unexpose");
			}
		});	
		
		blanket.bind("click.unexpose", unexpose);		
		$.unexpose = unexpose; 	
		
	}
	
	
	// jQuery plugin initialization
	$.fn.expose = function(params) {    
		expose(this, params);		
		return this; 
	}; 
	

})(jQuery);
