var jsan=new function() {
	/* private methods */

	function getHTTPObject() {
		var xmlhttp;
		/*@cc_on
		@if (@_jscript_version >= 5)
			try {
				xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
			} catch (e) {
				try {
					xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
				} catch (E) {
					xmlhttp = false;
				}
			}
		@else
		xmlhttp = false;
		@end @*/
		if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
			try {
				xmlhttp = new XMLHttpRequest();
			} catch (e) {
				xmlhttp = false;
			}
		}
		return xmlhttp;
	}

	function mknamespace(module) {
		//split namespace on '.', create empty
		// object for each , nested, if it doesn't already exist

		var path='http://nieuws.overijssel.nl/load.js?lib='; // base url for jsan packages
		var rest=new String(module);

		var name='';
		var temp=window.sp;
		var i=rest.indexOf('.');
		while (i!=-1) {
			name=rest.substring(0, i);
			path+=name+'/';
			if (!temp[name]) {
				temp[name]={};
			}
			temp=temp[name];
			rest=rest.substring(i+1);
			i=rest.indexOf('.');
		}
		path+=rest+'/show.js';
		// alert( 'parent: '+ temp + 'name: '+rest + 'path: ' + path );
		return { parent:temp, name:rest, path:path }
	}

	function checkcollision(module) {
		var collision = false;

		var rest=new String(module);

		var name='';
		var temp=window.sp;
		var i=rest.indexOf('.');
		while (i!=-1) {
			name=rest.substring(0, i);

			if (!temp[name]) {
				break;
			}
			temp=temp[name];
			rest=rest.substring(i+1);
			i=rest.indexOf('.');
		}

		if (temp[rest]) {
			collision = true;
		}
		return collision;
	}

	/* private variables */

	var http=getHTTPObject();
	var included={};
	var imported={};

	/* public methods */
	this.include=function(url) {
//		alert("including " + url);
		if (!included[url]) {
			// include a package from a url
		
			http.open('GET',url,false);
			http.send(null);
			var response=http.responseText;	
//			alert(response);
			eval(response);
			included[url]=jsan_package;
		}
		return included[url];
	}

	this.use=function(module) {
		// import a jsan module
		// FIXME: allow specific methods to be imported in the global namespace (window.*)
		if (!imported[module]) {
			var collision = checkcollision(module);
			var namespace=mknamespace(module);
			if (namespace.name) {
				// now rest is the name of the new package;
				if (collision) {
					var mypackage = this.include(namespace.path);
					for(myitem in mypackage) {
						namespace.parent[namespace.name][myitem]=mypackage[myitem];
					}
				} else {
					namespace.parent[namespace.name]=this.include(namespace.path);
				}
				imported[module]=namespace.parent[namespace.name];
			}
		}
		return imported[module];
	}

	this.fetch=function(url, onload_handler, waitforme) {
		// get content from url, optionally run onload_handler afterwards
		var timestamp=new Date();
		if (url.match(/\?/)) {
			timestamp='&t='+timestamp.getTime();
		} else {
			timestamp='?t='+timestamp.getTime();
		}
		var fetch_http=getHTTPObject();
		fetch_http.open('GET',url+timestamp,!waitforme);
		if (onload_handler) {
			fetch_http.onreadystatechange = function() {
				if (fetch_http.readyState == 4) {
					var response=fetch_http.responseText;
					onload_handler(response);
				}
			}
		}		
		fetch_http.send(null);
		if (waitforme) {
			return fetch_http.responseText;
		}
	}
}

var sp=new function() {
	this.init=function(columns, userpath) {
		sp.userpath=userpath;

		function init_columns(column) {
			DragDrop.makeListContainer(column);
			column.onDragDrop=sp.onDrop;
			column.acceptCheck=function(item) {
				if (item.getAttribute('sp:itemtype')=='item') {
					return true;
				} else {
					return false;
				}
			}
			var items=column.getElementsByTagName('LI');
			for (var i=items.length-1; i>=0; i--) {
				if (items[i].getAttribute('sp:type')) {
					sp.loadItem(items[i]);
					if (items[i].getAttribute('sp:hideheader') == "1") {
						items[i].setDragHandle(sp.item.getOptions(items[i]));
					} else {
						items[i].setDragHandle(items[i].getElementsByTagName("span")[0]);
					}
				}
/*
				var type=items[i].getAttribute('sp:type');
				if (type) {
					sp[type] = jsan.use(type);
					sp[type].show(items[i]);
					items[i].setDragHandle(sp.item.getHead(items[i]));
				}
*/
			}
		}

		// var columns=document.getElementsByTagName('UL');

		for (var i=0; i<columns.length; i++) {
			if (typeof(columns[i]=='string')) {
				var col=document.getElementById(columns[i]);
			} else {
				var col=columns[i];
			}
			init_columns(col);
		}
		// Fix to prevent text selection.
//		document.body.ondrag = function(){return false;}
//		document.body.onselectstart = function(){return false;}
		
		// Create the edit box for later use;
		sp.editBox.init();

		// Jtip init.
		JT_init();
	}
	this.fetch=function(url, onload_handler, item) {
		function getFunction(name) {
			var ob_list=name.split('.');
			var temp=window;
			try {
				for (var i=0; i<ob_list.length; i++) {
					temp=temp[ob_list[i]];
				}
			} catch( e ) {
				temp = null;
			}
			return temp;
		}

		if (typeof(onload_handler)=='string') {
			var fp=getFunction(onload_handler);
			if (fp) {
				jsan.fetch(url, function(response) {
					fp(response, item);
				});
			} else {
				alert(onload_handler+' not found');
			}
		} else {
			jsan.fetch(url, function(response) {
				onload_handler(response, item);
			});
		}

		sp.item.refreshLoop(item);
	}

	this.item={
		refreshLoop:function(item) {
			// Set timeout to refresh the item when needed;
			var refTime = item.getAttribute("sp:refresh");
			if (refTime > 0) {
				clearTimeout(item.refreshTimer);

				// Item refresh is given in minutes - it needs to be converted to ms (*60000);
				refTime = refTime * 60000;

				var myFp = function() {
					sp.item.refreshItem(item);
					// This isn't needed because refreshItem calls a new fetch, thus setting the timeout again.
					// item.setTimeout(myFp, reftime);
				}
				item.refreshTimer = setTimeout(myFp, refTime);
			}
		},

		getBody:function(item) {
			var temp=item.firstChild;
			while (temp) {
				if (temp.tagName=='DIV' && temp.className.match(/\bitembody\b/)) {
					return temp;
				}
				temp=temp.nextSibling;	
			}
			return null;
		},
		getHead:function(item) {
			var temp=item.firstChild;
			while (temp) {
				if (temp.tagName=='DIV' && temp.className.match(/\bitemheader\b/)) {
					return temp;
				}
				temp=temp.nextSibling;	
			}
			return null;
		},
		getOptions:function(item) {
			var temp = item.firstChild;
			while (temp) {
				if (temp.tagName=='DIV' && temp.className.match(/\boptionwrap\b/)) {
					return temp;
				}
				temp=temp.nextSibling;
			}
			return null;	
		},
		deleteItem:function(item) {
			jsan.fetch('http://nieuws.overijssel.nl/sp.delete.item.ajax?item='+escape(item.getAttribute('sp:path'))+'&user='+escape(sp.userpath), false, true);
			item.innerHTML = null;
			item.parentNode.removeChild(item);
		},
		editItem:function(item, url) {
			var timestamp=new Date();
			timestamp='?t='+timestamp.getTime();

			var myEditBox = sp.editBox.openEditBox(url + "edit.html" + timestamp);
			if (myEditBox) {
				myEditBox.item = item; //setAttribute("sp:itemid", item.getAttribute("id"));
			} else {
				alert("no editbox");
			}
		},
		newItem:function(newpath) {
			var myEditBox = sp.editBox.openEditBox("new.html?newpath="+escape(newpath));
			if (myEditBox) {
				
			} else {
				alert("no editbox");
			}
		},
		refreshItem:function(item) {
			var type=item.getAttribute('sp:type');
			if (type) {
				sp[type] = jsan.use(type);

				sp[type].show(item);
				if (item.getAttribute('sp:hideheader') == "1") {
					item.setDragHandle(sp.item.getOptions(item));
				} else {
					item.setDragHandle(item.getElementsByTagName("span")[0]);
				}
			}
		},
		reloadItem:function(item) {
			var oldItem = item;
			var contents = jsan.fetch('http://nieuws.overijssel.nl/sp.show.item.ajax?item='+escape(oldItem.getAttribute('sp:path'))+'&user='+escape(sp.userpath), false, true);
			if (contents == "error") {
				return;
			}

			var tempDiv = document.createElement("DIV");
			tempDiv.innerHTML = contents;

			var newItem = tempDiv.getElementsByTagName("LI")[0];
			oldItem.parentNode.insertBefore(newItem, oldItem);
			oldItem.parentNode.removeChild(oldItem);
			
			DragDrop.makeItemDraggable(newItem);
			if (newItem.getAttribute("sp:hideheader") == "1") {
				newItem.setDragHandle(sp.item.getOptions(newItem));
			} else {

				newItem.setDragHandle(newItem.getElementsByTagName("span")[0]);
			}
			setTimeout(function(){ sp.loadItem(newItem);}, 500);
			//sp.loadItem(newItem);
			

		},
		showOptions:function(item, timeout) {
			if (timeout) {
				item.mouseIsOver=true;
				window.setTimeout(function() { sp.item.showOptions(item, false) }, timeout);
			} else {
				if (item.mouseIsOver) {
					var opts = sp.item.getOptions(item);
					if (opts) {
						opts.style.visibility='visible';
					}
				}
			}
		},
		hideOptions:function(item, timeout) {
			if (timeout) {
				item.mouseIsOver=false;
				window.setTimeout(function() { sp.item.hideOptions(item, false) }, timeout);
			} else {
				if (!item.mouseIsOver) {
					var opts = sp.item.getOptions(item);
					if (opts) {
						opts.style.visibility='hidden';
					}
				}
			}
		}
	}
	this.loadItem=function(item) {
		if (item && !item.getAttribute('sp:loaded')) {
			var type=item.getAttribute('sp:type');
			var jsinit = item.getAttribute('sp:jsinit');
			if (type && jsinit) {
				sp[type] = jsan.use(type);
				sp[type].show(item);
			}
			item.setAttribute('sp:loaded','1');
			return true;
		} else {
			if (item && item.getAttribute('sp:refresh')) {
				sp.item.refreshLoop(item);
				return true;
			}
			return false;
		}
	}
	this.onDrop=function(item) {
		var now=new Date();
		// init the item if it isn't already done
		var newpath=false;

// Dit aangepast naar een check op het "copy" attribute, namelijk het attribute dat dit een kopie is ergens van.
//		if( !item.getAttribute('sp:loaded') ) {
		if (item.getAttribute("copy")) {

			// save the object under the users data dir
			newpath=jsan.fetch('http://nieuws.overijssel.nl/sp.save.item.ajax?item='+escape(item.getAttribute('sp:path'))+'&user='+escape(sp.userpath), false, true);
			if (newpath) {
				item.setAttribute('sp:path',newpath);
				sp.item.reloadItem(item);
			}
		}
		// check and update the serverside ordering
		// FIXME: laten we eens niet gaan afhangen van een vast aantal kolommen.
		switch (this.id) {
			case 'column1':
				var startPrio=0;
			break;
			case 'column2':
				var startPrio=1000;
			break;
			case 'column3':
				var startPrio=2000;
			break;
			case 'column4':
				var startPrio=3000;
			break;
			default:
				return false;
			break;
		}
		var counter=startPrio;
		var item=this.firstChild;

		while (item) {
			if (item.tagName=='LI') {
				var currPrio=item.getAttribute('sp:priority');
				if (currPrio && currPrio!=counter) {
					jsan.fetch('http://nieuws.overijssel.nl/sp.save.priority.ajax?path='+escape(item.getAttribute('sp:path'))+'&priority='+escape(counter)+'&isfixed='+escape(item.getAttribute('sp:fixed'))+'&userpath='+ escape(sp.userpath)+'&'+now.getTime());
					item.setAttribute('sp:priority', counter);
				}
				counter+=10;
			}
			item=item.nextSibling;
		}
		jsan.fetch('sp.touch.ajax?path=' + escape(sp.userpath)+'&'+now.getTime());
	}

	this.menu={
		menudiv : null,
		menulist : null,
		menucategories : null,

		startEdit: function(mylink) {
			mylink.parentNode.getElementsByTagName("A")[0].className = "beheer_normal";
			mylink.parentNode.getElementsByTagName("A")[1].className = "beheer_normal";

			mylink.className = "beheer_selected";
		
			sp.menu.editInit("menu");
			//hiderdivs.makeHiderDivs(document.getElementById("menu"));
			hiderdivs.makeHiderDivs(sp.menu.menudiv);
		},
		endEdit: function() {
			//sp.menu.init();
			//hiderdivs.removeHiderDivs();
			window.location = document.location;
		},
		onDrop: function(item) {
			var now=new Date();

			var counter=0;
			var item=this.firstChild;
			while (item) {
				if (item.tagName=='LI') {
					var currPrio=item.getAttribute('sp:priority');
					if (currPrio && currPrio!=counter) {
						jsan.fetch('http://nieuws.overijssel.nl/sp.save.priority.ajax?path='+escape(item.getAttribute('sp:path'))+'&priority='+escape(counter)+'&'+now.getTime());
						item.setAttribute('sp:priority', counter);
					}
					counter+=10;
				}
				item=item.nextSibling;
			}
		},
		editInit: function(divname) {
			// Set the menu in edit mode;
			if (!(sp.menu.menudiv)) {
				sp.menu.menudiv = document.getElementById(divname);
			}
			if (!(sp.menu.menulist)) {
				sp.menu.menulist = sp.menu.menudiv.getElementsByTagName("UL")[0];
			}
			if (!(sp.menu.menucategories)) {
				sp.menu.menucategories = sp.menu.menulist.getElementsByTagName("LI");
			}

			for (var i=0; i<sp.menu.menucategories.length; i++) {
				if (sp.menu.menucategories[i].parentNode==sp.menu.menulist) {
					var categorylist = sp.menu.menucategories[i].getElementsByTagName('UL');
						DragDrop.makeListContainer(categorylist[0]);
						sp.menu.menucategories[i].className='active';
						categorylist[0].acceptCheck = function(item) { 
						if(item.getAttribute('sp:itemtype') == 'item' && item.sourceParent.parentNode.parentNode.parentNode == sp.menu.menudiv) {
							return true;
						} else {
							return false;
						}
					}
					categorylist[0].onDragDrop=sp.menucategory.onDrop;
				}
			}

			DragDrop.makeListContainer(sp.menu.menulist);
			sp.menu.menulist.acceptCheck=function(item) {
				if (item.getAttribute('sp:itemtype')=='category') {
					return true;
				} else {
					return false;
				}
			}
			sp.menu.menulist.onDragDrop=sp.menu.onDrop;

		},
		init: function(divname) {
			if (!(sp.menu.menudiv)) {
				sp.menu.menudiv = document.getElementById(divname);
			}
			if (!(sp.menu.menulist)) {
				sp.menu.menulist = sp.menu.menudiv.getElementsByTagName("UL")[0];
			}
			if (!(sp.menu.menucategories)) {
				sp.menu.menucategories = sp.menu.menulist.getElementsByTagName("LI");
			}
	
			for (var i=0; i<sp.menu.menucategories.length; i++) {
				if (sp.menu.menucategories[i].parentNode == sp.menu.menulist) {
					var categorylist=sp.menu.menucategories[i].getElementsByTagName('UL');
					DragDrop.makeCopyListContainer(categorylist[0]);
					categorylist[0].acceptCheck = function(item) {return false;}
				}
			}
		}
	}

	this.menucategory ={
		onDrop: function(item) {
			var counter=0;
			var now = new Date();

			if (this != item.sourceParent) {
				var catpath = this.parentNode.getAttribute('sp:path');
				var newpath = jsan.fetch('http://nieuws.overijssel.nl/sp.move.item.ajax?itempath='+escape(item.getAttribute('sp:path'))+'&cat_path='+escape(catpath)+'&'+now.getTime(), null, true);
				item.setAttribute('sp:path', newpath);
			}
			var item=this.firstChild;
			while (item) {
				if (item.tagName=='LI') {
					var currPrio=item.getAttribute('sp:priority');
					if (currPrio && currPrio!=counter) {
						//alert('http://nieuws.overijssel.nl/sp.save.priority.ajax?path='+escape(item.getAttribute('sp:path'))+'&priority='+escape(counter)+'&isfixed='+escape(item.getAttribute('sp:fixed'))+'&userpath='+ escape(sp.userpath)+'&'+now.getTime());
						jsan.fetch('http://nieuws.overijssel.nl/sp.save.priority.ajax?path='+escape(item.getAttribute('sp:path'))+'&priority='+escape(counter)+'&isfixed='+escape(item.getAttribute('sp:fixed'))+'&userpath='+ escape(sp.userpath)+'&'+now.getTime());

						item.setAttribute('sp:priority', counter);
					}
					counter+=10;
				}
				item=item.nextSibling;
			}
		}
	}

	this.editBox={
		init: function() {
			var i =0;
			sp.editBoxx = document.createElement("DIV");
			sp.editBoxx.id = "editbox";
			sp.editBoxx.style.display = "none";


			//background toevoegingen !!!!
			sp.editBoxx.bg = document.createElement("DIV");
			sp.editBoxx.bg.id = "editboxBackground";
			sp.editBoxx.appendChild(sp.editBoxx.bg);
			sp.editBoxx.bgBottom = document.createElement("DIV");
			sp.editBoxx.bgBottom.id = "editboxBackgroundBottom";
			sp.editBoxx.appendChild(sp.editBoxx.bgBottom);

			sp.editBoxx.content = document.createElement("DIV");
			sp.editBoxx.content.id = "editboxContent";
			sp.editBoxx.appendChild(sp.editBoxx.content);
			
			sp.editBoxx.content.editHeader = document.createElement("DIV");
			sp.editBoxx.content.editHeader.id = "editheader";
			sp.editBoxx.content.editHeader.innerHTML = "<h3>Bewerk item</h3><img src='http://nieuws.overijssel.nl/graphics/common/cancel2.gif' id='closeImg' onclick='sp.editBox.closeEditBox(); return false;'>";
			sp.editBoxx.content.appendChild(sp.editBoxx.content.editHeader);

			sp.editBoxx.content.iFrame = document.createElement("IFRAME");
			sp.editBoxx.content.iFrame.id = "editframe";

			sp.editBoxx.content.appendChild(sp.editBoxx.content.iFrame);

			var requiredtext = document.createElement('DIV');
			requiredtext.id='requiredtext';
			requiredtext.innerHTML='<span class="required">*</span> verplicht veld.';
			sp.editBoxx.content.appendChild(requiredtext);

			sp.editBoxx.content.okButton = document.createElement("BUTTON");
			sp.editBoxx.content.okButton.id = "editok";
			sp.editBoxx.content.okButton.onclick = sp.editBox.okClick;
			sp.editBoxx.content.appendChild(sp.editBoxx.content.okButton);
//			sp.editBoxx.content.okButton.value = "OK";
			sp.editBoxx.content.okButton.appendChild(document.createTextNode('OK'));

			sp.editBoxx.content.cancelButton = document.createElement("BUTTON");
			sp.editBoxx.content.cancelButton.id = "editcancel";
			sp.editBoxx.content.cancelButton.onclick = sp.editBox.cancelClick;
			sp.editBoxx.content.appendChild(sp.editBoxx.content.cancelButton);
//			sp.editBoxx.content.cancelButton.value = "Cancel";
			sp.editBoxx.content.cancelButton.appendChild(document.createTextNode('Annuleer'));


			document.body.appendChild(sp.editBoxx);
		},
		getEditBox : function() {
			return sp.editBoxx;
		},
		okClick : function() {
			if( sp.editBoxx.content.iFrame.contentWindow.doSubmit ) {
				sp.editBoxx.content.iFrame.contentWindow.doSubmit();
			} else {
				alert("Something is wrong, our editwindow is compromised!");
				sp.editBox.closeEditBox();
			}
		},
		cancelClick : function() {
			sp.editBox.closeEditBox();
		},
		openEditBox : function(url, title, boxheight, boxwidth) {
			var box = sp.editBox.getEditBox();
			if (!(title)) {
				title = "Bewerk item";
			}
			if(!(boxheight)) {
				boxheight = "400px";
			}
			if(!(boxwidth)) {
				boxwidth = "600px";
			}

			sp.editBoxx.content.iFrame.src = url;
			sp.editBox.setTitle(title);

			sp.editBox.setHeight(boxheight);
			sp.editBox.setWidth(boxwidth);

			sp.editBoxx.style.display = "block";

			var newtop = parseInt(document.body.clientHeight)-parseInt(box.offsetHeight);
			newtop = newtop/2;
			if (newtop < 0) {
				newtop = 0;
			}

			var newleft = parseInt(document.body.clientWidth)-parseInt(box.offsetWidth);
			newleft = newleft/2;
			if (newleft < 0) {
				newleft = 0;
			}
			
			document.getElementById("editbox").style.top = newtop + "px";
			document.getElementById("editbox").style.left = newleft + "px";
			hiderdivs.makeHiderDivs(box);
			return box;
		},
		closeEditBox : function() {
			var box = sp.editBox.getEditBox();
			box.style.display = "none";
//			sp.editBoxx.iFrame.src = "";
			sp.editBoxx.content.iFrame.src = "";
//			sp.editBoxx.content.iFrame.contentWindow.document.body.innerHTML = "";
			hiderdivs.removeHiderDivs();
		},
		setTitle : function (title) {
			sp.editBoxx.content.editHeader.getElementsByTagName("H3")[0].innerHTML = title;
		},
		setWidth : function (width) {
			sp.editBoxx.style.width=width;
			sp.editBoxx.content.style.width = width;
			sp.editBoxx.content.iFrame.style.width = width;

			sp.editBoxx.bg.style.width = "7px";
			sp.editBoxx.bg.style.left = parseInt(width) + "px";

			sp.editBoxx.bgBottom.style.left = "3px";
			sp.editBoxx.bgBottom.style.width = parseInt(width) + "px";
		},
		setHeight : function (height) {
			sp.editBoxx.style.height = height;
			document.getElementById("editboxContent").style.height=height;

			var contentHeight = parseInt(height);
			frameHeight = contentHeight - 90;
			sp.editBoxx.content.iFrame.style.height = frameHeight + "px";

			sp.editBoxx.bg.style.height = parseInt(height) + "px";
			sp.editBoxx.bgBottom.style.height = "7px";
			sp.editBoxx.bgBottom.style.top = parseInt(height) + "px";
		}		
	}
}
/* prevent execution of jQuery if included more then once */
if(typeof window.jQuery == "undefined") {
/*
 * jQuery 1.0.4 - New Wave Javascript
 *
 * Copyright (c) 2006 John Resig (jquery.com)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * $Date: 2006-12-12 15:33:10 -0500 (Tue, 12 Dec 2006) $
 * $Rev: 696 $
 */

// Global undefined variable
window.undefined = window.undefined;

var jQuery = function(a,c) {

	// Shortcut for document ready
	if ( a && typeof a == "function" && jQuery.fn.ready && !a.nodeType && a[0] == undefined ) // Safari reports typeof on DOM NodeLists as a function
		return jQuery(document).ready(a);

	// Make sure that a selection was provided
	a = a || document;

	// Watch for when a jQuery object is passed as the selector
	if ( a.jquery )
		return jQuery( jQuery.merge( a, [] ) );

	// Watch for when a jQuery object is passed at the context
	if ( c && c.jquery )
		return jQuery( c ).find(a);

	// If the context is global, return a new object
	if ( window == this )
		return new jQuery(a,c);

	// Handle HTML strings
	if ( typeof a  == "string" ) {
		var m = /^[^<]*(<.+>)[^>]*$/.exec(a);
		if ( m ) a = jQuery.clean( [ m[1] ] );
	}

	// Watch for when an array is passed in
	this.set( a.constructor == Array || a.length && a != window && !a.nodeType && a[0] != undefined && a[0].nodeType ?
		// Assume that it is an array of DOM Elements
		jQuery.merge( a, [] ) :

		// Find the matching elements and save them for later
		jQuery.find( a, c ) );

	// See if an extra function was provided
	var fn = arguments[ arguments.length - 1 ];

	// If so, execute it in context
	if ( fn && typeof fn == "function" )
		this.each(fn);

	return this;
};

// Map over the $ in case of overwrite
if ( typeof $ != "undefined" )
	jQuery._$ = $;
	
// Map the jQuery namespace to the '$' one
var $ = jQuery;



jQuery.fn = jQuery.prototype = {

	jquery: "1.0.4",


	size: function() {
		return this.length;
	},


	get: function( num ) {
		return num == undefined ?

			// Return a 'clean' array
			jQuery.merge( this, [] ) :

			// Return just the object
			this[num];
	},

	set: function( array ) {
		// Use a tricky hack to make the jQuery object
		// look and feel like an array
		this.length = 0;
		[].push.apply( this, array );
		return this;
	},

	each: function( fn, args ) {
		return jQuery.each( this, fn, args );
	},

	index: function( obj ) {
		var pos = -1;
		this.each(function(i){
			if ( this == obj ) pos = i;
		});
		return pos;
	},


	attr: function( key, value, type ) {
		// Check to see if we're setting style values
		return key.constructor != String || value != undefined ?
			this.each(function(){
				// See if we're setting a hash of styles
				if ( value == undefined )
					// Set all the styles
					for ( var prop in key )
						jQuery.attr(
							type ? this.style : this,
							prop, key[prop]
						);

				// See if we're setting a single key/value style
				else
					jQuery.attr(
						type ? this.style : this,
						key, value
					);
			}) :

			// Look for the case where we're accessing a style value
			jQuery[ type || "attr" ]( this[0], key );
	},


	css: function( key, value ) {
		return this.attr( key, value, "curCSS" );
	},

	text: function(e) {
		e = e || this;
		var t = "";
		for ( var j = 0; j < e.length; j++ ) {
			var r = e[j].childNodes;
			for ( var i = 0; i < r.length; i++ )
				if ( r[i].nodeType != 8 )
					t += r[i].nodeType != 1 ?
						r[i].nodeValue : jQuery.fn.text([ r[i] ]);
		}
		return t;
	},


	wrap: function() {
		// The elements to wrap the target around
		var a = jQuery.clean(arguments);

		// Wrap each of the matched elements individually
		return this.each(function(){
			// Clone the structure that we're using to wrap
			var b = a[0].cloneNode(true);

			// Insert it before the element to be wrapped
			this.parentNode.insertBefore( b, this );

			// Find the deepest point in the wrap structure
			while ( b.firstChild )
				b = b.firstChild;

			// Move the matched element to within the wrap structure
			b.appendChild( this );
		});
	},


	append: function() {
		return this.domManip(arguments, true, 1, function(a){
			this.appendChild( a );
		});
	},


	prepend: function() {
		return this.domManip(arguments, true, -1, function(a){
			this.insertBefore( a, this.firstChild );
		});
	},


	before: function() {
		return this.domManip(arguments, false, 1, function(a){
			this.parentNode.insertBefore( a, this );
		});
	},


	after: function() {
		return this.domManip(arguments, false, -1, function(a){
			this.parentNode.insertBefore( a, this.nextSibling );
		});
	},

	end: function() {
		if( !(this.stack && this.stack.length) )
			return this;
		return this.set( this.stack.pop() );
	},

	find: function(t) {
		return this.pushStack( jQuery.map( this, function(a){
			return jQuery.find(t,a);
		}), arguments );
	},

	clone: function(deep) {
		return this.pushStack( jQuery.map( this, function(a){
			return a.cloneNode( deep != undefined ? deep : true );
		}), arguments );
	},


	filter: function(t) {
		return this.pushStack(
			t.constructor == Array &&
			jQuery.map(this,function(a){
				for ( var i = 0; i < t.length; i++ )
					if ( jQuery.filter(t[i],[a]).r.length )
						return a;
				return null;
			}) ||

			t.constructor == Boolean &&
			( t ? this.get() : [] ) ||

			typeof t == "function" &&
			jQuery.grep( this, t ) ||

			jQuery.filter(t,this).r, arguments );
	},


	not: function(t) {
		return this.pushStack( typeof t == "string" ?
			jQuery.filter(t,this,false).r :
			jQuery.grep(this,function(a){ return a != t; }), arguments );
	},


	add: function(t) {
		return this.pushStack( jQuery.merge( this, typeof t == "string" ?
			jQuery.find(t) : t.constructor == Array ? t : [t] ), arguments );
	},

	is: function(expr) {
		return expr ? jQuery.filter(expr,this).r.length > 0 : false;
	},

	domManip: function(args, table, dir, fn){
		var clone = this.size() > 1;
		var a = jQuery.clean(args);

		return this.each(function(){
			var obj = this;

			if ( table && this.nodeName.toUpperCase() == "TABLE" && a[0].nodeName.toUpperCase() != "THEAD" ) {
				var tbody = this.getElementsByTagName("tbody");

				if ( !tbody.length ) {
					obj = document.createElement("tbody");
					this.appendChild( obj );
				} else
					obj = tbody[0];
			}

			for ( var i = ( dir < 0 ? a.length - 1 : 0 );
				i != ( dir < 0 ? dir : a.length ); i += dir ) {
					fn.apply( obj, [ clone ? a[i].cloneNode(true) : a[i] ] );
			}
		});
	},

	pushStack: function(a,args) {
		var fn = args && args[args.length-1];
		var fn2 = args && args[args.length-2];
		
		if ( fn && fn.constructor != Function ) fn = null;
		if ( fn2 && fn2.constructor != Function ) fn2 = null;

		if ( !fn ) {
			if ( !this.stack ) this.stack = [];
			this.stack.push( this.get() );
			this.set( a );
		} else {
			var old = this.get();
			this.set( a );

			if ( fn2 && a.length || !fn2 )
				this.each( fn2 || fn ).set( old );
			else
				this.set( old ).each( fn );
		}

		return this;
	}
};


jQuery.extend = jQuery.fn.extend = function() {
	// copy reference to target object
	var target = arguments[0],
		a = 1;

	// extend jQuery itself if only one argument is passed
	if ( arguments.length == 1 ) {
		target = this;
		a = 0;
	}
	var prop;
	while (prop = arguments[a++])
		// Extend the base object
		for ( var i in prop ) target[i] = prop[i];

	// Return the modified object
	return target;
};

jQuery.extend({

	init: function(){
		jQuery.initDone = true;

		jQuery.each( jQuery.macros.axis, function(i,n){
			jQuery.fn[ i ] = function(a) {
				var ret = jQuery.map(this,n);
				if ( a && typeof a == "string" )
					ret = jQuery.filter(a,ret).r;
				return this.pushStack( ret, arguments );
			};
		});

		jQuery.each( jQuery.macros.to, function(i,n){
			jQuery.fn[ i ] = function(){
				var a = arguments;
				return this.each(function(){
					for ( var j = 0; j < a.length; j++ )
						jQuery(a[j])[n]( this );
				});
			};
		});

		jQuery.each( jQuery.macros.each, function(i,n){
			jQuery.fn[ i ] = function() {
				return this.each( n, arguments );
			};
		});

		jQuery.each( jQuery.macros.filter, function(i,n){
			jQuery.fn[ n ] = function(num,fn) {
				return this.filter( ":" + n + "(" + num + ")", fn );
			};
		});

		jQuery.each( jQuery.macros.attr, function(i,n){
			n = n || i;
			jQuery.fn[ i ] = function(h) {
				return h == undefined ?
					this.length ? this[0][n] : null :
					this.attr( n, h );
			};
		});

		jQuery.each( jQuery.macros.css, function(i,n){
			jQuery.fn[ n ] = function(h) {
				return h == undefined ?
					( this.length ? jQuery.css( this[0], n ) : null ) :
					this.css( n, h );
			};
		});

	},

	// args is for internal usage only
	each: function( obj, fn, args ) {
		if ( obj.length == undefined )
			for ( var i in obj )
				fn.apply( obj[i], args || [i, obj[i]] );
		else
			for ( var i = 0; i < obj.length; i++ )
				if ( fn.apply( obj[i], args || [i, obj[i]] ) === false ) break;
		return obj;
	},

	className: {
		add: function(o,c){
			if (jQuery.className.has(o,c)) return;
			o.className += ( o.className ? " " : "" ) + c;
		},
		remove: function(o,c){
			if( !c ) {
				o.className = "";
			} else {
				var classes = o.className.split(" ");
				for(var i=0; i<classes.length; i++) {
					if(classes[i] == c) {
						classes.splice(i, 1);
						break;
					}
				}
				o.className = classes.join(' ');
			}
		},
		has: function(e,a) {
			if ( e.className != undefined )
				e = e.className;
			return new RegExp("(^|\\s)" + a + "(\\s|$)").test(e);
		}
	},

	swap: function(e,o,f) {
		for ( var i in o ) {
			e.style["old"+i] = e.style[i];
			e.style[i] = o[i];
		}
		f.apply( e, [] );
		for ( var i in o )
			e.style[i] = e.style["old"+i];
	},

	css: function(e,p) {
		if ( p == "height" || p == "width" ) {
			var old = {}, oHeight, oWidth, d = ["Top","Bottom","Right","Left"];

			for ( var i=0; i<d.length; i++ ) {
				old["padding" + d[i]] = 0;
				old["border" + d[i] + "Width"] = 0;
			}

			jQuery.swap( e, old, function() {
				if (jQuery.css(e,"display") != "none") {
					oHeight = e.offsetHeight;
					oWidth = e.offsetWidth;
				} else {
					e = jQuery(e.cloneNode(true))
						.find(":radio").removeAttr("checked").end()
						.css({
							visibility: "hidden", position: "absolute", display: "block", right: "0", left: "0"
						}).appendTo(e.parentNode)[0];

					var parPos = jQuery.css(e.parentNode,"position");
					if ( parPos == "" || parPos == "static" )
						e.parentNode.style.position = "relative";

					oHeight = e.clientHeight;
					oWidth = e.clientWidth;

					if ( parPos == "" || parPos == "static" )
						e.parentNode.style.position = "static";

					e.parentNode.removeChild(e);
				}
			});

			return p == "height" ? oHeight : oWidth;
		}

		return jQuery.curCSS( e, p );
	},

	curCSS: function(elem, prop, force) {
		var ret;
		
		if (prop == 'opacity' && jQuery.browser.msie)
			return jQuery.attr(elem.style, 'opacity');
			
		if (prop == "float" || prop == "cssFloat")
		    prop = jQuery.browser.msie ? "styleFloat" : "cssFloat";

		if (!force && elem.style[prop]) {

			ret = elem.style[prop];

		} else if (document.defaultView && document.defaultView.getComputedStyle) {

			if (prop == "cssFloat" || prop == "styleFloat")
				prop = "float";

			prop = prop.replace(/([A-Z])/g,"-$1").toLowerCase();
			var cur = document.defaultView.getComputedStyle(elem, null);

			if ( cur )
				ret = cur.getPropertyValue(prop);
			else if ( prop == 'display' )
				ret = 'none';
			else
				jQuery.swap(elem, { display: 'block' }, function() {
				    var c = document.defaultView.getComputedStyle(this, '');
				    ret = c && c.getPropertyValue(prop) || '';
				});

		} else if (elem.currentStyle) {

			var newProp = prop.replace(/\-(\w)/g,function(m,c){return c.toUpperCase();});
			ret = elem.currentStyle[prop] || elem.currentStyle[newProp];
			
		}

		return ret;
	},
	
	clean: function(a) {
		var r = [];
		for ( var i = 0; i < a.length; i++ ) {
			var arg = a[i];
			if ( typeof arg == "string" ) { // Convert html string into DOM nodes
				// Trim whitespace, otherwise indexOf won't work as expected
				var s = jQuery.trim(arg), div = document.createElement("div"), wrap = [0,"",""];

				if ( !s.indexOf("<opt") ) // option or optgroup
					wrap = [1, "<select>", "</select>"];
				else if ( !s.indexOf("<thead") || !s.indexOf("<tbody") )
					wrap = [1, "<table>", "</table>"];
				else if ( !s.indexOf("<tr") )
					wrap = [2, "<table>", "</table>"];	// tbody auto-inserted
				else if ( !s.indexOf("<td") || !s.indexOf("<th") )
					wrap = [3, "<table><tbody><tr>", "</tr></tbody></table>"];

				// Go to html and back, then peel off extra wrappers
				div.innerHTML = wrap[1] + s + wrap[2];
				while ( wrap[0]-- ) div = div.firstChild;
				arg = div.childNodes;
			} 
			
			
			if ( arg.length != undefined && ( (jQuery.browser.safari && typeof arg == 'function') || !arg.nodeType ) ) // Safari reports typeof on a DOM NodeList to be a function
				for ( var n = 0; n < arg.length; n++ ) // Handles Array, jQuery, DOM NodeList collections
					r.push(arg[n]);
			else
				r.push(	arg.nodeType ? arg : document.createTextNode(arg.toString()) );
		}

		return r;
	},

	expr: {
		"": "m[2]== '*'||a.nodeName.toUpperCase()==m[2].toUpperCase()",
		"#": "a.getAttribute('id')&&a.getAttribute('id')==m[2]",
		":": {
			// Position Checks
			lt: "i<m[3]-0",
			gt: "i>m[3]-0",
			nth: "m[3]-0==i",
			eq: "m[3]-0==i",
			first: "i==0",
			last: "i==r.length-1",
			even: "i%2==0",
			odd: "i%2",

			// Child Checks
			"nth-child": "jQuery.sibling(a,m[3]).cur",
			"first-child": "jQuery.sibling(a,0).cur",
			"last-child": "jQuery.sibling(a,0).last",
			"only-child": "jQuery.sibling(a).length==1",

			// Parent Checks
			parent: "a.childNodes.length",
			empty: "!a.childNodes.length",

			// Text Check
			contains: "jQuery.fn.text.apply([a]).indexOf(m[3])>=0",

			// Visibility
			visible: "a.type!='hidden'&&jQuery.css(a,'display')!='none'&&jQuery.css(a,'visibility')!='hidden'",
			hidden: "a.type=='hidden'||jQuery.css(a,'display')=='none'||jQuery.css(a,'visibility')=='hidden'",

			// Form attributes
			enabled: "!a.disabled",
			disabled: "a.disabled",
			checked: "a.checked",
			selected: "a.selected || jQuery.attr(a, 'selected')",

			// Form elements
			text: "a.type=='text'",
			radio: "a.type=='radio'",
			checkbox: "a.type=='checkbox'",
			file: "a.type=='file'",
			password: "a.type=='password'",
			submit: "a.type=='submit'",
			image: "a.type=='image'",
			reset: "a.type=='reset'",
			button: "a.type=='button'",
			input: "/input|select|textarea|button/i.test(a.nodeName)"
		},
		".": "jQuery.className.has(a,m[2])",
		"@": {
			"=": "z==m[4]",
			"!=": "z!=m[4]",
			"^=": "z && !z.indexOf(m[4])",
			"$=": "z && z.substr(z.length - m[4].length,m[4].length)==m[4]",
			"*=": "z && z.indexOf(m[4])>=0",
			"": "z"
		},
		"[": "jQuery.find(m[2],a).length"
	},

	token: [
		"\\.\\.|/\\.\\.", "a.parentNode",
		">|/", "jQuery.sibling(a.firstChild)",
		"\\+", "jQuery.sibling(a).next",
		"~", function(a){
			var s = jQuery.sibling(a);
			return s.n >= 0 ? s.slice(s.n+1) : [];
		}
	],

	find: function( t, context ) {
		// Make sure that the context is a DOM Element
		if ( context && context.nodeType == undefined )
			context = null;

		// Set the correct context (if none is provided)
		context = context || document;

		if ( t.constructor != String ) return [t];

		if ( !t.indexOf("//") ) {
			context = context.documentElement;
			t = t.substr(2,t.length);
		} else if ( !t.indexOf("/") ) {
			context = context.documentElement;
			t = t.substr(1,t.length);
			// FIX Assume the root element is right :(
			if ( t.indexOf("/") >= 1 )
				t = t.substr(t.indexOf("/"),t.length);
		}

		var ret = [context];
		var done = [];
		var last = null;

		while ( t.length > 0 && last != t ) {
			var r = [];
			last = t;

			t = jQuery.trim(t).replace( /^\/\//i, "" );

			var foundToken = false;

			for ( var i = 0; i < jQuery.token.length; i += 2 ) {
				if ( foundToken ) continue;

				var re = new RegExp("^(" + jQuery.token[i] + ")");
				var m = re.exec(t);

				if ( m ) {
					r = ret = jQuery.map( ret, jQuery.token[i+1] );
					t = jQuery.trim( t.replace( re, "" ) );
					foundToken = true;
				}
			}

			if ( !foundToken ) {
				if ( !t.indexOf(",") || !t.indexOf("|") ) {
					if ( ret[0] == context ) ret.shift();
					done = jQuery.merge( done, ret );
					r = ret = [context];
					t = " " + t.substr(1,t.length);
				} else {
					var re2 = /^([#.]?)([a-z0-9\\*_-]*)/i;
					var m = re2.exec(t);

					if ( m[1] == "#" ) {
						// Ummm, should make this work in all XML docs
						var oid = document.getElementById(m[2]);
						r = ret = oid ? [oid] : [];
						t = t.replace( re2, "" );
					} else {
						if ( !m[2] || m[1] == "." ) m[2] = "*";

						for ( var i = 0; i < ret.length; i++ )
							r = jQuery.merge( r,
								m[2] == "*" ?
									jQuery.getAll(ret[i]) :
									ret[i].getElementsByTagName(m[2])
							);
					}
				}

			}

			if ( t ) {
				var val = jQuery.filter(t,r);
				ret = r = val.r;
				t = jQuery.trim(val.t);
			}
		}

		if ( ret && ret[0] == context ) ret.shift();
		done = jQuery.merge( done, ret );

		return done;
	},

	getAll: function(o,r) {
		r = r || [];
		var s = o.childNodes;
		for ( var i = 0; i < s.length; i++ )
			if ( s[i].nodeType == 1 ) {
				r.push( s[i] );
				jQuery.getAll( s[i], r );
			}
		return r;
	},

	attr: function(elem, name, value){
		var fix = {
			"for": "htmlFor",
			"class": "className",
			"float": jQuery.browser.msie ? "styleFloat" : "cssFloat",
			cssFloat: jQuery.browser.msie ? "styleFloat" : "cssFloat",
			innerHTML: "innerHTML",
			className: "className",
			value: "value",
			disabled: "disabled",
			checked: "checked",
			readonly: "readOnly"
		};
		
		// IE actually uses filters for opacity ... elem is actually elem.style
		if (name == "opacity" && jQuery.browser.msie && value != undefined) {
			// IE has trouble with opacity if it does not have layout
			// Would prefer to check element.hasLayout first but don't have access to the element here
			elem['zoom'] = 1; 
			if (value == 1) // Remove filter to avoid more IE weirdness
				return elem["filter"] = elem["filter"].replace(/alpha\([^\)]*\)/gi,"");
			else
				return elem["filter"] = elem["filter"].replace(/alpha\([^\)]*\)/gi,"") + "alpha(opacity=" + value * 100 + ")";
		} else if (name == "opacity" && jQuery.browser.msie) {
			return elem["filter"] ? parseFloat( elem["filter"].match(/alpha\(opacity=(.*)\)/)[1] )/100 : 1;
		}
		
		// Mozilla doesn't play well with opacity 1
		if (name == "opacity" && jQuery.browser.mozilla && value == 1) value = 0.9999;

		if ( fix[name] ) {
			if ( value != undefined ) elem[fix[name]] = value;
			return elem[fix[name]];
		} else if( value == undefined && jQuery.browser.msie && elem.nodeName && elem.nodeName.toUpperCase() == 'FORM' && (name == 'action' || name == 'method') ) {
			return elem.getAttributeNode(name).nodeValue;
		} else if ( elem.tagName ) { // IE elem.getAttribute passes even for style
			if ( value != undefined ) elem.setAttribute( name, value );
			return elem.getAttribute( name );
		} else {
			name = name.replace(/-([a-z])/ig,function(z,b){return b.toUpperCase();});
			if ( value != undefined ) elem[name] = value;
			return elem[name];
		}
	},

	// The regular expressions that power the parsing engine
	parse: [
		// Match: [@value='test'], [@foo]
		"\\[ *(@)S *([!*$^=]*) *('?\"?)(.*?)\\4 *\\]",

		// Match: [div], [div p]
		"(\\[)\s*(.*?)\s*\\]",

		// Match: :contains('foo')
		"(:)S\\(\"?'?([^\\)]*?)\"?'?\\)",

		// Match: :even, :last-chlid
		"([:.#]*)S"
	],

	filter: function(t,r,not) {
		// Figure out if we're doing regular, or inverse, filtering
		var g = not !== false ? jQuery.grep :
			function(a,f) {return jQuery.grep(a,f,true);};

		while ( t && /^[a-z[({<*:.#]/i.test(t) ) {

			var p = jQuery.parse;

			for ( var i = 0; i < p.length; i++ ) {
		
				// Look for, and replace, string-like sequences
				// and finally build a regexp out of it
				var re = new RegExp(
					"^" + p[i].replace("S", "([a-z*_-][a-z0-9_-]*)"), "i" );

				var m = re.exec( t );

				if ( m ) {
					// Re-organize the first match
					if ( !i )
						m = ["",m[1], m[3], m[2], m[5]];

					// Remove what we just matched
					t = t.replace( re, "" );

					break;
				}
			}

			// :not() is a special case that can be optimized by
			// keeping it out of the expression list
			if ( m[1] == ":" && m[2] == "not" )
				r = jQuery.filter(m[3],r,false).r;

			// Otherwise, find the expression to execute
			else {
				var f = jQuery.expr[m[1]];
				if ( f.constructor != String )
					f = jQuery.expr[m[1]][m[2]];

				// Build a custom macro to enclose it
				eval("f = function(a,i){" +
					( m[1] == "@" ? "z=jQuery.attr(a,m[3]);" : "" ) +
					"return " + f + "}");

				// Execute it against the current filter
				r = g( r, f );
			}
		}

		// Return an array of filtered elements (r)
		// and the modified expression string (t)
		return { r: r, t: t };
	},

	trim: function(t){
		return t.replace(/^\s+|\s+$/g, "");
	},

	parents: function( elem ){
		var matched = [];
		var cur = elem.parentNode;
		while ( cur && cur != document ) {
			matched.push( cur );
			cur = cur.parentNode;
		}
		return matched;
	},

	sibling: function(elem, pos, not) {
		var elems = [];
		
		if(elem) {
			var siblings = elem.parentNode.childNodes;
			for ( var i = 0; i < siblings.length; i++ ) {
				if ( not === true && siblings[i] == elem ) continue;
	
				if ( siblings[i].nodeType == 1 )
					elems.push( siblings[i] );
				if ( siblings[i] == elem )
					elems.n = elems.length - 1;
			}
		}

		return jQuery.extend( elems, {
			last: elems.n == elems.length - 1,
			cur: pos == "even" && elems.n % 2 == 0 || pos == "odd" && elems.n % 2 || elems[pos] == elem,
			prev: elems[elems.n - 1],
			next: elems[elems.n + 1]
		});
	},

	merge: function(first, second) {
		var result = [];

		// Move b over to the new array (this helps to avoid
		// StaticNodeList instances)
		for ( var k = 0; k < first.length; k++ )
			result[k] = first[k];

		// Now check for duplicates between a and b and only
		// add the unique items
		for ( var i = 0; i < second.length; i++ ) {
			var noCollision = true;

			// The collision-checking process
			for ( var j = 0; j < first.length; j++ )
				if ( second[i] == first[j] )
					noCollision = false;

			// If the item is unique, add it
			if ( noCollision )
				result.push( second[i] );
		}

		return result;
	},

	grep: function(elems, fn, inv) {
		// If a string is passed in for the function, make a function
		// for it (a handy shortcut)
		if ( typeof fn == "string" )
			fn = new Function("a","i","return " + fn);

		var result = [];

		// Go through the array, only saving the items
		// that pass the validator function
		for ( var i = 0; i < elems.length; i++ )
			if ( !inv && fn(elems[i],i) || inv && !fn(elems[i],i) )
				result.push( elems[i] );

		return result;
	},

	map: function(elems, fn) {
		// If a string is passed in for the function, make a function
		// for it (a handy shortcut)
		if ( typeof fn == "string" )
			fn = new Function("a","return " + fn);

		var result = [];

		// Go through the array, translating each of the items to their
		// new value (or values).
		for ( var i = 0; i < elems.length; i++ ) {
			var val = fn(elems[i],i);

			if ( val !== null && val != undefined ) {
				if ( val.constructor != Array ) val = [val];
				result = jQuery.merge( result, val );
			}
		}

		return result;
	},

	/*
	 * A number of helper functions used for managing events.
	 * Many of the ideas behind this code orignated from Dean Edwards' addEvent library.
	 */
	event: {

		// Bind an event to an element
		// Original by Dean Edwards
		add: function(element, type, handler) {
			// For whatever reason, IE has trouble passing the window object
			// around, causing it to be cloned in the process
			if ( jQuery.browser.msie && element.setInterval != undefined )
				element = window;

			// Make sure that the function being executed has a unique ID
			if ( !handler.guid )
				handler.guid = this.guid++;

			// Init the element's event structure
			if (!element.events)
				element.events = {};

			// Get the current list of functions bound to this event
			var handlers = element.events[type];

			// If it hasn't been initialized yet
			if (!handlers) {
				// Init the event handler queue
				handlers = element.events[type] = {};

				// Remember an existing handler, if it's already there
				if (element["on" + type])
					handlers[0] = element["on" + type];
			}

			// Add the function to the element's handler list
			handlers[handler.guid] = handler;

			// And bind the global event handler to the element
			element["on" + type] = this.handle;

			// Remember the function in a global list (for triggering)
			if (!this.global[type])
				this.global[type] = [];
			this.global[type].push( element );
		},

		guid: 1,
		global: {},

		// Detach an event or set of events from an element
		remove: function(element, type, handler) {
			if (element.events)
				if (type && element.events[type])
					if ( handler )
						delete element.events[type][handler.guid];
					else
						for ( var i in element.events[type] )
							delete element.events[type][i];
				else
					for ( var j in element.events )
						this.remove( element, j );
		},

		trigger: function(type,data,element) {
			// Clone the incoming data, if any
			data = $.merge([], data || []);

			// Handle a global trigger
			if ( !element ) {
				var g = this.global[type];
				if ( g )
					for ( var i = 0; i < g.length; i++ )
						this.trigger( type, data, g[i] );

			// Handle triggering a single element
			} else if ( element["on" + type] ) {
				// Pass along a fake event
				data.unshift( this.fix({ type: type, target: element }) );

				// Trigger the event
				element["on" + type].apply( element, data );
			}
		},

		handle: function(event) {
			if ( typeof jQuery == "undefined" ) return false;

			event = jQuery.event.fix( event || window.event || {} ); // Empty object is for triggered events with no data

			// If no correct event was found, fail
			if ( !event ) return false;

			var returnValue = true;

			var c = this.events[event.type];

			var args = [].slice.call( arguments, 1 );
			args.unshift( event );

			for ( var j in c ) {
				if ( c[j].apply( this, args ) === false ) {
					event.preventDefault();
					event.stopPropagation();
					returnValue = false;
				}
			}

			// Clean up added properties in IE to prevent memory leak
			if (jQuery.browser.msie) event.target = event.preventDefault = event.stopPropagation = null;

			return returnValue;
		},

		fix: function(event) {
			// check IE
			if(jQuery.browser.msie) {
				// fix target property, if available
				// check prevents overwriting of fake target coming from trigger
				if(event.srcElement)
					event.target = event.srcElement;
					
				// calculate pageX/Y
				var e = document.documentElement, b = document.body;
				event.pageX = event.clientX + (e.scrollLeft || b.scrollLeft);
				event.pageY = event.clientY + (e.scrollTop || b.scrollTop);
					
			// check safari and if target is a textnode
			} else if(jQuery.browser.safari && event.target.nodeType == 3) {
				// target is readonly, clone the event object
				event = jQuery.extend({}, event);
				// get parentnode from textnode
				event.target = event.target.parentNode;
			}
			
			// fix preventDefault and stopPropagation
			if (!event.preventDefault)
				event.preventDefault = function() {
					this.returnValue = false;
				};
				
			if (!event.stopPropagation)
				event.stopPropagation = function() {
					this.cancelBubble = true;
				};
				
			return event;
		}
	}
});

 
/*
 * Wheather the W3C compliant box model is being used.
 *
 * @property
 * @name $.boxModel
 * @type Boolean
 * @cat Javascript
 */
new function() {
	var b = navigator.userAgent.toLowerCase();

	// Figure out what browser is being used
	jQuery.browser = {
		safari: /webkit/.test(b),
		opera: /opera/.test(b),
		msie: /msie/.test(b) && !/opera/.test(b),
		mozilla: /mozilla/.test(b) && !/(compatible|webkit)/.test(b)
	};

	// Check to see if the W3C box model is being used
	jQuery.boxModel = !jQuery.browser.msie || document.compatMode == "CSS1Compat";
};

jQuery.macros = {
	to: {

		appendTo: "append",

		prependTo: "prepend",

		insertBefore: "before",

		insertAfter: "after"
	},



	css: "width,height,top,left,position,float,overflow,color,background".split(","),



	filter: [ "eq", "lt", "gt", "contains" ],

	attr: {


		val: "value",


		html: "innerHTML",


		id: null,


		title: null,


		name: null,


		href: null,


		src: null,


		rel: null
	},

	axis: {


		parent: "a.parentNode",


		ancestors: jQuery.parents,


		parents: jQuery.parents,


		next: "jQuery.sibling(a).next",


		prev: "jQuery.sibling(a).prev",


		siblings: "jQuery.sibling(a, null, true)",


		children: "jQuery.sibling(a.firstChild)"
	},

	each: {

		removeAttr: function( key ) {
			jQuery.attr( this, key, "" );
			this.removeAttribute( key );
		},

		show: function(){
			this.style.display = this.oldblock ? this.oldblock : "";
			if ( jQuery.css(this,"display") == "none" )
				this.style.display = "block";
		},

		hide: function(){
			this.oldblock = this.oldblock || jQuery.css(this,"display");
			if ( this.oldblock == "none" )
				this.oldblock = "block";
			this.style.display = "none";
		},

		toggle: function(){
			jQuery(this)[ jQuery(this).is(":hidden") ? "show" : "hide" ].apply( jQuery(this), arguments );
		},

		addClass: function(c){
			jQuery.className.add(this,c);
		},

		removeClass: function(c){
			jQuery.className.remove(this,c);
		},

		toggleClass: function( c ){
			jQuery.className[ jQuery.className.has(this,c) ? "remove" : "add" ](this, c);
		},


		remove: function(a){
			if ( !a || jQuery.filter( a, [this] ).r )
				this.parentNode.removeChild( this );
		},

		empty: function(){
			while ( this.firstChild )
				this.removeChild( this.firstChild );
		},

		bind: function( type, fn ) {
			jQuery.event.add( this, type, fn );
		},


		unbind: function( type, fn ) {
			jQuery.event.remove( this, type, fn );
		},

		trigger: function( type, data ) {
			jQuery.event.trigger( type, data, this );
		}
	}
};

jQuery.init();
jQuery.fn.extend({

	// We're overriding the old toggle function, so
	// remember it for later
	_toggle: jQuery.fn.toggle,
	toggle: function(a,b) {
		// If two functions are passed in, we're
		// toggling on a click
		return a && b && a.constructor == Function && b.constructor == Function ? this.click(function(e){
			// Figure out which function to execute
			this.last = this.last == a ? b : a;
			
			// Make sure that clicks stop
			e.preventDefault();
			
			// and execute the function
			return this.last.apply( this, [e] ) || false;
		}) :
		
		// Otherwise, execute the old toggle function
		this._toggle.apply( this, arguments );
	},
	hover: function(f,g) {
		
		// A private function for haandling mouse 'hovering'
		function handleHover(e) {
			// Check if mouse(over|out) are still within the same parent element
			var p = (e.type == "mouseover" ? e.fromElement : e.toElement) || e.relatedTarget;
	
			// Traverse up the tree
			while ( p && p != this ) try { p = p.parentNode } catch(e) { p = this; };
			
			// If we actually just moused on to a sub-element, ignore it
			if ( p == this ) return false;
			
			// Execute the right function
			return (e.type == "mouseover" ? f : g).apply(this, [e]);
		}
		
		// Bind the function to the two event listeners
		return this.mouseover(handleHover).mouseout(handleHover);
	},
	ready: function(f) {
		// If the DOM is already ready
		if ( jQuery.isReady )
			// Execute the function immediately
			f.apply( document );
			
		// Otherwise, remember the function for later
		else {
			// Add the function to the wait list
			jQuery.readyList.push( f );
		}
	
		return this;
	}
});

jQuery.extend({
	/*
	 * All the code that makes DOM Ready work nicely.
	 */
	isReady: false,
	readyList: [],
	
	// Handle when the DOM is ready
	ready: function() {
		// Make sure that the DOM is not already loaded
		if ( !jQuery.isReady ) {
			// Remember that the DOM is ready
			jQuery.isReady = true;
			
			// If there are functions bound, to execute
			if ( jQuery.readyList ) {
				// Execute all of them
				for ( var i = 0; i < jQuery.readyList.length; i++ )
					jQuery.readyList[i].apply( document );
				
				// Reset the list of functions
				jQuery.readyList = null;
			}
			// Remove event lisenter to avoid memory leak
			if ( jQuery.browser.mozilla || jQuery.browser.opera )
				document.removeEventListener( "DOMContentLoaded", jQuery.ready, false );
		}
	}
});

new function(){

	var e = ("blur,focus,load,resize,scroll,unload,click,dblclick," +
		"mousedown,mouseup,mousemove,mouseover,mouseout,change,reset,select," + 
		"submit,keydown,keypress,keyup,error").split(",");

	// Go through all the event names, but make sure that
	// it is enclosed properly
	for ( var i = 0; i < e.length; i++ ) new function(){
			
		var o = e[i];
		
		// Handle event binding
		jQuery.fn[o] = function(f){
			return f ? this.bind(o, f) : this.trigger(o);
		};
		
		// Handle event unbinding
		jQuery.fn["un"+o] = function(f){ return this.unbind(o, f); };
		
		// Finally, handle events that only fire once
		jQuery.fn["one"+o] = function(f){
			// save cloned reference to this
			var element = jQuery(this);
			var handler = function() {
				// unbind itself when executed
				element.unbind(o, handler);
				element = null;
				// apply original handler with the same arguments
				return f.apply(this, arguments);
			};
			return this.bind(o, handler);
		};
			
	};
	
	// If Mozilla is used
	if ( jQuery.browser.mozilla || jQuery.browser.opera ) {
		// Use the handy event callback
		document.addEventListener( "DOMContentLoaded", jQuery.ready, false );
	
	// If IE is used, use the excellent hack by Matthias Miller
	// http://www.outofhanwell.com/blog/index.php?title=the_window_onload_problem_revisited
	} else if ( jQuery.browser.msie ) {
	
		// Only works if you document.write() it
		document.write("<scr" + "ipt id=__ie_init defer=true " + 
			"src=//:><\/script>");
	
		// Use the defer script hack
		var script = document.getElementById("__ie_init");
		if (script) // script does not exist if jQuery is loaded dynamically
			script.onreadystatechange = function() {
				if ( this.readyState != "complete" ) return;
				this.parentNode.removeChild( this );
				jQuery.ready();
			};
	
		// Clear from memory
		script = null;
	
	// If Safari  is used
	} else if ( jQuery.browser.safari ) {
		// Continually check to see if the document.readyState is valid
		jQuery.safariTimer = setInterval(function(){
			// loaded and complete are both valid states
			if ( document.readyState == "loaded" || 
				document.readyState == "complete" ) {
	
				// If either one are found, remove the timer
				clearInterval( jQuery.safariTimer );
				jQuery.safariTimer = null;
	
				// and execute any waiting functions
				jQuery.ready();
			}
		}, 10);
	} 

	// A fallback to window.onload, that will always work
	jQuery.event.add( window, "load", jQuery.ready );
	
};

// Clean up after IE to avoid memory leaks
if (jQuery.browser.msie) jQuery(window).unload(function() {
	var event = jQuery.event, global = event.global;
	for (var type in global) {
 		var els = global[type], i = els.length;
		if (i>0) do if (type != 'unload') event.remove(els[i-1], type); while (--i);
	}
});
jQuery.fn.extend({

	// overwrite the old show method
	_show: jQuery.fn.show,

	show: function(speed,callback){
		return speed ? this.animate({
			height: "show", width: "show", opacity: "show"
		}, speed, callback) : this._show();
	},
	
	// Overwrite the old hide method
	_hide: jQuery.fn.hide,

	hide: function(speed,callback){
		return speed ? this.animate({
			height: "hide", width: "hide", opacity: "hide"
		}, speed, callback) : this._hide();
	},

	slideDown: function(speed,callback){
		return this.animate({height: "show"}, speed, callback);
	},

	slideUp: function(speed,callback){
		return this.animate({height: "hide"}, speed, callback);
	},

	slideToggle: function(speed,callback){
		return this.each(function(){
			var state = jQuery(this).is(":hidden") ? "show" : "hide";
			jQuery(this).animate({height: state}, speed, callback);
		});
	},

	fadeIn: function(speed,callback){
		return this.animate({opacity: "show"}, speed, callback);
	},

	fadeOut: function(speed,callback){
		return this.animate({opacity: "hide"}, speed, callback);
	},

	fadeTo: function(speed,to,callback){
		return this.animate({opacity: to}, speed, callback);
	},
	animate: function(prop,speed,callback) {
		return this.queue(function(){
		
			this.curAnim = jQuery.extend({}, prop);
			
			for ( var p in prop ) {
				var e = new jQuery.fx( this, jQuery.speed(speed,callback), p );
				if ( prop[p].constructor == Number )
					e.custom( e.cur(), prop[p] );
				else
					e[ prop[p] ]( prop );
			}
			
		});
	},
	queue: function(type,fn){
		if ( !fn ) {
			fn = type;
			type = "fx";
		}
	
		return this.each(function(){
			if ( !this.queue )
				this.queue = {};
	
			if ( !this.queue[type] )
				this.queue[type] = [];
	
			this.queue[type].push( fn );
		
			if ( this.queue[type].length == 1 )
				fn.apply(this);
		});
	}

});

jQuery.extend({
	
	speed: function(s,o) {
		o = o || {};
		
		if ( o.constructor == Function )
			o = { complete: o };
		
		var ss = { slow: 600, fast: 200 };
		o.duration = (s && s.constructor == Number ? s : ss[s]) || 400;
	
		// Queueing
		o.oldComplete = o.complete;
		o.complete = function(){
			jQuery.dequeue(this, "fx");
			if ( o.oldComplete && o.oldComplete.constructor == Function )
				o.oldComplete.apply( this );
		};
	
		return o;
	},
	
	queue: {},
	
	dequeue: function(elem,type){
		type = type || "fx";
	
		if ( elem.queue && elem.queue[type] ) {
			// Remove self
			elem.queue[type].shift();
	
			// Get next function
			var f = elem.queue[type][0];
		
			if ( f ) f.apply( elem );
		}
	},

	/*
	 * I originally wrote fx() as a clone of moo.fx and in the process
	 * of making it small in size the code became illegible to sane
	 * people. You've been warned.
	 */
	
	fx: function( elem, options, prop ){

		var z = this;

		// The users options
		z.o = {
			duration: options.duration || 400,
			complete: options.complete,
			step: options.step
		};

		// The element
		z.el = elem;

		// The styles
		var y = z.el.style;
		
		// Store display property
		var oldDisplay = jQuery.css(z.el, 'display');
		// Set display property to block for animation
		y.display = "block";
		// Make sure that nothing sneaks out
		y.overflow = "hidden";

		// Simple function for setting a style value
		z.a = function(){
			if ( options.step )
				options.step.apply( elem, [ z.now ] );

			if ( prop == "opacity" )
				jQuery.attr(y, "opacity", z.now); // Let attr handle opacity
			else if ( parseInt(z.now) ) // My hate for IE will never die
				y[prop] = parseInt(z.now) + "px";
		};

		// Figure out the maximum number to run to
		z.max = function(){
			return parseFloat( jQuery.css(z.el,prop) );
		};

		// Get the current size
		z.cur = function(){
			var r = parseFloat( jQuery.curCSS(z.el, prop) );
			return r && r > -10000 ? r : z.max();
		};

		// Start an animation from one number to another
		z.custom = function(from,to){
			z.startTime = (new Date()).getTime();
			z.now = from;
			z.a();

			z.timer = setInterval(function(){
				z.step(from, to);
			}, 13);
		};

		// Simple 'show' function
		z.show = function(){
			if ( !z.el.orig ) z.el.orig = {};

			// Remember where we started, so that we can go back to it later
			z.el.orig[prop] = this.cur();

			z.o.show = true;

			// Begin the animation
			z.custom(0, z.el.orig[prop]);

			// Stupid IE, look what you made me do
			if ( prop != "opacity" )
				y[prop] = "1px";
		};

		// Simple 'hide' function
		z.hide = function(){
			if ( !z.el.orig ) z.el.orig = {};

			// Remember where we started, so that we can go back to it later
			z.el.orig[prop] = this.cur();

			z.o.hide = true;

			// Begin the animation
			z.custom(z.el.orig[prop], 0);
		};
		
		//Simple 'toggle' function
		z.toggle = function() {
			if ( !z.el.orig ) z.el.orig = {};

			// Remember where we started, so that we can go back to it later
			z.el.orig[prop] = this.cur();

			if(oldDisplay == 'none')  {
				z.o.show = true;
				
				// Stupid IE, look what you made me do
				if ( prop != "opacity" )
					y[prop] = "1px";

				// Begin the animation
				z.custom(0, z.el.orig[prop]);	
			} else {
				z.o.hide = true;

				// Begin the animation
				z.custom(z.el.orig[prop], 0);
			}		
		};

		// Each step of an animation
		z.step = function(firstNum, lastNum){
			var t = (new Date()).getTime();

			if (t > z.o.duration + z.startTime) {
				// Stop the timer
				clearInterval(z.timer);
				z.timer = null;

				z.now = lastNum;
				z.a();

				z.el.curAnim[ prop ] = true;

				var done = true;
				for ( var i in z.el.curAnim )
					if ( z.el.curAnim[i] !== true )
						done = false;

				if ( done ) {
					// Reset the overflow
					y.overflow = '';
					
					// Reset the display
					y.display = oldDisplay;
					if (jQuery.css(z.el, 'display') == 'none')
						y.display = 'block';

					// Hide the element if the "hide" operation was done
					if ( z.o.hide ) 
						y.display = 'none';

					// Reset the properties, if the item has been hidden or shown
					if ( z.o.hide || z.o.show )
						for ( var p in z.el.curAnim )
							if (p == "opacity")
								jQuery.attr(y, p, z.el.orig[p]);
							else
								y[p] = '';
				}

				// If a callback was provided, execute it
				if( done && z.o.complete && z.o.complete.constructor == Function )
					// Execute the complete function
					z.o.complete.apply( z.el );
			} else {
				// Figure out where in the animation we are and set the number
				var p = (t - this.startTime) / z.o.duration;
				z.now = ((-Math.cos(p*Math.PI)/2) + 0.5) * (lastNum-firstNum) + firstNum;

				// Perform the next step of the animation
				z.a();
			}
		};
	
	}

});
jQuery.fn.extend({
	loadIfModified: function( url, params, callback ) {
		this.load( url, params, callback, 1 );
	},
	load: function( url, params, callback, ifModified ) {
		if ( url.constructor == Function )
			return this.bind("load", url);

		callback = callback || function(){};

		// Default to a GET request
		var type = "GET";

		// If the second parameter was provided
		if ( params ) {
			// If it's a function
			if ( params.constructor == Function ) {
				// We assume that it's the callback
				callback = params;
				params = null;

			// Otherwise, build a param string
			} else {
				params = jQuery.param( params );
				type = "POST";
			}
		}

		var self = this;

		// Request the remote document
		jQuery.ajax({
			url: url,
			type: type,
			data: params,
			ifModified: ifModified,
			complete: function(res, status){
				if ( status == "success" || !ifModified && status == "notmodified" ) {
					// Inject the HTML into all the matched elements
					self.html(res.responseText)
					  // Execute all the scripts inside of the newly-injected HTML
					  .evalScripts()
					  // Execute callback
					  .each( callback, [res.responseText, status, res] );
				} else
					callback.apply( self, [res.responseText, status, res] );
			}
		});
		return this;
	},
	serialize: function() {
		return jQuery.param( this );
	},
	evalScripts: function() {
		return this.find('script').each(function(){
			if ( this.src )
				// for some weird reason, it doesn't work if the callback is ommited
				jQuery.getScript( this.src );
			else {
				jQuery.globalEval( this.text || this.textContent || this.innerHTML || "" );
			}
		}).end();
	}

});

// If IE is used, create a wrapper for the XMLHttpRequest object
if ( jQuery.browser.msie && typeof XMLHttpRequest == "undefined" )
	XMLHttpRequest = function(){
		return new ActiveXObject("Microsoft.XMLHTTP");
	};

// Attach a bunch of functions for handling common AJAX events

new function(){
	var e = "ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(",");

	for ( var i = 0; i < e.length; i++ ) new function(){
		var o = e[i];
		jQuery.fn[o] = function(f){
			return this.bind(o, f);
		};
	};
};

jQuery.extend({
	get: function( url, data, callback, type, ifModified ) {
		// shift arguments if data argument was ommited
		if ( data && data.constructor == Function ) {
			callback = data;
			data = null;
		}

		// Delegate
		jQuery.ajax({
			url: url,
			data: data,
			success: callback,
			dataType: type,
			ifModified: ifModified
		});
	},
	getIfModified: function( url, data, callback, type ) {
		jQuery.get(url, data, callback, type, 1);
	},
	getScript: function( url, callback ) {
		if(callback)
			jQuery.get(url, null, callback, "script");
		else {
			jQuery.get(url, null, null, "script");
		}
	},
	getJSON: function( url, data, callback ) {
		jQuery.get(url, data, callback, "json");
	},
	post: function( url, data, callback, type ) {
		// Delegate
		jQuery.ajax({
			type: "POST",
			url: url,
			data: data,
			success: callback,
			dataType: type
		});
	},

	// timeout (ms)
	timeout: 0,
	ajaxTimeout: function(timeout) {
		jQuery.timeout = timeout;
	},

	// Last-Modified header cache for next request
	lastModified: {},
	ajax: function( s ) {
		// TODO introduce global settings, allowing the client to modify them for all requests, not only timeout
		s = jQuery.extend({
			global: true,
			ifModified: false,
			type: "GET",
			timeout: jQuery.timeout,
			complete: null,
			success: null,
			error: null,
			dataType: null,
			url: null,
			data: null,
			contentType: "application/x-www-form-urlencoded",
			processData: true,
			async: true,
			beforeSend: null
		}, s);

		// if data available
		if ( s.data ) {
			// convert data if not already a string
			if (s.processData && typeof s.data != 'string')
    			s.data = jQuery.param(s.data);
			// append data to url for get requests
			if( s.type.toLowerCase() == "get" )
				// "?" + data or "&" + data (in case there are already params)
				s.url += ((s.url.indexOf("?") > -1) ? "&" : "?") + s.data;
		}

		// Watch for a new set of requests
		if ( s.global && ! jQuery.active++ )
			jQuery.event.trigger( "ajaxStart" );

		var requestDone = false;

		// Create the request object
		var xml = new XMLHttpRequest();

		// Open the socket
		xml.open(s.type, s.url, s.async);

		// Set the correct header, if data is being sent
		if ( s.data )
			xml.setRequestHeader("Content-Type", s.contentType);

		// Set the If-Modified-Since header, if ifModified mode.
		if ( s.ifModified )
			xml.setRequestHeader("If-Modified-Since",
				jQuery.lastModified[s.url] || "Thu, 01 Jan 1970 00:00:00 GMT" );

		// Set header so the called script knows that it's an XMLHttpRequest
		xml.setRequestHeader("X-Requested-With", "XMLHttpRequest");

		// Make sure the browser sends the right content length
		if ( xml.overrideMimeType )
			xml.setRequestHeader("Connection", "close");
			
		// Allow custom headers/mimetypes
		if( s.beforeSend )
			s.beforeSend(xml);
		if (s.global)
		    jQuery.event.trigger("ajaxSend", [xml, s]);

		// Wait for a response to come back
		var onreadystatechange = function(isTimeout){
			// The transfer is complete and the data is available, or the request timed out
			if ( xml && (xml.readyState == 4 || isTimeout == "timeout") ) {
				requestDone = true;

				var status = jQuery.httpSuccess( xml ) && isTimeout != "timeout" ?
					s.ifModified && jQuery.httpNotModified( xml, s.url ) ? "notmodified" : "success" : "error";

				// Make sure that the request was successful or notmodified
				if ( status != "error" ) {
					// Cache Last-Modified header, if ifModified mode.
					var modRes;
					try {
						modRes = xml.getResponseHeader("Last-Modified");
					} catch(e) {} // swallow exception thrown by FF if header is not available

					if ( s.ifModified && modRes )
						jQuery.lastModified[s.url] = modRes;

					// process the data (runs the xml through httpData regardless of callback)
					var data = jQuery.httpData( xml, s.dataType );

					// If a local callback was specified, fire it and pass it the data
					if ( s.success )
						s.success( data, status );

					// Fire the global callback
					if( s.global )
						jQuery.event.trigger( "ajaxSuccess", [xml, s] );

				// Otherwise, the request was not successful
				} else {
					// If a local callback was specified, fire it
					if ( s.error ) s.error( xml, status );

					// Fire the global callback
					if( s.global )
						jQuery.event.trigger( "ajaxError", [xml, s] );
				}

				// The request was completed
				if( s.global )
					jQuery.event.trigger( "ajaxComplete", [xml, s] );

				// Handle the global AJAX counter
				if ( s.global && ! --jQuery.active )
					jQuery.event.trigger( "ajaxStop" );

				// Process result
				if ( s.complete ) s.complete(xml, status);

				// Stop memory leaks
				xml.onreadystatechange = function(){};
				xml = null;

			}
		};
		xml.onreadystatechange = onreadystatechange;

		// Timeout checker
		if(s.timeout > 0)
			setTimeout(function(){
				// Check to see if the request is still happening
				if (xml) {
					// Cancel the request
					xml.abort();

					if ( !requestDone ) onreadystatechange( "timeout" );

					// Clear from memory
					xml = null;
				}
			}, s.timeout);

		// Send the data
		xml.send(s.data);
		
		// return XMLHttpRequest to allow aborting the request etc.
		return xml;
	},

	// Counter for holding the number of active queries
	active: 0,

	// Determines if an XMLHttpRequest was successful or not
	httpSuccess: function(r) {
		try {
			return !r.status && location.protocol == "file:" ||
				( r.status >= 200 && r.status < 300 ) || r.status == 304 ||
				jQuery.browser.safari && r.status == undefined;
		} catch(e){}

		return false;
	},

	// Determines if an XMLHttpRequest returns NotModified
	httpNotModified: function(xml, url) {
		try {
			var xmlRes = xml.getResponseHeader("Last-Modified");

			// Firefox always returns 200. check Last-Modified date
			return xml.status == 304 || xmlRes == jQuery.lastModified[url] ||
				jQuery.browser.safari && xml.status == undefined;
		} catch(e){}

		return false;
	},

	/* Get the data out of an XMLHttpRequest.
	 * Return parsed XML if content-type header is "xml" and type is "xml" or omitted,
	 * otherwise return plain text.
	 * (String) data - The type of data that you're expecting back,
	 * (e.g. "xml", "html", "script")
	 */
	httpData: function(r,type) {
		var ct = r.getResponseHeader("content-type");
		var data = !type && ct && ct.indexOf("xml") >= 0;
		data = type == "xml" || data ? r.responseXML : r.responseText;

		// If the type is "script", eval it in global context
		if ( type == "script" ) {
			jQuery.globalEval( data );
		}

		// Get the JavaScript object, if JSON is used.
		if ( type == "json" ) eval( "data = " + data );

		// evaluate scripts within html
		if ( type == "html" ) jQuery("<div>").html(data).evalScripts();

		return data;
	},

	// Serialize an array of form elements or a set of
	// key/values into a query string
	param: function(a) {
		var s = [];

		// If an array was passed in, assume that it is an array
		// of form elements
		if ( a.constructor == Array || a.jquery ) {
			// Serialize the form elements
			for ( var i = 0; i < a.length; i++ )
				s.push( a[i].name + "=" + encodeURIComponent( a[i].value ) );

		// Otherwise, assume that it's an object of key/value pairs
		} else {
			// Serialize the key/values
			for ( var j in a ) {
				// If the value is an array then the key names need to be repeated
				if( a[j].constructor == Array ) {
					for (var k = 0; k < a[j].length; k++) {
						s.push( j + "=" + encodeURIComponent( a[j][k] ) );
					}
				} else {
					s.push( j + "=" + encodeURIComponent( a[j] ) );
				}
			}
		}

		// Return the resulting serialization
		return s.join("&");
	},
	
	// evalulates a script in global context
	// not reliable for safari
	globalEval: function(data) {
		if (window.execScript)
			window.execScript( data );
		else if(jQuery.browser.safari)
			// safari doesn't provide a synchronous global eval
			window.setTimeout( data, 0 );
		else
			eval.call( window, data );
	}

});
} // close: if(typeof window.jQuery == "undefined") {
/*
 * JTip
 * By Cody Lindley (http://www.codylindley.com)
 * Under an Attribution, Share Alike License
 * JTip is built on top of the very light weight jquery library.
 
 * Modifications by Rey Bango and Karl Swedberg
 * Modifications by Auke van Slooten
 *  17/01/07 
 *	- Removed click handler, hyperlinks may be followed as usual
 *      - class jTip is now enough, doesn't need to be a hyperlink
 *	- JT divs are now appended once, and only hidden, not removed, on mouseout
 *	- mouseout now waits 500 ms, and checks global var jTipHovering if the mouse
 *	  isn't hovering over a new tip or the jTip div itself.
 *	- hovering over the tip itself now stops the tip from hiding
 *	- jTip doesn't check the arguments to href of the hyperlink anymore, needs
 *	  an alternative place to store the arguments (rel attr? expando attr?)
 *	  width is fixed to 250px for now
 *	- getAbsoluteTop no longer skips the first offsetParent, I needed it.
 *	- jTip doesn't init on page load automatically anymore, since I needed it to
 *	  work with Ajax content that loaded later. Just call JT_init() when you need it
 *	- moved the title from the name attribute to the title attribute
 */

var jTipHovering=false;

function JT_init(){
	// 9/21/06 - Rey Bango added hide() method to correct an issue with FF
	$(".jTip").each(function() {
		if (this.title) {
			this.setAttribute('jt:title', this.title);
			this.removeAttribute('title');
		}
	});
	$(".jTip").hover(
		function() {
			jTipHovering=true;
			JT_show($(this).attr('href'),this,$(this).attr('jt:title'),$(this).attr('jt:body'));
			return false;
		},
		function() {
			jTipHovering=false;
			setTimeout(function() {
				if (!jTipHovering) {
					$('#JT, #JT_arrow_left, #JT_arrow_right').css({visibility: 'hidden'}); //.remove();
				}
			}, 500);
		}
	);
	if (!document.getElementById('JT')) {
		$('body').append("<div id='JT' style='width:250px; visibility: hidden;'><div id='JT_close_left'></div><div id='JT_copy'><div class='JT_loader'><div></div></div>");//right side
		$('body').append('<div id="JT_arrow_left" style="visibility: hidden;"></div>'); 
		$('body').append('<div id="JT_arrow_right" style="visiblity: hidden;"></div>');
		if ($.browser.msie) { 
			$('#JT').prepend('<iframe id="jTipiFrame"></iframe>'); // iframe for IE select box z-index issue
			$('#jTipiFrame').width("250px");	
		}
	}
	$('#JT').hover(
		function() {
			jTipHovering=true;
		},
		function() {
			jTipHovering=false;
			setTimeout(function() {
				if (!jTipHovering) {
					$('#JT, #JT_arrow_left, #JT_arrow_right').css({visibility: 'hidden'}); //.remove();
				}
			}, 500);
		}
	);
}

function JT_show(url,object,title,body){
	if (title == false) title = "&nbsp;";
	var de = document.documentElement;
	var w = self.innerWidth || (de&&de.clientWidth) || document.body.clientWidth;
	var hasArea = w - getAbsoluteLeft(object);
	var clickElementy = getAbsoluteTop(object) - 3; //set y position
	
	var params = { };
	if (params['width'] === undefined) {
		params['width'] = 250
	};
	
	if (hasArea>((params['width']*1)+175)) {
		var arrowOffset = getElementWidth(object) + 11;
		var clickElementx = getAbsoluteLeft(object) + arrowOffset; //set x position
		$('#JT_arrow_left').css({left: (clickElementx - 9) + "px", top: clickElementy +"px", visibility: 'visible'});		
	} else {
		var clickElementx = getAbsoluteLeft(object) - ((params['width']*1) + 20); //set x position
		$('#JT_arrow_right').css({left: (getAbsoluteLeft(object) - 22) + "px", top: clickElementy + "px", visibility: 'visible'});		
	}
	$('#JT').css({left: clickElementx+"px", top: clickElementy +"px"});
   

	var JT_resize=function() {
		//if jtip goes to left side and is partially cut off at left of doc...	  
		if ($('#JT_arrow_right') && clickElementx < 0) {
			var JT_width = (getAbsoluteLeft(object) - 22);
			$('#JT').css({left: 2, width: JT_width}); //adjust width to fit
		}
		//get the height of the jtip after loading it
		var jtip_height = $('#JT').height();
		//adjust the top of jTip
		move_jtip();
		if ( (scroll_position + window_height) - clickElementy < jtip_height ) {
			var adjusted_top = (window_height - jtip_height) - 6 + scroll_position;
			if ( adjusted_top - scroll_position < 0 ) {
				$('#JT').css({top: scroll_position + 1});
			} else {
				$('#JT').css({top: adjusted_top});
			}
		}      
	}

	document.getElementById('JT_close_left').innerHTML=title;
//	$('#JT_close_left').html(title);
	if (!body) {
		$('#JT_copy').load(url, JT_resize); // end .load()
		$('#JT').css({visibility: 'visible'});
	} else {
//		$('#JT_copy').get().html(body);
		document.getElementById('JT_copy').innerHTML=body; 
		JT_resize();
		$('#JT').css({visibility: 'visible'});
	}
} // end JT_show()

function getElementWidth(o) {
	return o.offsetWidth;
}

function getAbsoluteLeft(o) {
	// Get an object left position from the upper left viewport corner
	oLeft = o.offsetLeft            // Get left position from the parent object
	while(o.offsetParent!=null) {   // Parse the parent hierarchy up to the document element
		oParent = o.offsetParent    // Get parent object reference
		oLeft += oParent.offsetLeft // Add parent left position
		o = oParent
	}
	return oLeft
}

function getAbsoluteTop(o) {
	// Get an object top position from the upper left viewport corner
	oTop = 0;
	while(o) { // Parse the parent hierarchy up to the document element
		oTop += o.offsetTop; // Add parent top position
		o = o.offsetParent;
	}
	return oTop
}

function parseQuery ( query ) {
   var Params = new Object ();
   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 move_jtip() {
  if (window.innerHeight) {
	  scroll_position = window.pageYOffset;
	  window_height = window.innerHeight;
	}
	else if (document.documentElement && document.documentElement.scrollTop) {
		scroll_position = document.documentElement.scrollTop;
    window_height = document.documentElement.clientHeight;
	}
	else if (document.body) {
	  scroll_position = document.body.scrollTop;
	  window_height = document.body.clientHeight;
	}
}

function blockEvents(evt) {
  if(evt.target){
    evt.preventDefault();
  }else{
    evt.returnValue = false;
  }
}function menuOpen(a) {
	obj = document.getElementById(a); 
	if(obj){
		obj.style.visibility="visible";
		obj.style.display="block";
	}
}

function menuClose(a) {
	obj = document.getElementById(a); 
	if(obj){
		obj.style.visibility="hidden";
		obj.style.display="none";

	}
}
function setOpacity(a, opacity) {
	obj = document.getElementById(a); 
	if(obj){
		obj.style.filter = "alpha(opacity=" + (opacity*100) + ")";
		obj.style.MozOpacity = opacity;
		obj.style.KHTMLOpacity = opacity;
		obj.style.opacity = opacity;
		obj.style.zoom = "1.0";
	}
}/*
 * drag.js - click & drag DOM elements
 *
 * originally based on Youngpup's dom-drag.js, www.youngpup.net
 */

/**********************************************************
 Further modified from the example by Tim Taylor
 http://tool-man.org/examples/sorting.html
 
 Changed onMouseMove where it calls group.onDrag and then
 adjusts the offset for changes to the DOM.  If the item
 being moved changed parents it would be off so changed to
 get the absolute offset (recursive northwestOffset).
 
 **********************************************************/

var Drag = {
	BIG_Z_INDEX : 10000,
	group : null,
	isDragging : false,

	makeDraggable : function(group) {
		group.handle = group;
		group.handle.group = group;
		group.handle.onselectstart = function() {return false;}

		group.minX = null;
		group.minY = null;
		group.maxX = null;
		group.maxY = null;
		group.threshold = 0;
		group.thresholdY = 0;
		group.thresholdX = 0;

		group.onDragStart = new Function();
		group.onDragEnd = new Function();
		group.onDrag = new Function();
		group.allowDragStart = function() {
			return true;
		};
	
		// TODO: use element.prototype.myFunc
		group.setDragHandle = Drag.setDragHandle;
		group.setDragThreshold = Drag.setDragThreshold;
		group.setDragThresholdX = Drag.setDragThresholdX;
		group.setDragThresholdY = Drag.setDragThresholdY;
		group.constrain = Drag.constrain;
		group.constrainVertical = Drag.constrainVertical;
		group.constrainHorizontal = Drag.constrainHorizontal;

		group.onmousedown = Drag.onMouseDown;
	},

	constrainVertical : function() {
		var nwOffset = Coordinates.northwestOffset(this, true);
		this.minX = nwOffset.x;
		this.maxX = nwOffset.x;
	},

	constrainHorizontal : function() {
		var nwOffset = Coordinates.northwestOffset(this, true);
		this.minY = nwOffset.y;
		this.maxY = nwOffset.y;
	},

	constrain : function(nwPosition, sePosition) {
		this.minX = nwPosition.x;
		this.minY = nwPosition.y;
		this.maxX = sePosition.x;
		this.maxY = sePosition.y;
	},

	setDragHandle : function(handle) {
		if (handle && handle != null) {
			this.handle = handle;
		} else {
			this.handle = this;
		}

		this.handle.group = this;
		this.onmousedown = null;
		this.onselectstart = null;
		this.handle.onmousedown = Drag.onMouseDown;

		this.handle.ondrag = function() {return false;}
		this.handle.onselectstart = function() {return false;}

	},

	setDragThreshold : function(threshold) {
		if (isNaN(parseInt(threshold))) return;

		this.threshold = threshold;
	},

	setDragThresholdX : function(threshold) {
		if (isNaN(parseInt(threshold))) return;

		this.thresholdX = threshold;
	},

	setDragThresholdY : function(threshold) {
		if (isNaN(parseInt(threshold))) return;

		this.thresholdY = threshold;
	},

	onMouseDown : function(event) {
		if (Drag.isDragging) {
			return;
		}
		
		//this.group.preDragStart();
				
		if (!this.group.allowDragStart()) {
			return;
		}

		event = Drag.fixEvent(event);
		if (this.group.copy) {
			Drag.group = this.group.cloneNode(true);
			DragDrop.makeItemDraggable(Drag.group);
			Drag.group.olddisplay = Drag.group.style.display;
			Drag.group.copy = true;
			Drag.group.style.display = "none";

	                this.group.parentNode.insertBefore(Drag.group, this.group);
		} else {
			Drag.group = this.group;
		}

		var group = Drag.group;
		group.originalPosition=group.style.position;
		group.style.position='relative';
		var mouse = event.windowCoordinate;

		var offsets = Coordinates.getOffsets(group, true);
		var nwOffset = offsets[0];
		var seOffset = offsets[1];
		var scrollOffset = offsets[2];

//		var nwOffset = Coordinates.northwestOffset(group, true);
//		var seOffset = Coordinates.southeastOffset(group, true);
		var nwPosition = Coordinates.northwestPosition(group);
		var sePosition = Coordinates.southeastPosition(group);
//		var scrollOffset = Coordinates.scrollOffset(group);

		if (group.style.opacity) {
			group.originalOpacity = group.style.opacity;
		} else {
			group.originalOpacity = 1;
		}
		if (group.style.filter) {
			group.originalFilter = group.style.filter;
		}

		group.originalZIndex = group.style.zIndex;
		group.initialWindowCoordinate = mouse;
		group.mynw = group.initialWindowCoordinate.minus(nwOffset);

		// TODO: need a better name, but don't yet understand how it
		// participates in the magic while dragging 
		group.dragCoordinate = mouse;

//		Drag.showStatus(mouse, nwPosition, sePosition, nwOffset, seOffset, scrollOffset);

		group.onDragStart(nwPosition, sePosition, nwOffset, seOffset, scrollOffset);

		// TODO: need better constraint API
		if (group.minX != null)
			group.minMouseX = mouse.x - nwPosition.x + 
					group.minX - nwOffset.x;
		if (group.maxX != null) 
			group.maxMouseX = group.minMouseX + group.maxX - group.minX;

		if (group.minY != null)
			group.minMouseY = mouse.y - nwPosition.y + 
					group.minY - nwOffset.y;
		if (group.maxY != null) 
			group.maxMouseY = group.minMouseY + group.maxY - group.minY;

		group.mouseMin = new Coordinate(group.minMouseX, group.minMouseY);
		group.mouseMax = new Coordinate(group.maxMouseX, group.maxMouseY);

		document.onmousemove = Drag.onMouseMove;
		document.onmouseup = Drag.onMouseUp;

		event.cancelBubble = true;
		return false;
	},

	
	showStatus : function(mouse, nwPosition, sePosition, nwOffset, seOffset, scrollOffset) {
		window.status = 
				"mouse: " + mouse.toString() + "    " + 
				"NW pos: " + nwPosition.toString() + "    " + 
				"SE pos: " + sePosition.toString() + "    " + 
				"NW offset: " + nwOffset.toString() + "    " +
				"SE offset: " + seOffset.toString() + "    " +
				"Scroll offset: " + scrollOffset.toString();
	},

	onMouseMove : function(event) {
		event = Drag.fixEvent(event);
		var group = Drag.group;
		var mouse = event.windowCoordinate;

		var offsets = Coordinates.getOffsets(group, true);
		var nwOffset = offsets[0];
		var seOffset = offsets[1];
		var scrollOffset = offsets[2];

//		var nwOffset = Coordinates.northwestOffset(group, true);
//		var seOffset = Coordinates.southeastOffset(group, true);

		var nwPosition = Coordinates.northwestPosition(group);
		var sePosition = Coordinates.southeastPosition(group);
//		var scrollOffset = Coordinates.scrollOffset(group);

//		Drag.showStatus(mouse, nwPosition, sePosition, nwOffset, seOffset, scrollOffset);

		if (!Drag.isDragging) {
			if (group.threshold > 0) {
				var distance = group.initialWindowCoordinate.distance(
						mouse);
				if (distance < group.threshold) return true;
			} else if (group.thresholdY > 0) {
				var deltaY = Math.abs(group.initialWindowCoordinate.y - mouse.y);
				if (deltaY < group.thresholdY) return true;
			} else if (group.thresholdX > 0) {
				var deltaX = Math.abs(group.initialWindowCoordinate.x - mouse.x);
				if (deltaX < group.thresholdX) return true;
			}

			Drag.isDragging = true;
			if (group.copy) {
				group.style.display = group.olddisplay;
			}

			group.style["zIndex"] = Drag.BIG_Z_INDEX;

			Drag.setOpacity(group, 0.5);
			//group.style["opacity"] = 0.5;
		}

		// TODO: need better constraint API

		var adjusted = mouse.constrain(group.mouseMin, group.mouseMax);

		nwPosition = nwPosition.plus(adjusted.minus(group.dragCoordinate));
		nwPosition.reposition(group);
		group.dragCoordinate = adjusted;


		// once dragging has started, the position of the group
		// relative to the mouse should stay fixed.  They can get out
		// of sync if the DOM is manipulated while dragging, so we
		// correct the error here
		//
		// TODO: what we really want to do is find the offset from
		// our corner to the mouse coordinate and adjust to keep it
		// the same
		
		// changed to be recursive/use absolute offset for corrections
////		var offsetBefore = Coordinates.northwestOffset(group, true);
////		var scrollOffsetBefore = Coordinates.scrollOffset(group);

		offsets = Coordinates.getOffsets(group, true);
		var offsetBefore = offsets[0];
		var scrollOffsetBefore = offsets[2];

		group.onDrag(nwPosition, sePosition, nwOffset, seOffset, scrollOffset, mouse);

		offsets = Coordinates.getOffsets(group, true);

//		var offsetAfter = Coordinates.northwestOffset(group, true);
//		var scrollOffsetAfter = Coordinates.scrollOffset(group);
		var offsetAfter = offsets[0];
		var scrollOffsetAfter = offsets[2];

		if ((!offsetBefore.equals(offsetAfter)) || (!scrollOffsetBefore.equals(scrollOffsetAfter))) {
			var errorDelta = offsetBefore.minus(offsetAfter);

			nwPosition = Coordinates.northwestPosition(group).plus(errorDelta);

			var scrollErrorDelta = scrollOffsetBefore.minus(scrollOffsetAfter);
			nwPosition = nwPosition.minus(scrollErrorDelta);

			nwPosition.reposition(group);
		}
		event.cancelBubble = true;
		return false;
	},

	onMouseUp : function(event) {
		event = Drag.fixEvent(event);
		var group = Drag.group;
		group.style.position=group.originalPosition;
		var mouse = event.windowCoordinate;

		var offsets = Coordinates.getOffsets(group, true);
		
//		var nwOffset = Coordinates.northwestOffset(group, true);
//		var seOffset = Coordinates.southeastOffset(group, true);
		var nwOffset = offsets[0];
		var seOffset = offsets[1];
		var scrollOffset = offsets[2];

		var nwPosition = Coordinates.northwestPosition(group);
		var sePosition = Coordinates.southeastPosition(group);
//                var scrollOffset = Coordinates.scrollOffset(group);

		document.onmousemove = null;
		document.onmouseup   = null;

		if (Drag.isDragging) {
			group.onDragEnd(nwPosition, sePosition, nwOffset, seOffset, scrollOffset);
			// restoring zIndex before opacity avoids visual flicker in Firefox
			group.style["zIndex"] = group.originalZIndex;
			Drag.unsetOpacity(group);
		}

		if (group.copy) {
			group.copy = false;
		}


		Drag.group = null;
		Drag.isDragging = false;
		event.cancelBubble = true;
		return false;
	},

	setOpacity : function(object, opacity) {
		if (opacity >= 1) {
		        opacity = 1;
		}
		if (opacity < 0) {
		        opacity = 0;
		}

		object.style.filter = "alpha(opacity=" + (opacity*100) + ")";
		object.style.MozOpacity = opacity;
		object.style.KHTMLOpacity = opacity;
		object.style.opacity = opacity;
		object.style.zoom = "1.0";

		object.isDragging = true;
	},

	unsetOpacity : function(object) {
		Drag.setOpacity(object, object.originalOpacity);
		object.style.filter = object.originalFilter;

		object.isDragging = false;
	},

	fixEvent : function(event) {
		if (typeof event == 'undefined') event = window.event;
		Coordinates.fixEvent(event);

		return event;
	}
};
/**********************************************************
 Adapted from the sortable lists example by Tim Taylor
 http://tool-man.org/examples/sorting.html
 
 **********************************************************/

var DragDrop = {
	firstContainer : null,
	lastContainer : null,
	
	makeListContainer : function(list) {
		// each container becomes a linked list node
		if (this.firstContainer == null) {
			this.firstContainer = this.lastContainer = list;
			list.previousContainer = null;
			list.nextContainer = null;
		} else {
			list.previousContainer = this.lastContainer;
			list.nextContainer = null;
			this.lastContainer.nextContainer = list;
			this.lastContainer = list;
		}
		
		// these functions are called when an item is draged over
		// a container or out of a container bounds.  onDragOut
		// is also called when the drag ends with an item having
		// been added to the container
		list.onDragOver = new Function();
		list.onDragOut = new Function();
                list.onDragDrop = new Function();
		list.onSnapBack = new Function();

		// This function is called when an item is dropped. If it
		// returns true, the item is allowed to drop. Is it returns
		// false, the item cannot be dropped on this list.
		list.acceptCheck = function(item) {
			return true;
		}
		
		//list.preDragStart = new Function();
		
		list.SwapIn = new Function();
		list.SwapIn = DragDrop.SwapIn;
				
    		var items = list.getElementsByTagName( "li" );
//    		var items = list.childNodes;
    	
		for (var i = 0; i < items.length; i++) {
			if(items[i].parentNode == list) {
				DragDrop.makeItemDraggable(items[i]);
				items[i].copy = false;
			}
		}
	},

	makeCopyListContainer : function(list) {
		DragDrop.makeListContainer(list);
		var items = list.getElementsByTagName( "li" );
//    		var items = list.childNodes;

		for (var i=0; i < items.length; i++) {
			if(items[i].parentNode == list) {
				items[i].copy = true;
			}
		}
	},

	makeDropList : function(list, droplist) {
		// Constrain the items to make them only droppable in certain classes.
		list.dropList = droplist;
	},

	makeItemDraggable : function(item) {
		if (DragDrop.classMatch(item.className, "undraggable")) {
			return;
		}
		Drag.makeDraggable(item);
		item.setDragThreshold(5);
		
		// tracks if the item is currently outside all containers
		item.isOutside = false;

		//item.preDragStart = DragDrop.preDragStart;
		item.onDragStart = DragDrop.onDragStart;
		item.onDrag = DragDrop.onDrag;
		item.onDragEnd = DragDrop.onDragEnd;
	},

//	preDragStart : function() {
//		this.sourceParent = this.parentNode;
//		this.sourceNextSibling = this.nextSibling;
//		alert(this.sourceNextSibling);
//	},
	
	onDragStart : function(nwPosition, sePosition, nwOffset, seOffset, scrollOffset) {
		// update all container bounds, since they may have changed
		// on a previous drag
		//
		// could be more smart about when to do this

		var container = DragDrop.firstContainer;
		while (container != null) {
			container.northwest = Coordinates.northwestOffset( container, true );
			container.southeast = Coordinates.southeastOffset( container, true );
			container.scrolloffset = Coordinates.scrollOffset(container);
			container = container.nextContainer;
		}
		
		// item starts out over current parent
		// Replaced with preDragStart function;
		this.sourceParent = this.parentNode;
                this.sourceNextSibling = this.nextSibling;

		this.parentNode.onDragOver(this);
		this.isOutside = false;
	},

	compareClasses : function(droplist, classname) {
		// Check if we have a droplist. A container without a droplist accepts everything you drop on it.
		if (droplist && (droplist.length > 0)) {
			for (i in droplist) {
				if (DragDrop.classMatch(classname, droplist[i])) {
					return true;
				}
			}
			return false;
		}
		return true;
	},

	classMatch : function(classlist, classname) {
		if (classlist && classname) {
			if (classlist.match(new RegExp("\\b" + classname + "\\b"))) {
				return true;
			}
		}
		return false;
	},

	onDrag : function(nwPosition, sePosition, nwOffset, seOffset, scrollOffset, mouse) {
//		window.status = this.parentNode.id;

		var container = DragDrop.firstContainer;
		var targetcontainer;
		while (container != null) {
//			if (mouse.originside( container.northwest, container.southeast )) {
			if (mouse.inside( container.northwest, container.southeast, container.scrolloffset )) {

				if (targetcontainer) {
					// If the new targetcontainer has a higher zIndex, it has priority
					if (targetcontainer.style.zindex > container.style.zindex) {

	                                        if (container.acceptCheck(this)) {
        	                                        targetcontainer = container;
                	                        }

					}
				} else {
					if (container.acceptCheck(this)) {
						targetcontainer = container;
					}
				}
			}
			container = container.nextContainer;
		}

		if (targetcontainer) {
			// We have a targetcontainer
			if (this.isOutside) {
				// We're coming from nowhere

				if (this.parentNode) {
					var tempParent = this.parentNode;
					tempParent.removeChild( this );
					tempParent.parentNode.removeChild( tempParent );
				}
				targetcontainer.appendChild( this );
				this.isOutside = false;
				targetcontainer.onDragOver(this);
			} else {
				if (this.parentNode) {
					if (this.parentNode != targetcontainer) {
						// We're coming from another container
						this.parentNode.removeChild( this );

						if (this.parentNode == this.sourceParent) {
							this.parentNode.onDragOut(this);
						}

						targetcontainer.appendChild( this );
						this.isOutside = false;
						targetcontainer.onDragOver(this);
					}
				}
			}
		} else {
			if (! this.isOutside) {
				// We are nowhere now, but we used to be somewhere
				// Move the item to a temporary container
				this.isOutside = true;

				var tempParent = this.parentNode.cloneNode( false );

				tempParent.style.backgroundColor = "transparent";
				tempParent.style.border = "none";

				var origParent = this.parentNode;

				origParent.removeChild( this );
				origParent.onDragOut(this);

				tempParent.appendChild( this );
				if (origParent.parentNode) {
					origParent.parentNode.appendChild(tempParent);
				} else {
					document.getElementsByTagName( "body" ).item(0).appendChild( tempParent );
				}
				tempParent.style.position = "relative";
			}
			return;
		}

		// if we get here, we're inside some container bounds, so we do
		// everything the original dragsort script did to swap us into the
		// correct position
		if (! this.isOutside) {
			this.parentNode.SwapIn(this);
		}
		return;
	},

	SwapIn : function(item) {
		var parent = this;
		var swapitem = item;
	
		var next = DragUtils.nextItem(swapitem);
		while (next != null && item.offsetTop >= next.offsetTop - 2) {
			var swapitem = next;
			var next = DragUtils.nextItem(swapitem);
		}
		if (item != swapitem) {
			DragUtils.swap(item, next);
			return;
		}
		
		var swapitem = item;
		var previous = DragUtils.previousItem(swapitem);
		while (previous != null && item.offsetTop <= previous.offsetTop + 2) {
			var swapitem = previous;
			var previous = DragUtils.previousItem(swapitem);
		}
		if (item != swapitem) {
			DragUtils.swap(item, swapitem);
			return;
		}
	},

	onDragEnd : function(nwPosition, sePosition, nwOffset, seOffset, scrollOffset) {
		// if the drag ends and we're still outside all containers
		// it's time to remove ourselves from the document
		if (this.isOutside) {
			var tempParent = this.parentNode;
			this.parentNode.removeChild( this );
			tempParent.parentNode.removeChild( tempParent );

			// If this item was copied and it is nowhere, destroy it.
			// otherwise, snap ik back to the original position.

                        // FIXME: the snap back should put the item back in
                        // the original position instead of appending it
                        // back to the parent.

			if (this.copy) {
				this.copy = false;
				return;
			} else {
				if (this.sourceNextSibling && this.sourceNextSibling.parentNode == this.sourceParent) {
					this.sourceParent.insertBefore(this, this.sourceNextSibling);
				} else {
					this.sourceParent.appendChild( this );
				}

				// FIXME: decide if a snap back is a onDragDrop event
				this.sourceParent.onSnapBack(this);
			}
		} else {
			// FIXME: what if we came from this parent?
/*			if (this.parentNode == this.sourceParent) {
                                if (this.sourceNextSibling && this.sourceNextSibling.parentNode == this.sourceParent) {
                                        this.sourceParent.insertBefore(this, this.sourceNextSibling);
                                } else {
                                        this.sourceParent.appendChild( this );
                                }
                                this.sourceParent.onSnapBack(this);
			} else {
*/
				this.parentNode.onDragDrop(this);
//			}
		}
		this.style["top"] = "0px";
		this.style["left"] = "0px";
	}
};

var DragUtils = {
	swap : function(item1, item2) {
		var parent = item1.parentNode;

		parent.removeChild(item1);
		parent.insertBefore(item1, item2);

		item1.style["top"] = "0px";
		item1.style["left"] = "0px";
	},

	nextItem : function(item) {
		var sibling = item.nextSibling;
		while (sibling != null) {
			if (sibling.nodeName == item.nodeName) return sibling;
			sibling = sibling.nextSibling;
		}
		return null;
	},

	previousItem : function(item) {
		var sibling = item.previousSibling;
		while (sibling != null) {
			if (sibling.nodeName == item.nodeName) return sibling;
			sibling = sibling.previousSibling;
		}
		return null;
	}		
};
/**********************************************************
 Very minorly modified from the example by Tim Taylor
 http://tool-man.org/examples/sorting.html
 
 Added Coordinate.prototype.inside( northwest, southeast );
 
 **********************************************************/

var Coordinates = {
	ORIGIN : new Coordinate(0, 0),

	northwestPosition : function(element) {
		var x = parseInt(element.style.left);
		var y = parseInt(element.style.top);

		return new Coordinate(isNaN(x) ? 0 : x, isNaN(y) ? 0 : y);
	},

	southeastPosition : function(element) {
		return Coordinates.northwestPosition(element).plus(
				new Coordinate(element.offsetWidth, element.offsetHeight));
	},

	northwestOffset : function(element, isRecursive) {
		var offset = new Coordinate(element.offsetLeft, element.offsetTop);

		if (!isRecursive) return offset;

		var parent = element.offsetParent;
		while (parent) {
			offset = offset.plus(
					new Coordinate(parent.offsetLeft, parent.offsetTop));
			parent = parent.offsetParent;
		}
		return offset;
	},

	southeastOffset : function(element, isRecursive) {
		return Coordinates.northwestOffset(element, isRecursive).plus(
				new Coordinate(element.offsetWidth, element.offsetHeight));
	},

        scrollOffset : function(element) {
                var offset = new Coordinate(element.parentNode.scrollLeft, element.parentNode.scrollTop);

                var parent = element.parentNode;
                while (parent && parent.parentNode && typeof(parent.parentNode.scrollLeft) == 'number') {
                        offset = offset.plus(
                                new Coordinate(parent.parentNode.scrollLeft, parent.parentNode.scrollTop)
                        );
                        parent = parent.parentNode;
                }

                return offset;
        },

	getOffsets : function(element, isRecursive) {
		var nwOffset = new Coordinate(element.offsetLeft, element.offsetTop);
		var scrOffset = new Coordinate(0,0);

		if (element.offsetParent && typeof(element.offsetParent.scrollLeft) == 'number') {
			scrOffset = new Coordinate(element.offsetParent.scrollLeft, element.offsetParent.scrollTop);
		}
		
		if (!isRecursive) {
			var seOffset = nwOffset.plus(new Coordinate(element.offsetWidth, element.offsetHeight));
			return Array(nwOffset, seOffset, scrOffset);
		}
		var parent = element.offsetParent;
		while (parent) {
			nwOffset = nwOffset.plus(new Coordinate(parent.offsetLeft, parent.offsetTop));
			if (parent.offsetParent && typeof(parent.offsetParent.scrollLeft) == 'number') {
				scrOffset = scrOffset.plus(new Coordinate(parent.offsetParent.scrollLeft, parent.offsetParent.scrollTop));
			}
			parent = parent.offsetParent;
		}
		
		var seOffset = nwOffset.plus(new Coordinate(element.offsetWidth, element.offsetHeight));
		return Array(nwOffset, seOffset, scrOffset);
	},

	fixEvent : function(event) {
		event.windowCoordinate = new Coordinate(event.clientX, event.clientY);
	}
};

function Coordinate(x, y) {
	this.x = x;
	this.y = y;
}

Coordinate.prototype.toString = function() {
	return "(" + this.x + "," + this.y + ")";
}

Coordinate.prototype.plus = function(that) {
	return new Coordinate(this.x + that.x, this.y + that.y);
}

Coordinate.prototype.minus = function(that) {
	return new Coordinate(this.x - that.x, this.y - that.y);
}

Coordinate.prototype.distance = function(that) {
	var deltaX = this.x - that.x;
	var deltaY = this.y - that.y;

	return Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));
}

Coordinate.prototype.max = function(that) {
	var x = Math.max(this.x, that.x);
	var y = Math.max(this.y, that.y);
	return new Coordinate(x, y);
}

Coordinate.prototype.constrain = function(min, max) {
	if (min.x > max.x || min.y > max.y) return this;

	var x = this.x;
	var y = this.y;

	if (min.x != null) x = Math.max(x, min.x);
	if (max.x != null) x = Math.min(x, max.x);
	if (min.y != null) y = Math.max(y, min.y);
	if (max.y != null) y = Math.min(y, max.y);

	return new Coordinate(x, y);
}

Coordinate.prototype.reposition = function(element) {
//	alert(element.style["top"] + ":" + element.style["left"] + " => " + this.y + ":" + this.x);
	element.style["top"] = this.y + "px";
	element.style["left"] = this.x + "px";
}

Coordinate.prototype.equals = function(that) {
	if (this == that) return true;
	if (!that || that == null) return false;

	return this.x == that.x && this.y == that.y;
}

// returns true of this point is inside specified box
Coordinate.prototype.inside = function(northwest, southeast, scrolloffset) {
//	if ((this.x >= northwest.x) && (this.x <= southeast.x) &&
//		(this.y >= northwest.y) && (this.y <= southeast.y)) {
//		
//		return true;
//	}

	if ((this.x >= northwest.x - scrolloffset.x) && (this.x <= southeast.x - scrolloffset.x) &&
		(this.y >= northwest.y - scrolloffset.y) && (this.y <= southeast.y - scrolloffset.y)) {
		return true;
	}

	return false;
}

Coordinate.prototype.originside = function(northwest, southeast) {
	if ((this.x >= northwest.x) && (this.x <= southeast.x) &&
		(this.y >= northwest.y) && (this.y <= southeast.y)) {
		return true;
	}
	return false;
}
var hiderdivs = {
	// Hider divs library. Creates divs on the screen to give a "disabled" effect. Cancels all mouse clicks for whatever part of the screen is not active.
	
	hiderdivs : new Array(5),
	hidden : false,
	hiddendiv : null,

	setOpacity : function (object, opacity) {
		if (opacity >= 1) {
			opacity = 1;
		}
		if (opacity < 0) {
			opacity = 0;
		}

		object.style.filter = "alpha(opacity=" + (opacity*100) + ")";
		object.style.MozOpacity = opacity;
		object.style.KHTMLOpacity = opacity;
		object.style.opacity = opacity;
	},

	makeHiderDivs : function(object) {
		if (hiderdivs.hidden) {
			hiderdivs.removeHiderDivs();
		}

		hiderdivs.hidden = true;
		hiderdivs.hiddendiv = object;

   		// This function creates 4 divs that surround a given object like this:
   		// +-----------+
   		// |   top     |
   		// +--+-----+--+
   		// |l |     |r |
   		// |e |     |i |
   		// |f | obj |g |   
   		// |t |     |h |
   		// |  |     |t |   
   		// +--+-----+--+
   		// |  bottom   |
   		// +-----------+
   		//
   		//
   
		for (i=0; i<hiderdivs.hiderdivs.length; i++) {
			hiderdivs.hiderdivs[i] = document.createElement("div");
			hiderdivs.hiderdivs[i].style.position = "absolute";
			hiderdivs.hiderdivs[i].style.backgroundColor = "#888888";

			var iframe = document.createElement("IFRAME");
			iframe.src="http://nieuws.overijssel.nl/blank.html";
			iframe.frameBorder = "0";
			iframe.style.border = "none";
			iframe.style.width="100%";
			iframe.style.height="100%";
			hiderdivs.setOpacity(iframe, 0);
			hiderdivs.hiderdivs[i].appendChild(iframe);

			hiderdivs.hiderdivs[i].style.position = "absolute";
			hiderdivs.hiderdivs[i].style.zIndex = 100;
			hiderdivs.setOpacity(hiderdivs.hiderdivs[i], 0.5);
			hiderdivs.hiderdivs[i].onClick = function() {
				Event.cancelBubble = true;
				return false;
      			}
			document.body.appendChild(hiderdivs.hiderdivs[i]);
		}

		selected_left = Coordinates.northwestOffset(object, true).x;
		selected_top = Coordinates.northwestOffset(object, true).y;
		selected_height = parseInt(object.offsetHeight);
		selected_width = parseInt(object.offsetWidth);
		selected_right = selected_left + selected_width;
		selected_bottom = selected_top + selected_height;

		var divtop = hiderdivs.hiderdivs[0];
		var divleft = hiderdivs.hiderdivs[1];
		var divright = hiderdivs.hiderdivs[2];
		var divbottom = hiderdivs.hiderdivs[3];
		var divall = hiderdivs.hiderdivs[4];

		divall.style.top = "0px";
		divall.style.left = "0px";
		divall.style.height = "100%";
		divall.style.width = "100%";
		divall.style.visibility = "hidden";

		divtop.style.top = "0px";
		divtop.style.left = "0px";
		divtop.style.height = selected_top + "px";
		divtop.style.width = (document.body.clientWidth) + "px"; //"100%"; //document.body.offsetWidth + "px";
		divtop.style.overflow = "hidden";

		divleft.style.top = selected_top + "px";
		divleft.style.left = "0px";
		divleft.style.height = selected_height + "px";
		divleft.style.width = selected_left + "px";
		divleft.style.overflow = "hidden";
   
		var rightheight = document.body.clientHeight - (selected_right);
		if (rightheight < 0) {
			rightheight = 0;
		}
		divright.style.top = selected_top + "px";
		divright.style.left = selected_right + "px";
		divright.style.height = selected_height + "px";
		divright.style.width = (document.body.clientWidth - (selected_right)) + "px";
		divright.style.overflow = "hidden";

		var bottomheight = divall.offsetHeight - (selected_bottom);
		if (bottomheight < 0) {
			bottomheight = 0;
		}
		divbottom.style.top = selected_bottom + "px";
		divbottom.style.left = "0px";
		divbottom.style.height = bottomheight + "px";
		divbottom.style.width = (document.body.clientWidth) + "px"; //"100%"; //(document.body.offsetWidth) + "px";
		divbottom.style.overflow = "hidden";

		if (parseInt(divtop.style.height) == 0) {
			divtop.style.display = "none";
		}
		if (parseInt(divbottom.style.height) == 0) {
			divbottom.style.display = "none";
		}
		if (parseInt(divleft.style.width) == 0) {
			divleft.style.display = "none";
		}
		if (parseInt(divright.style.width) == 0) {
			divright.style.display = "none";
		}

	},

	purge : function(d) {
		var a = d.attributes, i, l, n;
		if (a) {
			l = a.length;
			for (i = 0; i < l; i += 1) {
				n = a[i].name;
				if (typeof d[n] === 'function') {
					d[n] = null;
				}
			}
		}
		a = d.childNodes;
		if (a) {
			l = a.length; 
			for (i = 0; i < l; i += 1) {
				hiderdivs.purge(d.childNodes[i]);
			}
		}
	},

	removeHiderDivs : function() {
		if (hiderdivs.hidden) {
			for (hiderdiv in hiderdivs.hiderdivs) {
				hiderdivs.purge(hiderdivs.hiderdivs[hiderdiv]);
				document.body.removeChild(hiderdivs.hiderdivs[hiderdiv]);
			}
			hiderdivs.hidden = false;
		}
	}
}

/*********************
outputBuffer.js

Creates an output buffer to capture document.writeln and document.write into a string.

Written by Yvo Brevoort, june 2006.
Copyright Muze 2006.
*********************/

/*
	Description:
	This script works by storing the original document.write() and document.writeln() functions, and replacing them with capture functions.
	
	Methods:
	outputBuffer.start();
		Empties the current buffer, and replaces the write() and writeln() functions with the capture functions.
	
	outputBuffer.end();
		Restores the original write() and writeln() functions. The buffer will still be available after this call.
		Removes the RegExp (if any) used in matchEntry.
		
	outputBuffer.getContents();
		Returns the current output buffer. This can be called before the outputBuffer is stopped.

	outputBuffer.matchEntry(entry, handler);
		Executes handler when the content added to the outputbuffer matches entry (using RegExp). 
		This can be used for example to add a match to the last line expected, and trigger something.

*/

var outputBuffer = {
	buffer : null,
	origwriteln : document.writeln,	
	origwrite : document.write,
	matchEntryReg : null,
	matchEntryHandler : null,
	currentLine : null,
	start : function() {
		outputBuffer.buffer = "";

		document.writeln = function(content) {
			// Check if the entry matches the one we think comes last.
			if (outputBuffer.matchEntryReg != null) {
				if (content.match(outputBuffer.matchEntryReg)) {
					if (outputBuffer.matchEntryHandler(content)) {
						outputBuffer.buffer += content + "\n";
					}
				} else {
					outputBuffer.buffer += content + "\n";
				}
			} else {
				outputBuffer.buffer += content + "\n";
			}
		}

		document.write = function(content) {
			outputBuffer.buffer += content;
		}
	},
	matchEntry : function(entry, fh) {
		outputBuffer.matchEntryReg = new RegExp(entry);
		outputBuffer.matchEntryHandler = fh;
	},
	end : function() {
		document.writeln = outputBuffer.origwriteln;
		document.write = outputBuffer.origwrite;
		matchEntryReg = null;
		matchEntryHandler = null;
	},
	getContents : function() {
		return outputBuffer.buffer;
	}
};