/*
**
** File 'functions.utf8.js'
**
*/
ï»¿/////////////////////////////////////////////////////////////////////////////////////////////////////////
self.onError=null;

var clientPC = navigator.userAgent.toLowerCase(); // Get client info
var clientVer = parseInt(navigator.appVersion); // Get browser version

  // *** BROWSER VERSION ***
// Note: On IE5, these return 4, so use is_ie5up to detect IE5.
var is_major = parseInt(navigator.appVersion);
var is_minor = parseFloat(navigator.appVersion);

var is_ie = ((clientPC.indexOf("msie") != -1) && (clientPC.indexOf("opera") == -1));
var is_nav = ((clientPC.indexOf('mozilla')!=-1) && (clientPC.indexOf('spoofer')==-1)  && (clientPC.indexOf('compatible') == -1) && (clientPC.indexOf('opera')==-1)  && (clientPC.indexOf('webtv')==-1) && (clientPC.indexOf('hotjava')==-1));
var is_moz = 0;
var is_win = ((clientPC.indexOf("win")!=-1) || (clientPC.indexOf("16bit") != -1));
var is_mac = (clientPC.indexOf("mac")!=-1);
var NS = (document.layers) ? 1 : 0;
var IE = (document.all) ? 1: 0;

var is_ie3    = (is_ie && (is_major < 4));
var is_ie4    = (is_ie && (is_major == 4) && (clientPC.indexOf("msie 4")!=-1) );
var is_ie4up  = (is_ie && (is_major >= 4));
var is_ie5    = (is_ie && (is_major == 4) && (clientPC.indexOf("msie 5.0")!=-1) );
var is_ie5_5  = (is_ie && (is_major == 4) && (clientPC.indexOf("msie 5.5") !=-1));
var is_ie5up  = (is_ie && !is_ie3 && !is_ie4);
var is_ie5_5up =(is_ie && !is_ie3 && !is_ie4 && !is_ie5);
var is_ie6    = (is_ie && (is_major == 4) && (clientPC.indexOf("msie 6.")!=-1) );
var is_ie6up  = (is_ie && !is_ie3 && !is_ie4 && !is_ie5 && !is_ie5_5);

var Browser = {};
var ua = navigator.userAgent.toLowerCase();
Browser.isMozilla = (typeof document.implementation != 'undefined') && (typeof document.implementation.createDocument != 'undefined') && (typeof HTMLDocument!='undefined');
Browser.isIE = window.ActiveXObject ? true : false;
Browser.isFirefox = (ua.indexOf("firefox")!=-1);
Browser.isSafari = (ua.indexOf("safari")!=-1);
Browser.isOpera = (typeof window.opera != 'undefined'); 
	

var keine_action = 1;
var alle_action = 2;

var now = new Date();
var start_time = now.getTime();
var show_session_layer = false;

var currentX = 0;
var currentY = 0;  
var whichIt = null;           
var lastScrollX = 0; 
var lastScrollY = 0;

/////////////////////////////////////////////////////////////////////////////////////////////////////////

function setCssClass (element, classname) {
	element.setAttribute('class',classname);
	element.setAttribute('className',classname); // IE6 is now our friend!
}

function addOnErrorEvent (fnc) {
  if ( typeof window.addEventListener != "undefined" )
    window.addEventListener( "error", fnc, false );
  else if ( typeof window.attachEvent != "undefined" ) {
    window.attachEvent( "onerror", fnc );
  }
  else {
    if ( window.onerror != null ) {
      var oldOnerror = window.onerror;
      window.onerror = function ( e ) {
        oldOnerror( e );
        window[fnc]();
      };
    }
    else
      window.onerror = fnc;
  }
}

function addEventHandler(element, type, handler) {
    try {
        element.addEventListener(type, handler, false);
    } catch(inferiorBrowserException) {
        if(element.attachEvent) 
            element.attachEvent('on'+type, handler);
        else 
            element['on'+type] = handler;
    }
    return [element, type, handler];
}

/* does not work in Safari */
if (window.addEventListener) {
	window.addEventListener("error", (function () {return null;}), false);
} else if (window.attachEvent) {
	window.attachEvent("onerror", (function () {return null;}));
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
function sliding(element_name) {
	if(IE) { diffY = document.body.scrollTop+120; diffX = document.body.scrollLeft; }
	if(NS) { diffY = self.pageYOffset; diffX = self.pageXOffset; }

	if(diffY != lastScrollY) {
		percent = .1 * (diffY - lastScrollY);
		if(percent > 0) percent = Math.ceil(percent);
		else percent = Math.floor(percent);

		if(IE) document.getElementById(element_name).style.pixelTop += percent;
		if(NS) document.getElementById(element_name).top += percent; 

		lastScrollY = lastScrollY + percent;
	}
	if(diffX != lastScrollX) {
		percent = .1 * (diffX - lastScrollX);
		if(percent > 0) percent = Math.ceil(percent);
		else percent = Math.floor(percent);
		if(IE) getElementById(element_name).style.pixelLeft += percent;
		if(NS) document.getElementById(element_name).left += percent;
		lastScrollX = lastScrollX + percent;
	}       
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
function getActiveText (selectedtext) { 
	text = (document.all) ? document.selection.createRange().text : document.getSelection();
	if (selectedtext.createTextRange) selectedtext.caretPos = document.selection.createRange().duplicate();
	return true;
}
//////////////////////////////////////////////////////////////////////////////////////////////////
function fenster (seite) {
	neu4 = window.open(seite,"preview","toolbar=no,width=500,height=550,scrollbars=yes,directories=no,menubar=no,screenx=1,screeny=1,pageXOffset=1,pageYOffset=1");
	neu4.focus();
}
//////////////////////////////////////////////////////////////////////////////////////////////////
function popup (seite) {
	neu4 = window.open(seite,"preview","toolbar=no,width=500,height=550,scrollbars=no,directories=no,menubar=no,screenx=1,screeny=1,pageXOffset=1,pageYOffset=1");
	neu4.focus();
}
//////////////////////////////////////////////////////////////////////////////////////////////////
function popup2 (seite,breite,hoehe) {
	neu4 = window.open(seite,"","toolbar=no,width="+breite+",height="+hoehe+",scrollbars=no,directories=no,menubar=no,screenx=1,screeny=1,pageXOffset=1,pageYOffset=1");
	neu4.focus();
}
//////////////////////////////////////////////////////////////////////////////////////////////////
function fenster_new (seite) {
	neu4 = window.open(seite,"preview","toolbar=yes,resizable=yes,width=600,height=500,scrollbars=yes,directories=yes,menubar=yes,screenx=1,screeny=1,pageXOffset=1,pageYOffset=1");
	neu4.focus();
}
//////////////////////////////////////////////////////////////////////////////////////////////////
function fenster2 (seite, breite, hoehe, id) {
	window.open(seite, id,"width=" +breite +",height=" +hoehe + ",resizable=no,location=no,status=no,toolbar=no,scrollbars=no,directories=no,menubar=no,screenx=1,screeny=1,pageXOffset=10,pageYOffset=10");
}

//////////////////////////////////////////////////////////////////////////////////////////////////
function fenster3 (seite, breite, hoehe, id) {
	window.open(seite, id,"width=" +breite +",height=" +hoehe + ",resizable=no,location=no,status=no,toolbar=no,scrollbars=no,directories=no,menubar=no,screenx=1,screeny=1,pageXOffset=10,pageYOffset=10");
//	neu=window.open("seite", id,"width=" +breite +",height=" +hoehe + ",resizable=no,location=no,status=no,toolbar=no,scrollbars=no,directories=no,menubar=no,screenx=1,screeny=1,pageXOffset=10,pageYOffset=10");
//	neu.document.write('<html><head><\/head><body topmargin="0" leftmargin="0"><img onClick="window.close();" src="'+seite+'"><\/body><\/html>')
//	neu.focus()
}

//////////////////////////////////////////////////////////////////////////////////////////////////
function fenster2_scrollbars (seite, breite, hoehe, id) {
	window.open(seite, id,"width=" +breite +",height=" +hoehe + ",resizable=yes,location=no,status=yes,toolbar=no,scrollbars=yes,directories=no,menubar=no,screenx=1,screeny=1,pageXOffset=1,pageYOffset=1");
}

////////////////////////////////////////////////////////////////////////////////////
function picture (seite, breite, hoehe, id) {
	neu=   window.open(seite, id ,"toolbar=no,width=" +breite +",height=" +hoehe + ",directories=no,status=no,menubar=no,screenx=1,screeny=1,pageXOffset=1,pageYOffset=1");
	neu.focus();
}

////////////////////////////////////////////////////////////////////////////////////
function image_link (start, image, breite, hoehe, id) {
	var string = "javascript: picture ('/index.php?action=" + start + "&image=" + image + "','" + breite +"','" + hoehe + "'," + id + ");"; 
	return string
}
////////////////////////////////////////////////////////////////////////////////////
function print_page (seite) {
	neu1=   window.open(seite, "Druckversion" ,"width=545,height=600,left=0,top=0,toolbar=yes,scrollbars=yes");
	neu1.focus();
}

////////////////////////////////////////////////////////////////////////////////////
function xml (seite) {
	neu2=   window.open(seite, "XMLVersion" ,"width=545,height=600,left=0,top=0,menubar=yes,toolbar=no,scrollbars=yes");
	neu2.focus();
}

////////////////////////////////////////////////////////////////////////////////////
function details (seite,id) {
	if (id != "") {
		neu3=   window.open(seite + "&idtoedit=" + id, "Details" ,"width=545,height=600,left=0,top=0,toolbar=yes,scrollbars=yes");
		neu3.focus();
	}
}
////////////////////////////////////////////////////////////////////////////////////
function GO (target) {
    if (target != "nix") {
    	self.location.href = target;
   }
}

////////////////////////////////////////////////////////////////////////////////////
function ListOption(content, id) {
	this.content = content;
	this.id = id;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
function AddText(NewCode,formName,fieldName) {
	var txtarea = document.forms[formName].elements[fieldName];
	
	if ((clientVer >= 4) && is_ie && is_win)	{
		var d = (document.forms ? document.forms[formName] : null);
		var e = (d && d.elements ? d.elements[fieldName] : null);
	   	if (e.createTextRange && e.caretPos) {
			var caretPos = e.caretPos;
			caretPos.text = caretPos.text.charAt(caretPos.text.length - 1) == ' ' ? NewCode + ' ' : NewCode;
		} else {
			e.value+=NewCode
		}
		txtarea.focus();
		text = '';
	} else {
		txtarea.value += NewCode;
	}
	getActiveText (txtarea);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
function markSelection (start_tag, stop_tag, element, formName, fieldName){
	var temp = "..." + stop_tag;  
	var val = start_tag;
	val += (stop_tag ? temp  : "");
	if (text)    {
    	val = start_tag + text +  stop_tag;
    }		
	AddText(val , formName, fieldName);
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
function SetActionValue (formName, fieldName, valueAssign) {
	document.forms[formName].elements[fieldName].value=valueAssign;
	document.forms[formName].submit();
	return true;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
function MM_preloadImages() { //v3.0
  var d=document; if(d.images){ if(!d.MM_p) d.MM_p=new Array();
    var i,j=d.MM_p.length,a=MM_preloadImages.arguments; for(i=0; i<a.length; i++)
    if (a[i].indexOf("#")!=0){ d.MM_p[j]=new Image; d.MM_p[j++].src=a[i];}}
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
function MM_swapImgRestore() { //v3.0
  var i,x,a=document.MM_sr; for(i=0;a&&i<a.length&&(x=a[i])&&x.oSrc;i++) x.src=x.oSrc;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
function MM_findObj(n, d) { //v4.01
  var p,i,x;  if(!d) d=document; if((p=n.indexOf("?"))>0&&parent.frames.length) {
    d=parent.frames[n.substring(p+1)].document; n=n.substring(0,p);}
  if(!(x=d[n])&&d.all) x=d.all[n]; for (i=0;!x&&i<d.forms.length;i++) x=d.forms[i][n];
  for(i=0;!x&&d.layers&&i<d.layers.length;i++) x=MM_findObj(n,d.layers[i].document);
  if(!x && d.getElementById) x=d.getElementById(n); return x;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
function MM_swapImage() { //v3.0
  var i,j=0,x,a=MM_swapImage.arguments; document.MM_sr=new Array; for(i=0;i<(a.length-2);i+=3)
   if ((x=MM_findObj(a[i]))!=null){document.MM_sr[j++]=x; if(!x.oSrc) x.oSrc=x.src; x.src=a[i+2];}
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
function MM_showHideLayers() { //v3.0
  var i,p,v,obj,args=MM_showHideLayers.arguments;
  for (i=0; i<(args.length-2); i+=3) if ((obj=MM_findObj(args[i]))!=null) { v=args[i+2];
    if (obj.style) { obj=obj.style; v=(v=='show')?'visible':(v='hide')?'hidden':v; }
    obj.visibility=v; }
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
function switch_layer(listID) { 
 if(listID.style.display=="none") { 
 	listID.style.display=""; 
 } else { 
 	listID.style.display="none"; 
 } 
} 

/////////////////////////////////////////////////////////////////////////////////////////////////////////
function backendSwitch () {
	switch_layer(document.getElementById('extended_footer_layer'));
	switch_layer(document.getElementById('admin_tree_layer'));
	switch_layer(document.getElementById('arrow_down'));
	switch_layer(document.getElementById('arrow_up'));
}


/////////////////////////////////////////////////////////////////////////////////////////////////////////
function treeSwitch () {
	switch_layer(document.getElementById('admin_tree'));
	switch_layer(document.getElementById('options_tree'));
	switch_layer(document.getElementById('admin_tree_icon'));
	switch_layer(document.getElementById('options_tree_icon'));
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
function auctionSwitch () {
	switch_layer(document.getElementById('teaser_layer'));
	switch_layer(document.getElementById('info_layer'));
	switch_layer(document.getElementById('flash_layer'));
	switch_layer(document.getElementById('phone_layer'));
	switch_layer(document.getElementById('button_layer'));
	switch_layer(document.getElementById('back_layer'));
	}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
function refreshDoc () {
	location.reload();
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
function expandTree () {
	switch_layer(document.getElementById('tree_down'));
	switch_layer(document.getElementById('tree_up'));
	expand_all();
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
function handleLoading () {
	switch_layer(document.getElementById('loading_message'));
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
function colapseTree () {
	switch_layer(document.getElementById('tree_down'));
	switch_layer(document.getElementById('tree_up'));
	collapse_all();
}


/////////////////////////////////////////////////////////////////////////////////////////////////////////
function AddParameter (to_add, value, start_string) { 
    var param     = new Array(); 
    var parameter = new Array(); 
    var location  = (start_string ? start_string  :  window.location.search); 
	var return_string = '';
	parameters   = location.substr(1, location.length - 1); 
    i            = -1; 
    x            = parameters.indexOf("&"); 

    while (x != -1) { 
      i++; 
      parameter[i] = parameters.substr(0, x); 
      parameters   = parameters.substr((x+1), parameters.length - (x+1)); 
      x            = parameters.indexOf("&"); 
    } 
    i++; 
    parameter[i] = parameters; 
    for( i=0; i<parameter.length; i++) { 
      x = parameter[i].indexOf("="); 
      if (x != -1) { 
        param['Name'+i] = parameter[i].substr(0, x); 
        param['Wert'+i] = parameter[i].substr((x+1), parameter[i].length - (x+1)); 
      } 
    } 
	for( i=0; i<parameter.length; i++) { 
		if (param['Name'+i] && param['Name'+i] != to_add) { return_string = return_string + '&' + param['Name'+i] + '=' + param['Wert'+i]; }
	} 
	return_string = return_string + '&' + to_add + '=' + value;
	return return_string; 
  } 


/////////////////////////////////////////////////////////////////////////////////////////////////////////
function saveLayer () {
	var string = '';
	var value = '';
	Check = confirm(unescape("M%F6chten Sie die Fenstereinstellungen wirklich speichern?\nBitte speichern Sie vorher Ihre ggf. gemachten %C4nderungen."));
	if (Check == true) {
	  string = window.location.pathname;
	  string = string + '?';
	  value = document.getElementById('admin_tree_layer').style.display;
	  value = value + ";" + document.getElementById('admin_tree').style.display;
	  value = value + ";" + document.getElementById('tree_up').style.display;
	  location.href= string  + AddParameter("save_layer", value, '');
	   
	}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
function changeParameter (parameter, value) {
	var string = '';
	var addon_string = '';
	string = window.location.pathname;
	string = string + '?';
	addon_string = AddParameter(parameter, value);
	location.href= string  + addon_string;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
function changeLayout (layout) {
	var string = '';
	var addon_string = '';
	string = window.location.pathname;
	string = string + '?';
	addon_string = AddParameter("designName", layout);
	location.href= string  + addon_string;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
function changeLanguage (language) {
	var string = '';
	var addon_string = '';
	string = window.location.pathname;
	string = string + '?';
	addon_string = AddParameter("reinitialize_options_tree", 1);
	addon_string = AddParameter("cache", 0, addon_string);
	addon_string = AddParameter("lang", language, addon_string);
	location.href= string  + addon_string;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
function reInitTree () {
	var string = '';
	var addon_string = '';
	Check = confirm(unescape("M%F6chten Sie die Baumansicht aktualisieren?\nBitte speichern Sie vorher Ihre ggf. gemachten %C4nderungen."));
	if (Check == true) {
		string = window.location.pathname;
	  string = string + '?';
		addon_string = AddParameter("reinitialize_options_tree", 1);
		addon_string = AddParameter("cache", 0, addon_string);
		location.href= string  + addon_string;
	}
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
function exportAccount (id) {
	var string = '';
	Check = confirm(unescape("Bitte beachten Sie, dass sich die Exportfunktion noch in der Entwicklung befindet.\nEs werden noch nicht alle Daten bzw. Module vollst%E4ndig exportiert.\nWollen Sie den Export trotzdem fortsetzen?"));
	if (Check == true) {
		string = "/index.php?action=account_export&account_id=" +id;
		self.location.href= string;
	}
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
function MM_nbGroup(event, grpName) { //v6.0
  var i,img,nbArr,args=MM_nbGroup.arguments;
  if (event == "init" && args.length > 2) {
    if ((img = MM_findObj(args[2])) != null && !img.MM_init) {
      img.MM_init = true; img.MM_up = args[3]; img.MM_dn = img.src;
      if ((nbArr = document[grpName]) == null) nbArr = document[grpName] = new Array();
      nbArr[nbArr.length] = img;
      for (i=4; i < args.length-1; i+=2) if ((img = MM_findObj(args[i])) != null) {
        if (!img.MM_up) img.MM_up = img.src;
        img.src = img.MM_dn = args[i+1];
        nbArr[nbArr.length] = img;
    } }
  } else if (event == "over") {
    document.MM_nbOver = nbArr = new Array();
    for (i=1; i < args.length-1; i+=3) if ((img = MM_findObj(args[i])) != null) {
      if (!img.MM_up) img.MM_up = img.src;
      img.src = (img.MM_dn && args[i+2]) ? args[i+2] : ((args[i+1])? args[i+1] : img.MM_up);
      nbArr[nbArr.length] = img;
    }
  } else if (event == "out" ) {
    for (i=0; i < document.MM_nbOver.length; i++) {
      img = document.MM_nbOver[i]; img.src = (img.MM_dn) ? img.MM_dn : img.MM_up; }
  } else if (event == "down") {
    nbArr = document[grpName];
    if (nbArr)
      for (i=0; i < nbArr.length; i++) { img=nbArr[i]; img.src = img.MM_up; img.MM_dn = 0; }
    document[grpName] = nbArr = new Array();
    for (i=2; i < args.length-1; i+=2) if ((img = MM_findObj(args[i])) != null) {
      if (!img.MM_up) img.MM_up = img.src;
      img.src = img.MM_dn = (args[i+1])? args[i+1] : img.MM_up;
      nbArr[nbArr.length] = img;
  } }
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
function hasOptions(obj) {
	if (obj!=null && obj.options!=null) { return true; }
	return false;
	}

 /////////////////////////////////////////////////////////////////////////////////////////////////////////
function lockOptions (obj) {
	if (!hasOptions(obj)) { return false; }
	for (var i=0; i<obj.options.length; i++) {
		if (obj.options[i].value == keine_action || obj.options[i].value == alle_action) return true;
		}
	}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
function unSelectMatchingOptions(obj,regex) {
	selectUnselectMatchingOptions(obj,regex,"unselect",false);
	}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
function selectUnselectMatchingOptions(obj,regex,which,only) {
	if (window.RegExp) {
		if (which == "select") {
			var selected1=true;
			var selected2=false;
			}
		else if (which == "unselect") {
			var selected1=false;
			var selected2=true;
			}
		else {
			return;
			}
		var re = new RegExp(regex);
		for (var i=0; i<obj.options.length; i++) {
			if (re.test(obj.options[i].text)) {
				obj.options[i].selected = selected1;
				}
			else {
				if (only == true) {
					obj.options[i].selected = selected2;
					}
				}
			}
		}
	}
		
/////////////////////////////////////////////////////////////////////////////////////////////////////////
function sortSelect(obj) {
	var o = new Array();
	if (!hasOptions(obj)) { return; }
	for (var i=0; i<obj.options.length; i++) {
		o[o.length] = new Option( obj.options[i].text, obj.options[i].value, obj.options[i].defaultSelected, obj.options[i].selected) ;
		}
	if (o.length==0) { return; }
	o = o.sort( 
		function(a,b) { 
			if ((a.text+"") < (b.text+"")) { return -1; }
			if ((a.text+"") > (b.text+"")) { return 1; }
			return 0;
			} 
		);

	for (var i=0; i<o.length; i++) {
		obj.options[i] = new Option(o[i].text, o[i].value, o[i].defaultSelected, o[i].selected);
		}
	}


function editSelectedOption(from,fieldset,label,edit,labeltext){
	tmp = new String(labeltext)
	label.innerHTML = tmp.replace( /%s/, from.text);
	new Effect.Appear(fieldset);
	$tmp = $('id_hidden_value_' + o.value + '_' + o.text);
	$tmp.setAttribute("text","TEST");
}
	
	
/////////////////////////////////////////////////////////////////////////////////////////////////////////
function moveSelectedOptions(from,to,check,proove,sort) {
	// Unselect matching options, if required
	var selectcount = 0;
    var option_set = 0;
    var lock = false;
    
    if (!hasOptions(from)) { return; }
    for (var i=0; i<from.options.length; i++) {
		var o = from.options[i];
		if (o.selected) { 

            selectcount++; 
            if (o.value == keine_action) option_set =  option_set + 1;
            if (o.value == alle_action) option_set = option_set + 2;
        }
    }
    
    if (proove == 1 && lockOptions(to) && option_set == 0) { return;  }

    if (proove ==1 && option_set > 0) {
         moveAllOptions (to, from);
        if (option_set > 1) {
            setSelectOptionsbyObj (from, alle_action, true);
        } else {
            setSelectOptionsbyObj (from, keine_action, true);
        }
    } 

	// Maximum exeeded ?
	if (check > 0 && (to.length >= check || ((selectcount+to.length) > check))) { return; }
	
	// Move them over
	for (var i=0; i<from.options.length; i++) {
		var o = from.options[i];
		if (o.selected) {
	        if (!hasOptions(to)) { var index = 0; } else { var index=to.options.length; }
			to.options[index] = new Option( o.text, o.value, false, false);
			}
		}

	// Delete them from original
	for (var i=(from.options.length-1); i>=0; i--) {
		var o = from.options[i];
		if (o.selected) {
			from.options[i] = null;
			}
		}

	if (sort == 1) {
		sortSelect(from);
		sortSelect(to);
	}
	from.selectedIndex = -1;
	to.selectedIndex = -1;
	}
	
	
/////////////////////////////////////////////////////////////////////////////////////////////////////////
function moveSelectedOptionsAJAX(from,to,check,proove,sort,form) {
	// Unselect matching options, if required
	
	var selectcount = 0;
    var option_set = 0;
    var lock = false;
    
    if (!hasOptions(from)) { return; }
    for (var i=0; i<from.options.length; i++) {
		var o = from.options[i];
		if (o.selected) { 

			var tmp = document.createElement("hidden");
			tmp.className = 'hidden_value_' + o.value + '_' + o.text;
			tmp.setAttribute('id','id_'+tmp.className);
			
            selectcount++; 
            if (o.value == keine_action) option_set =  option_set + 1;
            if (o.value == alle_action) option_set = option_set + 2;
        }
    }
    
    if (proove == 1 && lockOptions(to) && option_set == 0) { return;  }

    if (proove ==1 && option_set > 0) {
         moveAllOptions (to, from);
        if (option_set > 1) {
            setSelectOptionsbyObj (from, alle_action, true);
        } else {
            setSelectOptionsbyObj (from, keine_action, true);
        }
    } 

	// Maximum exeeded ?
	if (check > 0 && (to.length >= check || ((selectcount+to.length) > check))) { return; }
	
	// Move them over
	for (var i=0; i<from.options.length; i++) {
		var o = from.options[i];
		if (o.selected) {
	        if (!hasOptions(to)) { var index = 0; } else { var index=to.options.length; }
			to.options[index] = new Option( o.text, o.value, false, false);
			}
		}

	// Delete them from original
	for (var i=(from.options.length-1); i>=0; i--) {
		var o = from.options[i];
		if (o.selected) {
			from.options[i] = null;
			}
		}

	if (sort == 1) {
		sortSelect(from);
		sortSelect(to);
	}
	from.selectedIndex = -1;
	to.selectedIndex = -1;
	}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
function moveAllOptions(from,to) {
	selectAllOptions(from);
	moveSelectedOptions(from,to);
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
function copySelectedOptions(from,to,check,proove,sort,count) {
	if (!this.hasOptions(from)) { return false; }
	var options = new Object();
	
	// Maximum exeeded ?
	if (check > 0 && (to.length >= check || ((selectcount+to.length) > check))) { return; }

	for (var i=0; i<from.options.length; i++) {
		var o = from.options[i];
		if (o.selected) {
			if (typeof(options[o.value])=="undefined" || options[o.value]==null || options[o.value]!=o.text) {
				if (!this.hasOptions(to)) { 
					var index = 0; 
				} 
				else { 
					var index=to.options.length; 
				}
				if (count > 1) {
					for(var j=0; j<count; j++)
					to.options[index++] = new Option( o.text, o.value, false, false);
				} 
				else if (count == 1) {
					to.options[index] = new Option( o.text, o.value, false, false);
				}
				else {
					to.options[index] = new Option( o.text, o.value, false, false);
				}
			}
		}
	}

	from.selectedIndex = -1;
	to.selectedIndex = -1;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
function removeSelectedOptions(from) { 
	if (!hasOptions(from)) { return; }
	if (from.type=="select-one") {
		from.options[from.selectedIndex] = null;
		}
	else {
		for (var i=(from.options.length-1); i>=0; i--) { 
			var o=from.options[i]; 
			if (o.selected) { 
				from.options[i] = null; 
				} 
			}
		}
	from.selectedIndex = -1; 
} 

/////////////////////////////////////////////////////////////////////////////////////////////////////////
function setSelectOptions(the_form, the_select, do_check) {
    var selectObject = document.forms[the_form].elements[the_select];
    var selectCount  = selectObject.length;
    for (var i = 0; i < selectCount; i++) {
        selectObject.options[i].selected = do_check;
    } // end for
    return true;
} 

/////////////////////////////////////////////////////////////////////////////////////////////////////////
function setSelectOptionbyId(the_form, the_select, option_number) {
	if (option_number > 0) option_number = option_number-1; 
    var selectObject = document.forms[the_form].elements[the_select];
	selectObject.options[option_number].selected = true;
	return true;
} 

/////////////////////////////////////////////////////////////////////////////////////////////////////////
function setSelectOptionsbyObj ( obj, the_select, do_check) {
     for (var i=0; i < obj.options.length; i++) {
		var o = obj.options[i];
		if (o.value == the_select) {
            o.selected = do_check;
        } else {
              o.selected = false;
        }
    }
    return true;
} 

/////////////////////////////////////////////////////////////////////////////////////////////////////////
function moveOptionUp(obj) {
	if (!hasOptions(obj)) { return; }
	for (i=0; i<obj.options.length; i++) {
		if (obj.options[i].selected) {
			if (i != 0 && !obj.options[i-1].selected) {
				swapOptions(obj,i,i-1);
				obj.options[i-1].selected = true;
			}
		}
	}
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
function moveOptionDown(obj) {
	if (!hasOptions(obj)) { return; }
	for (i=obj.options.length-1; i>=0; i--) {
		if (obj.options[i].selected) {
			if (i != (obj.options.length-1) && ! obj.options[i+1].selected) {
				swapOptions(obj,i,i+1);
				obj.options[i+1].selected = true;
			}
		}
	}
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
function moveOptionDownAjax(obj) {
	
	if (!hasOptions(obj)) { return; }
	for (i=obj.options.length-1; i>=0; i--) {
		if (obj.options[i].selected) {
			
			if (i != (obj.options.length-1) && ! obj.options[i+1].selected) {
				swapOptions(obj,i,i+1);
				obj.options[i+1].selected = true;
			}
		}
	}
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
function swapOptions(obj,i,j) {
	var o = obj.options;
	var i_selected = o[i].selected;
	var j_selected = o[j].selected;
	var temp = new Option(o[i].text, o[i].value, o[i].defaultSelected, o[i].selected);
	var temp2= new Option(o[j].text, o[j].value, o[j].defaultSelected, o[j].selected);
	o[i] = temp2;
	o[j] = temp;
	o[i].selected = j_selected;
	o[j].selected = i_selected;
}
	
/////////////////////////////////////////////////////////////////////////////////////////////////////////
function timeRedirect (in_time, link) {
	var current_date = new Date();
	var current_time = Math.round((current_date.getTime() - start_time)/1000);
	if (current_time >= (in_time+2)) {
		self.location.href = link;
	}
	window.setTimeout('timeRedirect(' + in_time + ',\'' + link + '\')',1000);
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
function sessionWarning (in_time) {
	var current_date = new Date();
	var current_time = Math.round((current_date.getTime() - start_time)/1000);
	if (current_time >= (in_time-120) && show_session_layer == false) {
		switch_layer(document.getElementById('session_warning'));
		show_session_layer = true;
		if (NS || IE) action = window.setInterval("sliding('session_warning')",50);
	}
	window.setTimeout('sessionWarning(' + in_time + ')',1000);
	
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
function selectAllOptions(obj) {
//alert(obj.name);
	
	if (!hasOptions(obj)) { return; }
	obj.multiple=true;
	for (var i=0; i<obj.options.length; i++) {
		obj.options[i].selected = true;
		
		}
	}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
function Auswahl(form,index) {
      form.options[index].selected = true;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
function updateGame () {
	var string = '';	
	var addon_string = '';
	var selected_value = document.forms["anbieter_search"].search_team.options[document.forms["anbieter_search"].search_team.selectedIndex].value;

	string = window.location.pathname;
	string = string + '?';
	addon_string = AddParameter("game", "0");
	addon_string = AddParameter("team", selected_value, addon_string);
	self.location.href= string  + addon_string;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
function updateGameTime () {
	var string = '';
	var selected_value = document.forms["anbieter_search"].search_game.options[document.forms["anbieter_search"].search_game.selectedIndex].value;
	string = window.location.pathname;
	string = string + '?';
	self.location.href= string  + AddParameter("game", selected_value, '');
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
function updateVariant () {
	var string = '';
	var selected_value = (document.forms["new_variant"]) ? document.forms["new_variant"].fk_product.options[document.forms["new_variant"].fk_product.selectedIndex].value : 0;
	selected_value = (document.forms["edit_variant"]) ? document.forms["edit_variant"].fk_product.options[document.forms["edit_variant"].fk_product.selectedIndex].value : selected_value;
	string = window.location.pathname;
	string = string + '?';
	self.location.href= string  + AddParameter("fk_product", selected_value, '');
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
function updateBranches () {
	document.forms["kooperation_newsletter"].submit_type.value = 'changes';
	document.forms["kooperation_newsletter"].submit();
}	
/////////////////////////////////////////////////////////////////////////////////////////////////////////
function updateBranchesSimple () {
	var string = '';	
	var addon_string = '';
	var selected_branch = document.forms["kooperation_newsletter"].search_branches.options[document.forms["kooperation_newsletter"].search_branches.selectedIndex].value;
	var selected_technology = document.forms["kooperation_newsletter"].search_technology.options[document.forms["kooperation_newsletter"].search_technology.selectedIndex].value;

	string = window.location.pathname;
	string = string + '?';
	addon_string = AddParameter("technology", selected_technology);
	addon_string = AddParameter("branch", selected_branch, addon_string);
	self.location.href= string  + addon_string;
}	
	
/////////////////////////////////////////////////////////////////////////////////////////////////////////
function updateIndustry (audit) {
	var string = '';	
	var addon_string = '';
	var selected_branch = document.forms["delete_form"].industry.options[document.forms["delete_form"].industry.selectedIndex].value;

	string = window.location.pathname;
	string = string + '?';
	addon_string = AddParameter("industry", selected_branch);
	addon_string = AddParameter("audit", audit, addon_string);
	self.location.href= string  + addon_string;
}		
/////////////////////////////////////////////////////////////////////////////////////////////////////////

// -----------------------------------------------------------------------------
// Globals
// Major version of Flash required
var requiredMajorVersion = 6;
// Minor version of Flash required
var requiredMinorVersion = 0;
// Minor version of Flash required
var requiredRevision = 0;
// the version of javascript supported
var jsVersion = 1.0;
// -----------------------------------------------------------------------------

var isIE  = (navigator.appVersion.indexOf("MSIE") != -1) ? true : false;
var isWin = (navigator.appVersion.toLowerCase().indexOf("win") != -1) ? true : false;
var isOpera = (navigator.userAgent.indexOf("Opera") != -1) ? true : false;
jsVersion = 1.1;

/////////////////////////////////////////////////////////////////////////////////////////////////////////

// JavaScript helper required to detect Flash Player PlugIn version information
function JSGetSwfVer(i){
	// NS/Opera version >= 3 check for Flash plugin in plugin array
	if (navigator.plugins != null && navigator.plugins.length > 0) {
		if (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]) {
			var swVer2 = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : "";
      		var flashDescription = navigator.plugins["Shockwave Flash" + swVer2].description;
			descArray = flashDescription.split(" ");
			tempArrayMajor = descArray[2].split(".");
			versionMajor = tempArrayMajor[0];
			versionMinor = tempArrayMajor[1];
			if ( descArray[3] != "" ) {
				tempArrayMinor = descArray[3].split("r");
			} else {
				tempArrayMinor = descArray[4].split("r");
			}
      		versionRevision = tempArrayMinor[1] > 0 ? tempArrayMinor[1] : 0;
            flashVer = versionMajor + "." + versionMinor + "." + versionRevision;
      	} else {
			flashVer = -1;
		}
	}
	// MSN/WebTV 2.6 supports Flash 4
	else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.6") != -1) flashVer = 4;
	// WebTV 2.5 supports Flash 3
	else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.5") != -1) flashVer = 3;
	// older WebTV supports Flash 2
	else if (navigator.userAgent.toLowerCase().indexOf("webtv") != -1) flashVer = 2;
	// Can't detect in all other cases
	else {
		
		flashVer = -1;
	}
	return flashVer;
} 

/////////////////////////////////////////////////////////////////////////////////////////////////////////

// When called with reqMajorVer, reqMinorVer, reqRevision returns true if that version or greater is available
function DetectFlashVer(reqMajorVer, reqMinorVer, reqRevision) 
{
 	reqVer = parseFloat(reqMajorVer + "." + reqRevision);
   	// loop backwards through the versions until we find the newest version	

	for (i=25;i>0;i--) {	
		if (isIE && isWin && !isOpera) {
			versionStr = VBGetSwfVer(i);
		} else {
			versionStr = JSGetSwfVer(i);		
		}
		
		if (versionStr == -1 ) { 
			return false;
		} else if (versionStr != 0) {
			if(isIE && isWin && !isOpera) {
				tempArray         = versionStr.split(" ");
				tempString        = tempArray[1];
				versionArray      = tempString .split(",");				
			} else {
				versionArray      = versionStr.split(".");
			}
			versionMajor      = versionArray[0];
			versionMinor      = versionArray[1];
			versionRevision   = versionArray[2];
			
			versionString     = versionMajor + "." + versionRevision;   // 7.0r24 == 7.24
			versionNum        = parseFloat(versionString);
        	// is the major.revision >= requested major.revision AND the minor version >= requested minor
			if ( (versionMajor > reqMajorVer) && (versionNum >= reqVer) ) {
				return true;
			} else {
				return ((versionNum >= reqVer && versionMinor >= reqMinorVer) ? true : false );	
			}
		}
	}	
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
function updateParent(target) {
	if(window.opener && window.opener.closed == false) {
		window.opener.location.href = target;
		window.opener.focus();
	}
	else 
	{ 
		window.open(target,"Parent");
 	}
	window.close();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////

function fnSetInfo(text) {
	if (text != '') {
	text = text.replace(new RegExp(decode('%A7%A7'),'gi'), '"');
	text = text.replace(new RegExp(decode('%26lt%3B'),'gi'), '<');
	
  event.dataTransfer.setData("Text", text); 
  event.dataTransfer.effectAllowed = "copy";                 
	}
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
function fnGetInfo(formName, fieldName) {
  event.returnValue = false;                           
  event.dataTransfer.dropEffect = "copy";              
  document.forms[formName].elements[fieldName].value += event.dataTransfer.getData("Text");
  document.forms[formName].elements[fieldName].focus();
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
function fnCancelDefault() {                                            
  event.returnValue = false;                  
  event.dataTransfer.dropEffect = "copy";  
}


/////////////////////////////////////////////////////////////////////////////////////////////////////////
function radioCheck (name, current_value) {
	for (i = 0; i < document.getElementsByName(name).length; i++) {
    if (document.getElementsByName(name)[i].value != current_value) {
     document.getElementsByName(name)[i].checked = false;
    } else {
		document.getElementsByName(name)[i].checked = true;
   }
  }
}


/////////////////////////////////////////////////////////////////////////////////////////////////////////
function formDynamicSubmit (name, field) {
	var string = '';
	if (field == null) field = 'Option';
	for (i = 0; i < document.getElementsByName(name).length; i++) {
		if (document.getElementsByName(name)[i].checked) {
			string = document.getElementsByName(name)[i].value;
		}
	}
	if (string != '') {
		document.forms[string].submit();
	} else {
		alert (unescape('Bitte w%E4hle eine ' + field + ' durch Anklicken des Kreises vor der Option.'));
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
function xorCrypt(text) {
	key = "123456789123456789123456789123456789123456789123456789";
	result = '';
	for (i = 0; i < text.length; i++){
		j = (i >= text.length)? 0 : i;
		result += String.fromCharCode(text.charCodeAt(i) ^ key.charCodeAt(j));		
	}
	return result;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
function sendmail(mail) {
	mail = 'mailto:'+xorCrypt(unescape(mail));
	location.href=mail;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
String.prototype.removeTags = function() {
	var tmp = this;
	while (tmp.search(/\<[^>]*\>/) != -1){
		tmp = tmp.replace(/\<[^>]*\>/,'').replace(/\n/,'').replace(/\r/,'');
	}
	return tmp.replace(/^(^\s*|\s*$)/, "").replace(/(^\s*|\s*$)$/, "");
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
String.prototype.trim = function(){
	return this.replace(/(^\s*|\s*$)/, "");
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
function insertText(from,select,field){
	var fieldset = $('id_'+field);
	var obj = $('id_'+from);
	var obj2 = document.getElementsByName(from);
	var select1 = document.getElementsByName(select+'[]')[0];
	var select2 = document.getElementsByName(select+'_unselected[]')[0];
	var input = obj2[0].value;
	var elementId = obj.g_id;
	var object = document.getElementById('id_hidden_value_' + elementId);
	object.value = input;
	var cstring = '';
	if (input.length > 10) cstring = input.slice(0,7) + '...';
	else cstring = input;
	if (fieldset != 'undefined') {Effect.Fade(fieldset);};
	if (hasOptions(select1)){ 
	    for (var i=0; i<select1.options.length; i++) {
			var o1 = select1.options[i];
			if (o1.value == elementId){
				o1.text = o1.text.replace(/\(.*\)/,'');
				o1.text = o1.text.concat(' ('+cstring+')');
				return;
			}
		}
	}
	if (hasOptions(select2) && cstring.length > 0){ 
	    for (var i=0; i<select2.options.length; i++) {
			var o2 = select2.options[i];
			if (o2.value == elementId){
				o2.text = o2.text.replace(/\(.*\)/,'');
				o2.text = o2.text.concat(' ('+cstring+')');
				return;
			}
		}
	}
	if (hasOptions(select2) && cstring.length == 0){ 
	    for (var i=0; i<select2.options.length; i++) {
			var o2 = select2.options[i];
			if (o2.value == elementId){
				o2.text = o2.text.replace(/\(.*\)/,'');
				o2.text = o2.text.concat('');
				return;
			}
		}
	}
	
}

function getSelectedValue(object){
	if (hasOptions(object)) {
		for (var i=0; i<object.options.length; i++) {
		//	alert("hasOptions(obj)");
			if (object.options[i].selected) { 
				return object.options[i].value;
			}
		}
	}
	return null;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
function showEditArea(fieldset,obj,textobj){
	var index;
	var replace = new Array();	
	index = (obj.selectedIndex > -1)?obj.options[obj.selectedIndex].value:null;
	
	if (index != null) {
		
		var object = $('id_hidden_value_' + index);
		var test2 = (object.replacetext == undefined || object.replacetext == null)? '' : new String(object.replacetext);
		var outer_replace = test2.split('+++++');	
		var obj2 = document.getElementsByName(textobj);
		$('id_'+textobj).g_id = obj.value;
		for (i=0;i<outer_replace.length;i++){
			replace.push(outer_replace[i].split('-----'));		
			var tmp = (is_ie)
						? $("id_"+replace[i][0]).firstChild
						: $("id_"+replace[i][0]);
			var myregexp = new RegExp(tmp.innerHTML.removeTags());
			tmp.innerHTML = tmp.innerHTML.replace(myregexp,replace[i][1]);	
			tmp.innerHTML = tmp.innerHTML.replace(myregexp,replace[i][1]);
			var tmp_array = tmp.innerHTML.split('%s');
			var IH = '';
			for (j=0;j<tmp_array.length;j++){
				IH = IH.concat(tmp_array[j]);
				if (replace[i][j+2] != undefined) IH = IH.concat(replace[i][j+2]);
			}
			tmp.innerHTML = IH;
		}	
		Effect.Appear(fieldset);
		
		obj2[0].value = object.value;
	}
}

function prepareHiddenFields(from1,from2){
	if (hasOptions(from1)) { 
		for (var i=0; i<from1.options.length; i++) {
			var o = from1.options[i];
			var object = $('id_hidden_value_' + o.value);
			object.replacetext = o.id;
			o.id ='';
		}
	}
	if (hasOptions(from2)) { 
	    for (var i=0; i<from2.options.length; i++) {
			var o = from2.options[i];
			var object = $('id_hidden_value_' + o.value);
			object.replacetext = o.id;
			o.id ='';
		}
	}
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
function moveSelectedOptionsAJAX(from,to,check,proove,sort,form,fieldset) {
	// Unselect matching options, if required
	var selectcount = 0;
    var option_set = 0;
    var lock = false;
	
	
    if (!hasOptions(from)) { return; }
    for (var i=0; i<from.options.length; i++) {
		var o = from.options[i];
		
		if (o.selected) { 
			selectcount++; 
	        if (o.value == keine_action) option_set =  option_set + 1;
	        if (o.value == alle_action) option_set = option_set + 2;
        }
    }
    
    if (proove == 1 && lockOptions(to) && option_set == 0) { return;  }

    if (proove ==1 && option_set > 0) {
         moveAllOptions (to, from);
        if (option_set > 1) {
            setSelectOptionsbyObj (from, alle_action, true);
        } else {
            setSelectOptionsbyObj (from, keine_action, true);
        }
    } 

	// Maximum exeeded ?
	if (check > 0 && (to.length >= check || ((selectcount+to.length) > check))) { return; }
	
	// Move them over
	for (var i=0; i<from.options.length; i++) {
		var o = from.options[i];
		if (o.selected) {
	        if (!hasOptions(to)) { var index = 0; } else { var index=to.options.length; }
			to.options[index] = new Option( o.text, o.value, false, false);
			to.options[index].setAttribute("id",o.id);
			}
		}

	// Delete them from original
	for (var i=(from.options.length-1); i>=0; i--) {
		var o = from.options[i];
		if (o.selected) {
				from.options[i] = null;			
			}
		}
	
	if (sort == 1) {
		sortSelect(from);
		sortSelect(to);
	}
	if (fieldset) {Effect.Fade(fieldset);};
	from.selectedIndex = -1;
	to.selectedIndex = -1;
	
	}
	
/**
*
*  UTF-8 data encode / decode
*
**/
var Utf8 = {

    // public method for url encoding
    encode : function (string) {
        string = string.replace(/\r\n/g,"\n");
        var utftext = "";

        for (var n = 0; n < string.length; n++) {

            var c = string.charCodeAt(n);

            if (c < 128) {
                utftext += String.fromCharCode(c);
            }
            else if((c > 127) && (c < 2048)) {
                utftext += String.fromCharCode((c >> 6) | 192);
                utftext += String.fromCharCode((c & 63) | 128);
            }
            else {
                utftext += String.fromCharCode((c >> 12) | 224);
                utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                utftext += String.fromCharCode((c & 63) | 128);
            }

        }

        return utftext;
    },

    // public method for url decoding
    decode : function (utftext) {
        var string = "";
        var i = 0;
        var c = c1 = c2 = 0;

        while ( i < utftext.length ) {

            c = utftext.charCodeAt(i);

            if (c < 128) {
                string += String.fromCharCode(c);
                i++;
            }
            else if((c > 191) && (c < 224)) {
                c2 = utftext.charCodeAt(i+1);
                string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
                i += 2;
            }
            else {
                c2 = utftext.charCodeAt(i+1);
                c3 = utftext.charCodeAt(i+2);
                string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
                i += 3;
            }

        }

        return string;
    }

}

// This code is in the public domain. Feel free to link back to http://jan.moesen.nu/
		function sprintf()
		{
			if (!arguments || arguments.length < 1 || !RegExp)
			{
				return;
			}
			var str = arguments[0];
			var re = /([^%]*)%('.|0|\x20)?(-)?(\d+)?(\.\d+)?(%|b|c|d|u|f|o|s|x|X)(.*)/;
			var a = b = [], numSubstitutions = 0, numMatches = 0;
			while (a = re.exec(str))
			{
				var leftpart = a[1], pPad = a[2], pJustify = a[3], pMinLength = a[4];
				var pPrecision = a[5], pType = a[6], rightPart = a[7];
				
				//alert(a + '\n' + [a[0], leftpart, pPad, pJustify, pMinLength, pPrecision);

				numMatches++;
				if (pType == '%')
				{
					subst = '%';
				}
				else
				{
					numSubstitutions++;
					if (numSubstitutions >= arguments.length)
					{
						alert('Error! Not enough function arguments (' + (arguments.length - 1) + ', excluding the string)\nfor the number of substitution parameters in string (' + numSubstitutions + ' so far).');
					}
					var param = arguments[numSubstitutions];
					var pad = '';
					       if (pPad && pPad.substr(0,1) == "'") pad = leftpart.substr(1,1);
					  else if (pPad) pad = pPad;
					var justifyRight = true;
					       if (pJustify && pJustify === "-") justifyRight = false;
					var minLength = -1;
					       if (pMinLength) minLength = parseInt(pMinLength);
					var precision = -1;
					       if (pPrecision && pType == 'f') precision = parseInt(pPrecision.substring(1));
					var subst = param;
					       if (pType == 'b') subst = parseInt(param).toString(2);
					  else if (pType == 'c') subst = String.fromCharCode(parseInt(param));
					  else if (pType == 'd') subst = parseInt(param) ? parseInt(param) : 0;
					  else if (pType == 'u') subst = Math.abs(param);
					  else if (pType == 'f') subst = (precision > -1) ? Math.round(parseFloat(param) * Math.pow(10, precision)) / Math.pow(10, precision): parseFloat(param);
					  else if (pType == 'o') subst = parseInt(param).toString(8);
					  else if (pType == 's') subst = param;
					  else if (pType == 'x') subst = ('' + parseInt(param).toString(16)).toLowerCase();
					  else if (pType == 'X') subst = ('' + parseInt(param).toString(16)).toUpperCase();
				}
				str = leftpart + subst + rightPart;
			}
			return str;
		}
		
/////////////////////////////////////////////////////////////////////////////////////////////////////////
function blog_checkform_addcomment (form) {

	var author  = form.author;
	var email   = form.email;
	var comment = form.comment_text;

	var error = "";
	if (author.value.match(/^\s*$/)) {
		error = error + "- Bitte geben Sie Ihren Namen ein.\n";
	}
	if (comment.value.match(/^\s*$/)) {
		error = error + "- Bitte geben Sie einen Kommentar an.\n";
	}
	if ((email.value.length > 0) && !email.value.match(/^.+\@.+\..+$/)) {
		error = error + unescape("- Bitte pr%FCfen Sie Ihre Email-Adresse auf G%FCltigkeit (oder lassen Sie das Feld ganz leer).");
	}
	
	if (error.length != 0) {
		alert(unescape("Folgende Felder sind nicht oder nicht korrekt ausgef%FCllt:\n") + error);
		return false;
	}
	
	return true;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////

/* Funktion zum PrÃ¼fen von Formulareingaben:

   Benutzung im Formular-Eventhandler:
     <form ... onSubmit="javascript:return validForm(this, new Array('email'), new Array('author','text'))">...</form>

   Feldtypen:
     - email: (automatisch, wenn kein Feldtyp angegeben und der Feldname 'mail' enthÃ¤lt)
	 - text: optional kÃ¶nnen Minimal- und MaximallÃ¤nge Ã¼bergeben werden
	 - integer: optional kÃ¶nnen Minimal- und Maximalwert Ã¼bergeben werden
	 
   RÃ¼ckgabewert:
	 - bei Fehlern wird eine Meldung angezeigt
     - Funktion gibt true oder false zurÃ¼ck
*/
function validForm (form, requiredFields) {
	var error = false;
	// ...
	return error;
}

function validEmail (email) { // UNGETESTET!!!
	if (String(email).match(/^.+\@.+\..+$/)) {
		return true;
	}
	return false;
}
function validText (text, minlength, maxlength) { // UNGETESTET!!!
	var t = String(text);
	if (t.length >= minlength && t.length <= maxlength) {
		return true;
	}
	return false;
}
function validInteger (integer, minvalue, maxvalue) { // UNGETESTET!!!
	var i = Number(integer);
	if (i.isNaN() || !i.isFinite || i < Number(minvalue) || i > Number(maxvalue)) {
		return true;
	}
	return false;
}

function lightboxRequest(element,params,type,mode,my_index,autoplay,autoplaytiming){
	if (type == undefined) type = 'gallery';	
	if (my_index == undefined) my_index = '1';	
	if (params == undefined) params = '';
	if (autoplay == undefined) autoplay = false;
	if (autoplaytiming == undefined) autoplaytiming = '10';
	if(mode == 'gallery') {
		url = '/data/gallery_getXML.php';
	}

	else {
		url = '/data/photoalbum_getXML.php';
	}	
	params = encodeURI(params+'&first_id=id_lightbox_photo_first&index='+my_index+'&type='+type);
	var opt = {
		// Use POST
		method: 'post',
		// Send this lovely data
		postBody: params,
		// Handle successful response
		onSuccess: function(t) {
			$(element).update(t.responseText);
			first = $('id_lightbox_photo_first');			
			if (type == 'lightbox'){
				//fÃ¼r lightbox
				initLightbox();
				myLightbox.start(first,autoplay,autoplaytiming);
			} else {
				//fÃ¼r lightview
				Lightview.updateViews();
				Lightview.show(first);
			}
		},
		// Handle 404
		on404: function(t) {
			alert('Error 404: location \"' + t.statusText + '\" was not found.');
		},
		// Handle other errors
		onFailure: function(t) {
			alert('Error ' + t.status + ' -- ' + t.statusText);
		}
	}
	new Ajax.Request(url, opt);
}

AIM = {
	frame : function(c) {

		var n = 'f' + Math.floor(Math.random() * 99999);
		var d = document.createElement('DIV');
		d.innerHTML = '<iframe style="display:none" src="about:blank" id="'+n+'" name="'+n+'" onload="AIM.loaded(\''+n+'\')"></iframe>';
		document.body.appendChild(d);

		var i = document.getElementById(n);
		if (c && typeof(c.onComplete) == 'function') {
			i.onComplete = c.onComplete;
		}

		if (c && c.options) {
			i.options = c.options;
		}	
		
		return n;
	},

	form : function(f, name) {
		f.setAttribute('target', name);
	},

	submit : function(f, c) {
		AIM.form(f, AIM.frame(c));
		if (c && typeof(c.onStart) == 'function') {
			return c.onStart();
		} else {
			return true;
		}
	},

	loaded : function(id) {
		var i = document.getElementById(id);
		if (i.contentDocument) {
			var d = i.contentDocument;
		} else if (i.contentWindow) {
			var d = i.contentWindow.document;
		} else {
			var d = window.frames[id].document;
		}
		if (d.location.href == "about:blank") {
			return;
		}

		if (typeof(i.onComplete) == 'function') {
			if (!d.body.getAttribute) {  
				i.onComplete(d.body.innerHTML,0);
			} else {
				i.onComplete(d.body.innerHTML,d.body.getAttribute('error'));
			}
		}
	}

}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
function defaultConfirmMessage (text, link, formName) {
	if (text != '') {
		text = text.replace("<br>", "\n");
		text = text.replace("<br />", "\n");
		Check = confirm(text);
		if (Check == true) {
			if (formName && formName != '') {
				document.forms[formName].submit();
			}
			else if (link && link != '') {
				location.href = link;
			}	
		}
	}	
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////
function clearText(str) {
	str = str.replace(new RegExp(unescape("%E4"),"g"),'ae');
	str = str.replace(new RegExp(unescape("%F6"),"g"),'oe');
	str = str.replace(new RegExp(unescape("%FC"),"g"),'ue');
	str = str.replace(new RegExp(unescape("%C4"),"g"),'Ae');
	str = str.replace(new RegExp(unescape("%D6"),"g"),'Oe');
	str = str.replace(new RegExp(unescape("%DC"),"g"),'Ue');
	str = str.replace(new RegExp(unescape("%DF"),"g"),'ss');
	restr = unescape("%5C%24%7C%2C%7C%B4%7C%B0%7C%40%7C%23%7C%C4%7C%A7%7C%5C%2F%7C%D6%7C%DC%7C%E4%7C%F6%7C%FC%7C%DF%7C %7C~%7C%60%7C%5C%25%7C%5C*%7C%5C%5E%7C%5C%26%7C%5C(%7C%5C)%7C%5C%2B%7C%5C%3D%7C%5C%5B%7C%5C%5D%7C%5C%7D%7C%5C%7B%7C%5C%3B%7C%5C%3A%7C%5C'%7C%5C%22%7C%5C%3C%7C%5C%3E%7C%5C%3F%7C%5C%7C%7C%5C%5C%7C%5C!%7C%5C%24%7C%5C.");
	// Entspricht "\$|,|Â´|Â°|@|#|Ã„|Â§|\/|Ã–|Ãœ|Ã¤|Ã¶|Ã¼|ÃŸ| |~|`|\%|\*|\^|\&|\(|\)|\+|\=|\[|\]|\}|\{|\;|\:|\'|\"|\<|\>|\?|\||\\|\!|\$|\."
	// Wichtig: nach urlencode das + gegen leerzeichern austauschen
	re = new RegExp(restr,"g");
	
	// re = /\$|,|`|@|#|Ã„|Â§|\/|Ã–|Ãœ|Ã¤|Ã¶|Ã¼|ÃŸ| |~|`|\%|\*|\^|\&|\(|\)|\+|\=|\[|\-|\_|\]|\[|\}|\{|\;|\:|\'|\"|\<|\>|\?|\||\\|\!|\$|\./g;
	// remove special characters like "$" and "," etc...
	return str.replace(re, "-");
}



/*
**
** File 'JavaScriptFlashGateway.js'
**
*/
/*
Macromedia(r) Flash(r) JavaScript Integration Kit License


Copyright (c) 2005 Macromedia, inc. All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.

3. The end-user documentation included with the redistribution, if any, must
include the following acknowledgment:

"This product includes software developed by Macromedia, Inc.
(http://www.macromedia.com)."

Alternately, this acknowledgment may appear in the software itself, if and
wherever such third-party acknowledgments normally appear.

4. The name Macromedia must not be used to endorse or promote products derived
from this software without prior written permission. For written permission,
please contact devrelations@macromedia.com.

5. Products derived from this software may not be called "Macromedia" or
"Macromedia Flash", nor may "Macromedia" or "Macromedia Flash" appear in their
name.

THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MACROMEDIA OR
ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.

--

This code is part of the Flash / JavaScript Integration Kit:
http://www.macromedia.com/go/flashjavascript/

Created by:

Christian Cantrell
http://weblogs.macromedia.com/cantrell/
mailto:cantrell@macromedia.com

Mike Chambers
http://weblogs.macromedia.com/mesh/
mailto:mesh@macromedia.com

Macromedia
*/

/**
 * Create a new Exception object.
 * name: The name of the exception.
 * message: The exception message.
 */
function Exception(name, message)
{
    if (name)
        this.name = name;
    if (message)
        this.message = message;
}

/**
 * Set the name of the exception. 
 */
Exception.prototype.setName = function(name)
{
    this.name = name;
}

/**
 * Get the exception's name. 
 */
Exception.prototype.getName = function()
{
    return this.name;
}

/**
 * Set a message on the exception. 
 */
Exception.prototype.setMessage = function(msg)
{
    this.message = msg;
}

/**
 * Get the exception message. 
 */
Exception.prototype.getMessage = function()
{
    return this.message;
}

/**
 * Generates a browser-specific Flash tag. Create a new instance, set whatever
 * properties you need, then call either toString() to get the tag as a string, or
 * call write() to write the tag out.
 */

/**
 * Creates a new instance of the FlashTag.
 * src: The path to the SWF file.
 * width: The width of your Flash content.
 * height: the height of your Flash content.
 */
function FlashTag(src, width, height,version, wmode)
{
    this.src       = src;
    this.width     = width;
    this.height    = height;
    this.version   = '7,0,14,0';
    this.id        = null;
    this.bgcolor   = 'ffffff';
    this.fullscreen= 'true';
    this.flashVars = null;
	if (!wmode) 
		wmode=0;
	this.wmode     = wmode; // 1 -> transparent, funktioniert aber nicht mit videoplayer fullscreen
}

/**
 * Sets the Flash version used in the Flash tag.
 */
FlashTag.prototype.setVersion = function(v)
{
    this.version = v;
}

/**
 * Sets the ID used in the Flash tag.
 */
FlashTag.prototype.setId = function(id)
{
    this.id = id;
}

/**
 * Kuborgh Bugfix!!!
 */
FlashTag.prototype.setWmode= function(mode)
{
    this.wmode = mode;
}

/**
 * Sets the background color used in the Flash tag.
 */
FlashTag.prototype.setBgcolor = function(bgc)
{
    this.bgcolor = bgc;
}

/**
 * Sets the background color used in the Flash tag.
 */
FlashTag.prototype.setFullscreen = function(fs)
{
    this.fullscreen = fs;
}

/**
 * Sets any variables to be passed into the Flash content. 
 */
FlashTag.prototype.setFlashvars = function(fv)
{
    this.flashVars = fv;
}

/**
 * Get the Flash tag as a string. 
 */
FlashTag.prototype.toString = function()
{
    var ie = (navigator.appName.indexOf ("Microsoft") != -1) ? 1 : 0;
    var flashTag = new String();
    if (ie)
    {
        flashTag += '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" ';
        if (this.id != null)
        {
            flashTag += 'id="'+this.id+'" ';
        }
        flashTag += 'codebase="https://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version='+this.version+'" ';
        flashTag += 'width="'+this.width+'" ';
        flashTag += 'height="'+this.height+'">';
        flashTag += '<param name="movie" value="'+this.src+'"/>';
        flashTag += '<param name="quality" value="high"/>';
		flashTag += '<param name="salign" value="lt" />';
		if (this.wmode == 1) 
			flashTag += '<param name="wmode" value="transparent"/>';
		flashTag += '<param name="bgcolor" value="'+this.bgcolor+'"/>';
        flashTag += '<param name="allowfullscreen" value="'+this.fullscreen+'"/>';
        if (this.flashVars != null)
        {
            flashTag += '<param name="flashvars" value="'+this.flashVars+'"/>';
        }
        flashTag += '</object>';
    }
    else
    {
        flashTag += '<embed src="'+this.src+'" ';
        flashTag += 'quality="high" '; 
		if (this.wmode == 1) 
			flashTag += 'wmode="transparent" ';
        flashTag += 'salign="lt" ';
        flashTag += 'bgcolor="'+this.bgcolor+'" ';
        flashTag += 'allowfullscreen="'+this.fullscreen+'" ';
        flashTag += 'width="'+this.width+'" ';
        flashTag += 'height="'+this.height+'" ';
        flashTag += 'type="application/x-shockwave-flash" ';
        if (this.flashVars != null)
        {
            flashTag += 'flashvars="'+this.flashVars+'" ';
        }
        if (this.id != null)
        {
            flashTag += 'name="'+this.id+'" ';
        }
        flashTag += 'pluginspage="http://www.macromedia.com/go/getflashplayer">';
        flashTag += '</embed>';
    }
    return flashTag;
}

/**
 * Write the Flash tag out. Pass in a reference to the document to write to. 
 */
FlashTag.prototype.write = function(doc)
{
    doc.write(this.toString());
}

/**
 * The FlashSerializer serializes JavaScript variables of types object, array, string,
 * number, date, boolean, null or undefined into XML. 
 */

/**
 * Create a new instance of the FlashSerializer.
 * useCdata: Whether strings should be treated as character data. If false, strings are simply XML encoded.
 */
function FlashSerializer(useCdata)
{
    this.useCdata = useCdata;
}

/**
 * Serialize an array into a format that can be deserialized in Flash. Supported data types are object,
 * array, string, number, date, boolean, null, and undefined. Returns a string of serialized data.
 */
FlashSerializer.prototype.serialize = function(args)
{
    var qs = new String();

    for (var i = 0; i < args.length; ++i)
    {
        switch(typeof(args[i]))
        {
            case 'undefined':
                qs += 't'+(i)+'=undf';
                break;
            case 'string':
                qs += 't'+(i)+'=str&d'+(i)+'='+escape(args[i]);
                break;
            case 'number':
                qs += 't'+(i)+'=num&d'+(i)+'='+escape(args[i]);
                break;
            case 'boolean':
                qs += 't'+(i)+'=bool&d'+(i)+'='+escape(args[i]);
                break;
            case 'object':
                if (args[i] == null)
                {
                    qs += 't'+(i)+'=null';
                }
                else if (args[i] instanceof Date)
                {
                    qs += 't'+(i)+'=date&d'+(i)+'='+escape(args[i].getTime());
                }
                else // array or object
                {
                    try
                    {
                        qs += 't'+(i)+'=xser&d'+(i)+'='+escape(this._serializeXML(args[i]));
                    }
                    catch (exception)
                    {
                        throw new Exception("FlashSerializationException",
                                            "The following error occurred during complex object serialization: " + exception.getMessage());
                    }
                }
                break;
            default:
                throw new Exception("FlashSerializationException",
                                    "You can only serialize strings, numbers, booleans, dates, objects, arrays, nulls, and undefined.");
        }

        if (i != (args.length - 1))
        {
            qs += '&';
        }
    }

    return qs;
}

/**
 * Private
 */
FlashSerializer.prototype._serializeXML = function(obj)
{
    var doc = new Object();
    doc.xml = '<fp>'; 
    this._serializeNode(obj, doc, null);
    doc.xml += '</fp>'; 
    return doc.xml;
}

/**
 * Private
 */
FlashSerializer.prototype._serializeNode = function(obj, doc, name)
{
    switch(typeof(obj))
    {
        case 'undefined':
            doc.xml += '<undf'+this._addName(name)+'/>';
            break;
        case 'string':
            doc.xml += '<str'+this._addName(name)+'>'+this._escapeXml(obj)+'</str>';
            break;
        case 'number':
            doc.xml += '<num'+this._addName(name)+'>'+obj+'</num>';
            break;
        case 'boolean':
            doc.xml += '<bool'+this._addName(name)+' val="'+obj+'"/>';
            break;
        case 'object':
            if (obj == null)
            {
                doc.xml += '<null'+this._addName(name)+'/>';
            }
            else if (obj instanceof Date)
            {
                doc.xml += '<date'+this._addName(name)+'>'+obj.getTime()+'</date>';
            }
            else if (obj instanceof Array)
            {
                doc.xml += '<array'+this._addName(name)+'>';
                for (var i = 0; i < obj.length; ++i)
                {
                    this._serializeNode(obj[i], doc, null);
                }
                doc.xml += '</array>';
            }
            else
            {
                doc.xml += '<obj'+this._addName(name)+'>';
                for (var n in obj)
                {
                    if (typeof(obj[n]) == 'function')
                        continue;
                    this._serializeNode(obj[n], doc, n);
                }
                doc.xml += '</obj>';
            }
            break;
        default:
            throw new Exception("FlashSerializationException",
                                "You can only serialize strings, numbers, booleans, objects, dates, arrays, nulls and undefined");
            break;
    }
}

/**
 * Private
 */
FlashSerializer.prototype._addName= function(name)
{
    if (name != null)
    {
        return ' name="'+name+'"';
    }
    return '';
}

/**
 * Private
 */
FlashSerializer.prototype._escapeXml = function(str)
{
    if (this.useCdata)
        return '<![CDATA['+str+']]>';
    else
        return str.replace(/&/g,'&amp;').replace(/</g,'&lt;');
}

/**
 * The FlashProxy object is what proxies function calls between JavaScript and Flash.
 * It handles all argument serialization issues.
 */

/**
 * Instantiates a new FlashProxy object. Pass in a uniqueID and the name (including the path)
 * of the Flash proxy SWF. The ID is the same ID that needs to be passed into your Flash content as lcId.
 */
function FlashProxy(uid, proxySwfName)
{
    this.uid = uid;
    this.proxySwfName = proxySwfName;
    this.flashSerializer = new FlashSerializer(false);
	this.wmode	   = 1;
}

/**
 * Call a function in your Flash content.  Arguments should be:
 * 1. ActionScript function name to call,
 * 2. any number of additional arguments of type object,
 *    array, string, number, boolean, date, null, or undefined. 
 */
FlashProxy.prototype.call = function()
{

    if (arguments.length == 0)
    {
        throw new Exception("Flash Proxy Exception",
                            "The first argument should be the function name followed by any number of additional arguments.");
    }

    var qs = 'lcId=' + escape(this.uid) + '&functionName=' + escape(arguments[0]);

    if (arguments.length > 1)
    {
        var justArgs = new Array();
        for (var i = 1; i < arguments.length; ++i)
        {
            justArgs.push(arguments[i]);
        }
        qs += ('&' + this.flashSerializer.serialize(justArgs));
    }

    var divName = '_flash_proxy_' + this.uid;
    if(!document.getElementById(divName))
    {
        var newTarget = document.createElement("div");
        newTarget.id = divName;
        document.body.appendChild(newTarget);
    }
    var target = document.getElementById(divName);
    var ft = new FlashTag(this.proxySwfName, 1, 1);
    ft.setVersion('6,0,65,0');
    ft.setFlashvars(qs);
	ft.setWmode(this.wmode);
    target.innerHTML = ft.toString();
}

/**
 * Kuborgh Bugfix!!!
 */
FlashProxy.prototype.setWmode= function(mode)
{
    this.wmode = mode;
}

/**
 * This is the function that proxies function calls from Flash to JavaScript.
 * It is called implicitly.
 */
FlashProxy.callJS = function()
{
    var functionToCall = eval(arguments[0]);
    var argArray = new Array();
    for (var i = 1; i < arguments.length; ++i)
    {
        argArray.push(arguments[i]);
    }
    functionToCall.apply(functionToCall, argArray);
}


/*
**
** File 'flashproxy.js'
**
*/
var lcId = new Date().getTime();
		var flashProxy = new FlashProxy(lcId, '/java/JavaScriptFlashGateway.swf'); 
		
		/*
		function transferItemToFlash() {
			flashProxy.call('functionXY', 'paramXY');
		}
		*/
/*
**
** File 'prototype.js'
**
*/
/*  Prototype JavaScript framework, version 1.6.0.3
 *  (c) 2005-2008 Sam Stephenson
 *
 *	Bugfix für Safari  Element.select() included
 *
 *  Prototype is freely distributable under the terms of an MIT-style license.
 *  For details, see the Prototype web site: http://www.prototypejs.org/
 *
 *--------------------------------------------------------------------------*/

var Prototype = {
  Version: '1.6.0.3',

  Browser: {
    IE:     !!(window.attachEvent &&
      navigator.userAgent.indexOf('Opera') === -1),
    Opera:  navigator.userAgent.indexOf('Opera') > -1,
    WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
    Gecko:  navigator.userAgent.indexOf('Gecko') > -1 &&
      navigator.userAgent.indexOf('KHTML') === -1,
    MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/)
  },

  BrowserFeatures: {
    XPath: !!document.evaluate,
    SelectorsAPI: !!document.querySelector,
    ElementExtensions: !!window.HTMLElement,
    SpecificElementExtensions:
      document.createElement('div')['__proto__'] &&
      document.createElement('div')['__proto__'] !==
        document.createElement('form')['__proto__']
  },

  ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>',
  JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/,

  emptyFunction: function() { },
  K: function(x) { return x }
};

if (Prototype.Browser.MobileSafari)
  Prototype.BrowserFeatures.SpecificElementExtensions = false;

var Abstract = { };



var Try = {
  these: function() {
    var returnValue;

    for (var i = 0, length = arguments.length; i < length; i++) {
      var lambda = arguments[i];
      try {
        returnValue = lambda();
        break;
      } catch (e) { }
    }

    return returnValue;
  }
};

/* Based on Alex Arnell's inheritance implementation. */

var Class = (function() {

  function create() {
    var parent = null, properties = $A(arguments);
    if (Object.isFunction(properties[0]))
      parent = properties.shift();

    function klass() {
      this.initialize.apply(this, arguments);
    }

    Object.extend(klass, Class.Methods);
    klass.superclass = parent;
    klass.subclasses = [];

    if (parent) {
      var subclass = function() {};
      subclass.prototype = parent.prototype;
      klass.prototype = new subclass;
      parent.subclasses.push(klass);
    }

    for (var i = 0; i < properties.length; i++)
      klass.addMethods(properties[i]);

    if (!klass.prototype.initialize)
      klass.prototype.initialize = Prototype.emptyFunction;

    klass.prototype.constructor = klass;
    return klass;
  }

  function addMethods(source) {
    var ancestor   = this.superclass && this.superclass.prototype;
    var properties = Object.keys(source);

    if (!Object.keys({ toString: true }).length)
      properties.push("toString", "valueOf");

    for (var i = 0, length = properties.length; i < length; i++) {
      var property = properties[i], value = source[property];
      if (ancestor && Object.isFunction(value) &&
          value.argumentNames().first() == "$super") {
        var method = value;
        value = (function(m) {
          return function() { return ancestor[m].apply(this, arguments); };
        })(property).wrap(method);

        value.valueOf = method.valueOf.bind(method);
        value.toString = method.toString.bind(method);
      }
      this.prototype[property] = value;
    }

    return this;
  }

  return {
    create: create,
    Methods: {
      addMethods: addMethods
    }
  };
})();


(function() {

  function getClass(object) {
    return Object.prototype.toString.call(object)
     .match(/^\[object\s(.*)\]$/)[1];
  }

  function extend(destination, source) {
    for (var property in source)
      destination[property] = source[property];
    return destination;
  }

  function inspect(object) {
    try {
      if (isUndefined(object)) return 'undefined';
      if (object === null) return 'null';
      return object.inspect ? object.inspect() : String(object);
    } catch (e) {
      if (e instanceof RangeError) return '...';
      throw e;
    }
  }

  function toJSON(object) {
    var type = typeof object;
    switch (type) {
      case 'undefined':
      case 'function':
      case 'unknown': return;
      case 'boolean': return object.toString();
    }

    if (object === null) return 'null';
    if (object.toJSON) return object.toJSON();
    if (isElement(object)) return;

    var results = [];
    for (var property in object) {
      var value = toJSON(object[property]);
      if (!isUndefined(value))
        results.push(property.toJSON() + ': ' + value);
    }

    return '{' + results.join(', ') + '}';
  }

  function toQueryString(object) {
    return $H(object).toQueryString();
  }

  function toHTML(object) {
    return object && object.toHTML ? object.toHTML() : String.interpret(object);
  }

  function keys(object) {
    var results = [];
    for (var property in object)
      results.push(property);
    return results;
  }

  function values(object) {
    var results = [];
    for (var property in object)
      results.push(object[property]);
    return results;
  }

  function clone(object) {
    return extend({ }, object);
  }

  function isElement(object) {
    return !!(object && object.nodeType == 1);
  }

  function isArray(object) {
    return getClass(object) === "Array";
  }

  function isHash(object) {
    return object instanceof Hash;
  }

  function isFunction(object) {
    return typeof object === "function";
  }

  function isString(object) {
    return getClass(object) === "String";
  }

  function isNumber(object) {
    return getClass(object) === "Number";
  }

  function isUndefined(object) {
    return typeof object === "undefined";
  }

  extend(Object, {
    extend:        extend,
    inspect:       inspect,
    toJSON:        toJSON,
    toQueryString: toQueryString,
    toHTML:        toHTML,
    keys:          keys,
    values:        values,
    clone:         clone,
    isElement:     isElement,
    isArray:       isArray,
    isHash:        isHash,
    isFunction:    isFunction,
    isString:      isString,
    isNumber:      isNumber,
    isUndefined:   isUndefined
  });
})();


Object.extend(Function.prototype, (function() {
  var slice = Array.prototype.slice;

  function update(array, args) {
    var arrayLength = array.length, length = args.length;
    while (length--) array[arrayLength + length] = args[length];
    return array;
  }

  function merge(array, args) {
    array = slice.call(array, 0);
    return update(array, args);
  }

  function argumentNames() {
    var names = this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1]
      .replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '')
      .replace(/\s+/g, '').split(',');
    return names.length == 1 && !names[0] ? [] : names;
  }

  function bind(context) {
    if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this;
    var __method = this, args = slice.call(arguments, 1);
    return function() {
      var a = merge(args, arguments);
      return __method.apply(context, a);
    }
  }

  function bindAsEventListener(context) {
    var __method = this, args = slice.call(arguments, 1);
    return function(event) {
      var a = update([event || window.event], args);
      return __method.apply(context, a);
    }
  }

  function curry() {
    if (!arguments.length) return this;
    var __method = this, args = slice.call(arguments, 0);
    return function() {
      var a = merge(args, arguments);
      return __method.apply(this, a);
    }
  }

  function delay(timeout) {
    var __method = this, args = slice.call(arguments, 1);
    timeout = timeout * 1000
    return window.setTimeout(function() {
      return __method.apply(__method, args);
    }, timeout);
  }

  function defer() {
    var args = update([0.01], arguments);
    return this.delay.apply(this, args);
  }

  function wrap(wrapper) {
    var __method = this;
    return function() {
      var a = update([__method.bind(this)], arguments);
      return wrapper.apply(this, a);
    }
  }

  function methodize() {
    if (this._methodized) return this._methodized;
    var __method = this;
    return this._methodized = function() {
      var a = update([this], arguments);
      return __method.apply(null, a);
    };
  }

  return {
    argumentNames:       argumentNames,
    bind:                bind,
    bindAsEventListener: bindAsEventListener,
    curry:               curry,
    delay:               delay,
    defer:               defer,
    wrap:                wrap,
    methodize:           methodize
  }
})());




Date.prototype.toJSON = function() {
  return '"' + this.getUTCFullYear() + '-' +
    (this.getUTCMonth() + 1).toPaddedString(2) + '-' +
    this.getUTCDate().toPaddedString(2) + 'T' +
    this.getUTCHours().toPaddedString(2) + ':' +
    this.getUTCMinutes().toPaddedString(2) + ':' +
    this.getUTCSeconds().toPaddedString(2) + 'Z"';
};



RegExp.prototype.match = RegExp.prototype.test;

RegExp.escape = function(str) {
  return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
};


var PeriodicalExecuter = Class.create({

  initialize: function(callback, frequency) {
    this.callback = callback;
    this.frequency = frequency;
    this.currentlyExecuting = false;

    this.registerCallback();
  },

  registerCallback: function() {
    this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
  },

  execute: function() {
    this.callback(this);
  },

  stop: function() {
    if (!this.timer) return;
    clearInterval(this.timer);
    this.timer = null;
  },

  onTimerEvent: function() {
    if (!this.currentlyExecuting) {
      try {
        this.currentlyExecuting = true;
        this.execute();
      } finally {
        this.currentlyExecuting = false;
      }
    }
  }
});



Object.extend(String, {

  interpret: function(value) {
    return value == null ? '' : String(value);
  },
  specialChar: {
    '\b': '\\b',
    '\t': '\\t',
    '\n': '\\n',
    '\f': '\\f',
    '\r': '\\r',
    '\\': '\\\\'
  }
});

Object.extend(String.prototype, (function() {

  function prepareReplacement(replacement) {
    if (Object.isFunction(replacement)) return replacement;
    var template = new Template(replacement);
    return function(match) { return template.evaluate(match) };
  }

  function gsub(pattern, replacement) {
    var result = '', source = this, match;
    replacement = prepareReplacement(replacement);

    while (source.length > 0) {
      if (match = source.match(pattern)) {
        result += source.slice(0, match.index);
        result += String.interpret(replacement(match));
        source  = source.slice(match.index + match[0].length);
      } else {
        result += source, source = '';
      }
    }
    return result;
  }

  function sub(pattern, replacement, count) {
    replacement = prepareReplacement(replacement);
    count = Object.isUndefined(count) ? 1 : count;

    return this.gsub(pattern, function(match) {
      if (--count < 0) return match[0];
      return replacement(match);
    });
  }

  function scan(pattern, iterator) {
    this.gsub(pattern, iterator);
    return String(this);
  }

  function truncate(length, truncation) {
    length = length || 30;
    truncation = Object.isUndefined(truncation) ? '...' : truncation;
    return this.length > length ?
      this.slice(0, length - truncation.length) + truncation : String(this);
  }

  function strip() {
    return this.replace(/^\s+/, '').replace(/\s+$/, '');
  }

  function stripTags() {
    return this.replace(/<\/?[^>]+>/gi, '');
  }

  function stripScripts() {
    return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
  }

  function extractScripts() {
    var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
    var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
    return (this.match(matchAll) || []).map(function(scriptTag) {
      return (scriptTag.match(matchOne) || ['', ''])[1];
    });
  }

  function evalScripts() {
    return this.extractScripts().map(function(script) { return eval(script) });
  }

  function escapeHTML() {
    escapeHTML.text.data = this;
    return escapeHTML.div.innerHTML;
  }

  function unescapeHTML() {
    var div = new Element('div');
    div.innerHTML = this.stripTags();
    return div.childNodes[0] ? (div.childNodes.length > 1 ?
      $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) :
      div.childNodes[0].nodeValue) : '';
  }

  function toQueryParams(separator) {
    var match = this.strip().match(/([^?#]*)(#.*)?$/);
    if (!match) return { };

    return match[1].split(separator || '&').inject({ }, function(hash, pair) {
      if ((pair = pair.split('='))[0]) {
        var key = decodeURIComponent(pair.shift());
        var value = pair.length > 1 ? pair.join('=') : pair[0];
        if (value != undefined) value = decodeURIComponent(value);

        if (key in hash) {
          if (!Object.isArray(hash[key])) hash[key] = [hash[key]];
          hash[key].push(value);
        }
        else hash[key] = value;
      }
      return hash;
    });
  }

  function toArray() {
    return this.split('');
  }

  function succ() {
    return this.slice(0, this.length - 1) +
      String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
  }

  function times(count) {
    return count < 1 ? '' : new Array(count + 1).join(this);
  }

  function camelize() {
    var parts = this.split('-'), len = parts.length;
    if (len == 1) return parts[0];

    var camelized = this.charAt(0) == '-'
      ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
      : parts[0];

    for (var i = 1; i < len; i++)
      camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);

    return camelized;
  }

  function capitalize() {
    return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
  }

  function underscore() {
    return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();
  }

  function dasherize() {
    return this.gsub(/_/,'-');
  }

  function inspect(useDoubleQuotes) {
    var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) {
      var character = String.specialChar[match[0]];
      return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16);
    });
    if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
    return "'" + escapedString.replace(/'/g, '\\\'') + "'";
  }

  function toJSON() {
    return this.inspect(true);
  }

  function unfilterJSON(filter) {
    return this.sub(filter || Prototype.JSONFilter, '#{1}');
  }

  function isJSON() {
    var str = this;
    if (str.blank()) return false;
    str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '');
    return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str);
  }

  function evalJSON(sanitize) {
    var json = this.unfilterJSON();
    try {
      if (!sanitize || json.isJSON()) return eval('(' + json + ')');
    } catch (e) { }
    throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
  }

  function include(pattern) {
    return this.indexOf(pattern) > -1;
  }

  function startsWith(pattern) {
    return this.indexOf(pattern) === 0;
  }

  function endsWith(pattern) {
    var d = this.length - pattern.length;
    return d >= 0 && this.lastIndexOf(pattern) === d;
  }

  function empty() {
    return this == '';
  }

  function blank() {
    return /^\s*$/.test(this);
  }

  function interpolate(object, pattern) {
    return new Template(this, pattern).evaluate(object);
  }

  return {
    gsub:           gsub,
    sub:            sub,
    scan:           scan,
    truncate:       truncate,
    strip:          strip,
    stripTags:      stripTags,
    stripScripts:   stripScripts,
    extractScripts: extractScripts,
    evalScripts:    evalScripts,
    escapeHTML:     escapeHTML,
    unescapeHTML:   unescapeHTML,
    toQueryParams:  toQueryParams,
    parseQuery:     toQueryParams,
    toArray:        toArray,
    succ:           succ,
    times:          times,
    camelize:       camelize,
    capitalize:     capitalize,
    underscore:     underscore,
    dasherize:      dasherize,
    inspect:        inspect,
    toJSON:         toJSON,
    unfilterJSON:   unfilterJSON,
    isJSON:         isJSON,
    evalJSON:       evalJSON,
    include:        include,
    startsWith:     startsWith,
    endsWith:       endsWith,
    empty:          empty,
    blank:          blank,
    interpolate:    interpolate
  };
})());

if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, {
  escapeHTML: function() {
    return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
  },
  unescapeHTML: function() {
    return this.stripTags().replace(/&amp;/g,'&').replace(/&lt;/g,'<').replace(/&gt;/g,'>');
  }
});

Object.extend(String.prototype.escapeHTML, {
  div:  document.createElement('div'),
  text: document.createTextNode('')
});

String.prototype.escapeHTML.div.appendChild(String.prototype.escapeHTML.text);


var Template = Class.create({

  initialize: function(template, pattern) {
    this.template = template.toString();
    this.pattern = pattern || Template.Pattern;
  },

  evaluate: function(object) {
    if (Object.isFunction(object.toTemplateReplacements))
      object = object.toTemplateReplacements();

    return this.template.gsub(this.pattern, function(match) {
      if (object == null) return '';

      var before = match[1] || '';
      if (before == '\\') return match[2];

      var ctx = object, expr = match[3];
      var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;
      match = pattern.exec(expr);
      if (match == null) return before;

      while (match != null) {
        var comp = match[1].startsWith('[') ? match[2].gsub('\\\\]', ']') : match[1];
        ctx = ctx[comp];
        if (null == ctx || '' == match[3]) break;
        expr = expr.substring('[' == match[3] ? match[1].length : match[0].length);
        match = pattern.exec(expr);
      }

      return before + String.interpret(ctx);
    });
  }
});
Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;




var $break = { };

var Enumerable = (function() {

  function each(iterator, context) {
    var index = 0;
    try {
      this._each(function(value) {
        iterator.call(context, value, index++);
      });
    } catch (e) {
      if (e != $break) throw e;
    }
    return this;
  }

  function eachSlice(number, iterator, context) {
    var index = -number, slices = [], array = this.toArray();
    if (number < 1) return array;
    while ((index += number) < array.length)
      slices.push(array.slice(index, index+number));
    return slices.collect(iterator, context);
  }

  function all(iterator, context) {
    iterator = iterator || Prototype.K;
    var result = true;
    this.each(function(value, index) {
      result = result && !!iterator.call(context, value, index);
      if (!result) throw $break;
    });
    return result;
  }

  function any(iterator, context) {
    iterator = iterator || Prototype.K;
    var result = false;
    this.each(function(value, index) {
      if (result = !!iterator.call(context, value, index))
        throw $break;
    });
    return result;
  }

  function collect(iterator, context) {
    iterator = iterator || Prototype.K;
    var results = [];
    this.each(function(value, index) {
      results.push(iterator.call(context, value, index));
    });
    return results;
  }

  function detect(iterator, context) {
    var result;
    this.each(function(value, index) {
      if (iterator.call(context, value, index)) {
        result = value;
        throw $break;
      }
    });
    return result;
  }

  function findAll(iterator, context) {
    var results = [];
    this.each(function(value, index) {
      if (iterator.call(context, value, index))
        results.push(value);
    });
    return results;
  }

  function grep(filter, iterator, context) {
    iterator = iterator || Prototype.K;
    var results = [];

    if (Object.isString(filter))
      filter = new RegExp(RegExp.escape(filter));

    this.each(function(value, index) {
      if (filter.match(value))
        results.push(iterator.call(context, value, index));
    });
    return results;
  }

  function include(object) {
    if (Object.isFunction(this.indexOf))
      if (this.indexOf(object) != -1) return true;

    var found = false;
    this.each(function(value) {
      if (value == object) {
        found = true;
        throw $break;
      }
    });
    return found;
  }

  function inGroupsOf(number, fillWith) {
    fillWith = Object.isUndefined(fillWith) ? null : fillWith;
    return this.eachSlice(number, function(slice) {
      while(slice.length < number) slice.push(fillWith);
      return slice;
    });
  }

  function inject(memo, iterator, context) {
    this.each(function(value, index) {
      memo = iterator.call(context, memo, value, index);
    });
    return memo;
  }

  function invoke(method) {
    var args = $A(arguments).slice(1);
    return this.map(function(value) {
      return value[method].apply(value, args);
    });
  }

  function max(iterator, context) {
    iterator = iterator || Prototype.K;
    var result;
    this.each(function(value, index) {
      value = iterator.call(context, value, index);
      if (result == null || value >= result)
        result = value;
    });
    return result;
  }

  function min(iterator, context) {
    iterator = iterator || Prototype.K;
    var result;
    this.each(function(value, index) {
      value = iterator.call(context, value, index);
      if (result == null || value < result)
        result = value;
    });
    return result;
  }

  function partition(iterator, context) {
    iterator = iterator || Prototype.K;
    var trues = [], falses = [];
    this.each(function(value, index) {
      (iterator.call(context, value, index) ?
        trues : falses).push(value);
    });
    return [trues, falses];
  }

  function pluck(property) {
    var results = [];
    this.each(function(value) {
      results.push(value[property]);
    });
    return results;
  }

  function reject(iterator, context) {
    var results = [];
    this.each(function(value, index) {
      if (!iterator.call(context, value, index))
        results.push(value);
    });
    return results;
  }

  function sortBy(iterator, context) {
    return this.map(function(value, index) {
      return {
        value: value,
        criteria: iterator.call(context, value, index)
      };
    }).sort(function(left, right) {
      var a = left.criteria, b = right.criteria;
      return a < b ? -1 : a > b ? 1 : 0;
    }).pluck('value');
  }

  function toArray() {
    return this.map();
  }

  function zip() {
    var iterator = Prototype.K, args = $A(arguments);
    if (Object.isFunction(args.last()))
      iterator = args.pop();

    var collections = [this].concat(args).map($A);
    return this.map(function(value, index) {
      return iterator(collections.pluck(index));
    });
  }

  function size() {
    return this.toArray().length;
  }

  function inspect() {
    return '#<Enumerable:' + this.toArray().inspect() + '>';
  }

  return {
    each:       each,
    eachSlice:  eachSlice,
    all:        all,
    every:      all,
    any:        any,
    some:       any,
    collect:    collect,
    map:        collect,
    detect:     detect,
    findAll:    findAll,
    select:     findAll,
    filter:     findAll,
    grep:       grep,
    include:    include,
    member:     include,
    inGroupsOf: inGroupsOf,
    inject:     inject,
    invoke:     invoke,
    max:        max,
    min:        min,
    partition:  partition,
    pluck:      pluck,
    reject:     reject,
    sortBy:     sortBy,
    toArray:    toArray,
    entries:    toArray,
    zip:        zip,
    size:       size,
    inspect:    inspect,
    find:       detect
  };
})();


function $A(iterable) {
  if (!iterable) return [];
  if (iterable.toArray) return iterable.toArray();
  var length = iterable.length || 0, results = new Array(length);
  while (length--) results[length] = iterable[length];
  return results;
}

if (Prototype.Browser.WebKit) {
  $A = function(iterable) {
    if (!iterable) return [];
    // In Safari, only use the `toArray` method if it's not a NodeList.
    // A NodeList is a function, has an function `item` property, and a numeric
    // `length` property. Adapted from Google Doctype.
    if (!(typeof iterable === 'function' && typeof iterable.length ===
        'number' && typeof iterable.item === 'function') && iterable.toArray)
      return iterable.toArray();
    var length = iterable.length || 0, results = new Array(length);
    while (length--) results[length] = iterable[length];
    return results;
  };
}

function $w(string) {
  if (!Object.isString(string)) return [];
  string = string.strip();
  return string ? string.split(/\s+/) : [];
}

Array.from = $A;

(function() {
  var arrayProto = Array.prototype,
      slice = arrayProto.slice,
      _each = arrayProto.forEach; // use native browser JS 1.6 implementation if available

  function each(iterator) {
    for (var i = 0, length = this.length; i < length; i++)
      iterator(this[i]);
  }
  if (!_each) _each = each;

  function clear() {
    this.length = 0;
    return this;
  }

  function first() {
    return this[0];
  }

  function last() {
    return this[this.length - 1];
  }

  function compact() {
    return this.select(function(value) {
      return value != null;
    });
  }

  function flatten() {
    return this.inject([], function(array, value) {
      if (Object.isArray(value))
        return array.concat(value.flatten());
      array.push(value);
      return array;
    });
  }

  function without() {
    var values = slice.call(arguments, 0);
    return this.select(function(value) {
      return !values.include(value);
    });
  }

  function reverse(inline) {
    return (inline !== false ? this : this.toArray())._reverse();
  }

  function reduce() {
    return this.length > 1 ? this : this[0];
  }

  function uniq(sorted) {
    return this.inject([], function(array, value, index) {
      if (0 == index || (sorted ? array.last() != value : !array.include(value)))
        array.push(value);
      return array;
    });
  }

  function intersect(array) {
    return this.uniq().findAll(function(item) {
      return array.detect(function(value) { return item === value });
    });
  }

  function clone() {
    return slice.call(this, 0);
  }

  function size() {
    return this.length;
  }

  function inspect() {
    return '[' + this.map(Object.inspect).join(', ') + ']';
  }

  function toJSON() {
    var results = [];
    this.each(function(object) {
      var value = Object.toJSON(object);
      if (!Object.isUndefined(value)) results.push(value);
    });
    return '[' + results.join(', ') + ']';
  }

  function indexOf(item, i) {
    i || (i = 0);
    var length = this.length;
    if (i < 0) i = length + i;
    for (; i < length; i++)
      if (this[i] === item) return i;
    return -1;
  }

  function lastIndexOf(item, i) {
    i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1;
    var n = this.slice(0, i).reverse().indexOf(item);
    return (n < 0) ? n : i - n - 1;
  }

  function concat() {
    var array = slice.call(this, 0), item;
    for (var i = 0, length = arguments.length; i < length; i++) {
      item = arguments[i];
      if (Object.isArray(item) && !('callee' in item)) {
        for (var j = 0, arrayLength = item.length; j < arrayLength; j++)
          array.push(item[j]);
      } else {
        array.push(item);
      }
    }
    return array;
  }

  Object.extend(arrayProto, Enumerable);

  if (!arrayProto._reverse)
    arrayProto._reverse = arrayProto.reverse;

  Object.extend(arrayProto, {
    _each:     _each,
    clear:     clear,
    first:     first,
    last:      last,
    compact:   compact,
    flatten:   flatten,
    without:   without,
    reverse:   reverse,
    reduce:    reduce,
    uniq:      uniq,
    intersect: intersect,
    clone:     clone,
    toArray:   clone,
    size:      size,
    inspect:   inspect,
    toJSON:    toJSON
  });

  // fix for opera
  var CONCAT_ARGUMENTS_BUGGY = (function() {
    return [].concat(arguments)[0][0] !== 1;
  })(1,2)

  if (CONCAT_ARGUMENTS_BUGGY) arrayProto.concat = concat;

  // use native browser JS 1.6 implementation if available
  if (!arrayProto.indexOf) arrayProto.indexOf = indexOf;
  if (!arrayProto.lastIndexOf) arrayProto.lastIndexOf = lastIndexOf;
})();


function $H(object) {
  return new Hash(object);
};

var Hash = Class.create(Enumerable, (function() {

  function initialize(object) {
    this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);
  }

  function _each(iterator) {
    for (var key in this._object) {
      var value = this._object[key], pair = [key, value];
      pair.key = key;
      pair.value = value;
      iterator(pair);
    }
  }

  function set(key, value) {
    return this._object[key] = value;
  }

  function get(key) {
    // simulating poorly supported hasOwnProperty
    if (this._object[key] !== Object.prototype[key])
      return this._object[key];
  }

  function unset(key) {
    var value = this._object[key];
    delete this._object[key];
    return value;
  }

  function toObject() {
    return Object.clone(this._object);
  }

  function keys() {
    return this.pluck('key');
  }

  function values() {
    return this.pluck('value');
  }

  function index(value) {
    var match = this.detect(function(pair) {
      return pair.value === value;
    });
    return match && match.key;
  }

  function merge(object) {
    return this.clone().update(object);
  }

  function update(object) {
    return new Hash(object).inject(this, function(result, pair) {
      result.set(pair.key, pair.value);
      return result;
    });
  }

  function toQueryPair(key, value) {
    if (Object.isUndefined(value)) return key;
    return key + '=' + encodeURIComponent(String.interpret(value));
  }

  function toQueryString() {
    return this.inject([], function(results, pair) {
      var key = encodeURIComponent(pair.key), values = pair.value;

      if (values && typeof values == 'object') {
        if (Object.isArray(values))
          return results.concat(values.map(toQueryPair.curry(key)));
      } else results.push(toQueryPair(key, values));
      return results;
    }).join('&');
  }

  function inspect() {
    return '#<Hash:{' + this.map(function(pair) {
      return pair.map(Object.inspect).join(': ');
    }).join(', ') + '}>';
  }

  function toJSON() {
    return Object.toJSON(this.toObject());
  }

  function clone() {
    return new Hash(this);
  }

  return {
    initialize:             initialize,
    _each:                  _each,
    set:                    set,
    get:                    get,
    unset:                  unset,
    toObject:               toObject,
    toTemplateReplacements: toObject,
    keys:                   keys,
    values:                 values,
    index:                  index,
    merge:                  merge,
    update:                 update,
    toQueryString:          toQueryString,
    inspect:                inspect,
    toJSON:                 toJSON,
    clone:                  clone
  };
})());

Hash.from = $H;



Object.extend(Number.prototype, (function() {

  function toColorPart() {
    return this.toPaddedString(2, 16);
  }

  function succ() {
    return this + 1;
  }

  function times(iterator, context) {
    $R(0, this, true).each(iterator, context);
    return this;
  }

  function toPaddedString(length, radix) {
    var string = this.toString(radix || 10);
    return '0'.times(length - string.length) + string;
  }

  function toJSON() {
    return isFinite(this) ? this.toString() : 'null';
  }

  function abs() {
    return Math.abs(this);
  }

  function round() {
    return Math.round(this);
  }

  function ceil() {
    return Math.ceil(this);
  }

  function floor() {
    return Math.floor(this);
  }

  return {
    toColorPart:    toColorPart,
    succ:           succ,
    times:          times,
    toPaddedString: toPaddedString,
    toJSON:         toJSON,
    abs:            abs,
    round:          round,
    ceil:           ceil,
    floor:          floor
  };
})());



function $R(start, end, exclusive) {
  return new ObjectRange(start, end, exclusive);
}

var ObjectRange = Class.create(Enumerable, (function() {

  function initialize(start, end, exclusive) {
    this.start = start;
    this.end = end;
    this.exclusive = exclusive;
  }

  function _each(iterator) {
    var value = this.start;
    while (this.include(value)) {
      iterator(value);
      value = value.succ();
    }
  }

  function include(value) {
    if (value < this.start)
      return false;
    if (this.exclusive)
      return value < this.end;
    return value <= this.end;
  }

  return {
    initialize: initialize,
    _each:      _each,
    include:    include
  };
})());

var Ajax = {
  getTransport: function() {
    return Try.these(
      function() {return new XMLHttpRequest()},
      function() {return new ActiveXObject('Msxml2.XMLHTTP')},
      function() {return new ActiveXObject('Microsoft.XMLHTTP')}
    ) || false;
  },

  activeRequestCount: 0
};
Ajax.Responders = {
  responders: [],

  _each: function(iterator) {
    this.responders._each(iterator);
  },

  register: function(responder) {
    if (!this.include(responder))
      this.responders.push(responder);
  },

  unregister: function(responder) {
    this.responders = this.responders.without(responder);
  },

  dispatch: function(callback, request, transport, json) {
    this.each(function(responder) {
      if (Object.isFunction(responder[callback])) {
        try {
          responder[callback].apply(responder, [request, transport, json]);
        } catch (e) { }
      }
    });
  }
};

Object.extend(Ajax.Responders, Enumerable);

Ajax.Responders.register({
  onCreate:   function() { Ajax.activeRequestCount++ },
  onComplete: function() { Ajax.activeRequestCount-- }
});
Ajax.Base = Class.create({
  initialize: function(options) {
    this.options = {
      method:       'post',
      asynchronous: true,
      contentType:  'application/x-www-form-urlencoded',
      encoding:     'UTF-8',
      parameters:   '',
      evalJSON:     true,
      evalJS:       true
    };
    Object.extend(this.options, options || { });

    this.options.method = this.options.method.toLowerCase();

    if (Object.isString(this.options.parameters))
      this.options.parameters = this.options.parameters.toQueryParams();
    else if (Object.isHash(this.options.parameters))
      this.options.parameters = this.options.parameters.toObject();
  }
});
Ajax.Request = Class.create(Ajax.Base, {
  _complete: false,

  initialize: function($super, url, options) {
    $super(options);
    this.transport = Ajax.getTransport();
    this.request(url);
  },

  request: function(url) {
    this.url = url;
    this.method = this.options.method;
    var params = Object.clone(this.options.parameters);

    if (!['get', 'post'].include(this.method)) {
      // simulate other verbs over post
      params['_method'] = this.method;
      this.method = 'post';
    }

    this.parameters = params;

    if (params = Object.toQueryString(params)) {
      // when GET, append parameters to URL
      if (this.method == 'get')
        this.url += (this.url.include('?') ? '&' : '?') + params;
      else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))
        params += '&_=';
    }

    try {
      var response = new Ajax.Response(this);
      if (this.options.onCreate) this.options.onCreate(response);
      Ajax.Responders.dispatch('onCreate', this, response);

      this.transport.open(this.method.toUpperCase(), this.url,
        this.options.asynchronous);

      if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1);

      this.transport.onreadystatechange = this.onStateChange.bind(this);
      this.setRequestHeaders();

      this.body = this.method == 'post' ? (this.options.postBody || params) : null;
      this.transport.send(this.body);

      /* Force Firefox to handle ready state 4 for synchronous requests */
      if (!this.options.asynchronous && this.transport.overrideMimeType)
        this.onStateChange();

    }
    catch (e) {
      this.dispatchException(e);
    }
  },

  onStateChange: function() {
    var readyState = this.transport.readyState;
    if (readyState > 1 && !((readyState == 4) && this._complete))
      this.respondToReadyState(this.transport.readyState);
  },

  setRequestHeaders: function() {
    var headers = {
      'X-Requested-With': 'XMLHttpRequest',
      'X-Prototype-Version': Prototype.Version,
      'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
    };

    if (this.method == 'post') {
      headers['Content-type'] = this.options.contentType +
        (this.options.encoding ? '; charset=' + this.options.encoding : '');

      /* Force "Connection: close" for older Mozilla browsers to work
       * around a bug where XMLHttpRequest sends an incorrect
       * Content-length header. See Mozilla Bugzilla #246651.
       */
      if (this.transport.overrideMimeType &&
          (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
            headers['Connection'] = 'close';
    }

    // user-defined headers
    if (typeof this.options.requestHeaders == 'object') {
      var extras = this.options.requestHeaders;

      if (Object.isFunction(extras.push))
        for (var i = 0, length = extras.length; i < length; i += 2)
          headers[extras[i]] = extras[i+1];
      else
        $H(extras).each(function(pair) { headers[pair.key] = pair.value });
    }

    for (var name in headers)
      this.transport.setRequestHeader(name, headers[name]);
  },

  success: function() {
    var status = this.getStatus();
    return !status || (status >= 200 && status < 300);
  },

  getStatus: function() {
    try {
      return this.transport.status || 0;
    } catch (e) { return 0 }
  },

  respondToReadyState: function(readyState) {
    var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this);

    if (state == 'Complete') {
      try {
        this._complete = true;
        (this.options['on' + response.status]
         || this.options['on' + (this.success() ? 'Success' : 'Failure')]
         || Prototype.emptyFunction)(response, response.headerJSON);
      } catch (e) {
        this.dispatchException(e);
      }

      var contentType = response.getHeader('Content-type');
      if (this.options.evalJS == 'force'
          || (this.options.evalJS && this.isSameOrigin() && contentType
          && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i)))
        this.evalResponse();
    }

    try {
      (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON);
      Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON);
    } catch (e) {
      this.dispatchException(e);
    }

    if (state == 'Complete') {
      // avoid memory leak in MSIE: clean up
      this.transport.onreadystatechange = Prototype.emptyFunction;
    }
  },

  isSameOrigin: function() {
    var m = this.url.match(/^\s*https?:\/\/[^\/]*/);
    return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({
      protocol: location.protocol,
      domain: document.domain,
      port: location.port ? ':' + location.port : ''
    }));
  },

  getHeader: function(name) {
    try {
      return this.transport.getResponseHeader(name) || null;
    } catch (e) { return null }
  },

  evalResponse: function() {
    try {
      return eval((this.transport.responseText || '').unfilterJSON());
    } catch (e) {
      this.dispatchException(e);
    }
  },

  dispatchException: function(exception) {
    (this.options.onException || Prototype.emptyFunction)(this, exception);
    Ajax.Responders.dispatch('onException', this, exception);
  }
});

Ajax.Request.Events =
  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
Ajax.Response = Class.create({
  initialize: function(request){
    this.request = request;
    var transport  = this.transport  = request.transport,
        readyState = this.readyState = transport.readyState;

    if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) {
      this.status       = this.getStatus();
      this.statusText   = this.getStatusText();
      this.responseText = String.interpret(transport.responseText);
      this.headerJSON   = this._getHeaderJSON();
    }

    if(readyState == 4) {
      var xml = transport.responseXML;
      this.responseXML  = Object.isUndefined(xml) ? null : xml;
      this.responseJSON = this._getResponseJSON();
    }
  },

  status:      0,
  statusText: '',

  getStatus: Ajax.Request.prototype.getStatus,

  getStatusText: function() {
    try {
      return this.transport.statusText || '';
    } catch (e) { return '' }
  },

  getHeader: Ajax.Request.prototype.getHeader,

  getAllHeaders: function() {
    try {
      return this.getAllResponseHeaders();
    } catch (e) { return null }
  },

  getResponseHeader: function(name) {
    return this.transport.getResponseHeader(name);
  },

  getAllResponseHeaders: function() {
    return this.transport.getAllResponseHeaders();
  },

  _getHeaderJSON: function() {
    var json = this.getHeader('X-JSON');
    if (!json) return null;
    json = decodeURIComponent(escape(json));
    try {
      return json.evalJSON(this.request.options.sanitizeJSON ||
        !this.request.isSameOrigin());
    } catch (e) {
      this.request.dispatchException(e);
    }
  },

  _getResponseJSON: function() {
    var options = this.request.options;
    if (!options.evalJSON || (options.evalJSON != 'force' &&
      !(this.getHeader('Content-type') || '').include('application/json')) ||
        this.responseText.blank())
          return null;
    try {
      return this.responseText.evalJSON(options.sanitizeJSON ||
        !this.request.isSameOrigin());
    } catch (e) {
      this.request.dispatchException(e);
    }
  }
});

Ajax.Updater = Class.create(Ajax.Request, {
  initialize: function($super, container, url, options) {
    this.container = {
      success: (container.success || container),
      failure: (container.failure || (container.success ? null : container))
    };

    options = Object.clone(options);
    var onComplete = options.onComplete;
    options.onComplete = (function(response, json) {
      this.updateContent(response.responseText);
      if (Object.isFunction(onComplete)) onComplete(response, json);
    }).bind(this);

    $super(url, options);
  },

  updateContent: function(responseText) {
    var receiver = this.container[this.success() ? 'success' : 'failure'],
        options = this.options;

    if (!options.evalScripts) responseText = responseText.stripScripts();

    if (receiver = $(receiver)) {
      if (options.insertion) {
        if (Object.isString(options.insertion)) {
          var insertion = { }; insertion[options.insertion] = responseText;
          receiver.insert(insertion);
        }
        else options.insertion(receiver, responseText);
      }
      else receiver.update(responseText);
    }
  }
});
Ajax.PeriodicalUpdater = Class.create(Ajax.Base, {
  initialize: function($super, container, url, options) {
    $super(options);
    this.onComplete = this.options.onComplete;

    this.frequency = (this.options.frequency || 2);
    this.decay = (this.options.decay || 1);

    this.updater = { };
    this.container = container;
    this.url = url;

    this.start();
  },

  start: function() {
    this.options.onComplete = this.updateComplete.bind(this);
    this.onTimerEvent();
  },

  stop: function() {
    this.updater.options.onComplete = undefined;
    clearTimeout(this.timer);
    (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
  },

  updateComplete: function(response) {
    if (this.options.decay) {
      this.decay = (response.responseText == this.lastText ?
        this.decay * this.options.decay : 1);

      this.lastText = response.responseText;
    }
    this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency);
  },

  onTimerEvent: function() {
    this.updater = new Ajax.Updater(this.container, this.url, this.options);
  }
});

function $(element) {
  if (arguments.length > 1) {
    for (var i = 0, elements = [], length = arguments.length; i < length; i++)
      elements.push($(arguments[i]));
    return elements;
  }
  if (Object.isString(element))
    element = document.getElementById(element);
  return Element.extend(element);
}

if (Prototype.BrowserFeatures.XPath) {
  document._getElementsByXPath = function(expression, parentElement) {
    var results = [];
    var query = document.evaluate(expression, $(parentElement) || document,
      null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
    for (var i = 0, length = query.snapshotLength; i < length; i++)
      results.push(Element.extend(query.snapshotItem(i)));
    return results;
  };
}

/*--------------------------------------------------------------------------*/

if (!window.Node) var Node = { };

if (!Node.ELEMENT_NODE) {
  // DOM level 2 ECMAScript Language Binding
  Object.extend(Node, {
    ELEMENT_NODE: 1,
    ATTRIBUTE_NODE: 2,
    TEXT_NODE: 3,
    CDATA_SECTION_NODE: 4,
    ENTITY_REFERENCE_NODE: 5,
    ENTITY_NODE: 6,
    PROCESSING_INSTRUCTION_NODE: 7,
    COMMENT_NODE: 8,
    DOCUMENT_NODE: 9,
    DOCUMENT_TYPE_NODE: 10,
    DOCUMENT_FRAGMENT_NODE: 11,
    NOTATION_NODE: 12
  });
}

(function(global) {
  var element = global.Element;
  global.Element = function(tagName, attributes) {
    attributes = attributes || { };
    tagName = tagName.toLowerCase();
    var cache = Element.cache;
    if (Prototype.Browser.IE && attributes.name) {
      tagName = '<' + tagName + ' name="' + attributes.name + '">';
      delete attributes.name;
      return Element.writeAttribute(document.createElement(tagName), attributes);
    }
    if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName));
    return Element.writeAttribute(cache[tagName].cloneNode(false), attributes);
  };
  Object.extend(global.Element, element || { });
  if (element) global.Element.prototype = element.prototype;
})(this);

Element.cache = { };
Element.idCounter = 1;

Element.Methods = {
  visible: function(element) {
    return $(element).style.display != 'none';
  },

  toggle: function(element) {
    element = $(element);
    Element[Element.visible(element) ? 'hide' : 'show'](element);
    return element;
  },

  hide: function(element) {
    element = $(element);
    element.style.display = 'none';
    return element;
  },

  show: function(element) {
    element = $(element);
    element.style.display = '';
    return element;
  },

  remove: function(element) {
    element = $(element);
    element.parentNode.removeChild(element);
    return element;
  },

  update: function(element, content) {
    element = $(element);
    if (content && content.toElement) content = content.toElement();
    if (Object.isElement(content)) return element.update().insert(content);
    content = Object.toHTML(content);
    element.innerHTML = content.stripScripts();
    content.evalScripts.bind(content).defer();
    return element;
  },

  replace: function(element, content) {
    element = $(element);
    if (content && content.toElement) content = content.toElement();
    else if (!Object.isElement(content)) {
      content = Object.toHTML(content);
      var range = element.ownerDocument.createRange();
      range.selectNode(element);
      content.evalScripts.bind(content).defer();
      content = range.createContextualFragment(content.stripScripts());
    }
    element.parentNode.replaceChild(content, element);
    return element;
  },

  insert: function(element, insertions) {
    element = $(element);

    if (Object.isString(insertions) || Object.isNumber(insertions) ||
        Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))
          insertions = {bottom:insertions};

    var content, insert, tagName, childNodes;

    for (var position in insertions) {
      content  = insertions[position];
      position = position.toLowerCase();
      insert = Element._insertionTranslations[position];

      if (content && content.toElement) content = content.toElement();
      if (Object.isElement(content)) {
        insert(element, content);
        continue;
      }

      content = Object.toHTML(content);

      tagName = ((position == 'before' || position == 'after')
        ? element.parentNode : element).tagName.toUpperCase();

      childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts());

      if (position == 'top' || position == 'after') childNodes.reverse();
      childNodes.each(insert.curry(element));

      content.evalScripts.bind(content).defer();
    }

    return element;
  },

  wrap: function(element, wrapper, attributes) {
    element = $(element);
    if (Object.isElement(wrapper))
      $(wrapper).writeAttribute(attributes || { });
    else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes);
    else wrapper = new Element('div', wrapper);
    if (element.parentNode)
      element.parentNode.replaceChild(wrapper, element);
    wrapper.appendChild(element);
    return wrapper;
  },

  inspect: function(element) {
    element = $(element);
    var result = '<' + element.tagName.toLowerCase();
    $H({'id': 'id', 'className': 'class'}).each(function(pair) {
      var property = pair.first(), attribute = pair.last();
      var value = (element[property] || '').toString();
      if (value) result += ' ' + attribute + '=' + value.inspect(true);
    });
    return result + '>';
  },

  recursivelyCollect: function(element, property) {
    element = $(element);
    var elements = [];
    while (element = element[property])
      if (element.nodeType == 1)
        elements.push(Element.extend(element));
    return elements;
  },

  ancestors: function(element) {
    return $(element).recursivelyCollect('parentNode');
  },

  descendants: function(element) {
    return $(element).select("*");
  },

  firstDescendant: function(element) {
    element = $(element).firstChild;
    while (element && element.nodeType != 1) element = element.nextSibling;
    return $(element);
  },

  immediateDescendants: function(element) {
    if (!(element = $(element).firstChild)) return [];
    while (element && element.nodeType != 1) element = element.nextSibling;
    if (element) return [element].concat($(element).nextSiblings());
    return [];
  },

  previousSiblings: function(element) {
    return $(element).recursivelyCollect('previousSibling');
  },

  nextSiblings: function(element) {
    return $(element).recursivelyCollect('nextSibling');
  },

  siblings: function(element) {
    element = $(element);
    return element.previousSiblings().reverse().concat(element.nextSiblings());
  },

  match: function(element, selector) {
    if (Object.isString(selector))
      selector = new Selector(selector);
    return selector.match($(element));
  },

  up: function(element, expression, index) {
    element = $(element);
    if (arguments.length == 1) return $(element.parentNode);
    var ancestors = element.ancestors();
    return Object.isNumber(expression) ? ancestors[expression] :
      Selector.findElement(ancestors, expression, index);
  },

  down: function(element, expression, index) {
    element = $(element);
    if (arguments.length == 1) return element.firstDescendant();
    return Object.isNumber(expression) ? element.descendants()[expression] :
      Element.select(element, expression)[index || 0];
  },

  previous: function(element, expression, index) {
    element = $(element);
    if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));
    var previousSiblings = element.previousSiblings();
    return Object.isNumber(expression) ? previousSiblings[expression] :
      Selector.findElement(previousSiblings, expression, index);
  },

  next: function(element, expression, index) {
    element = $(element);
    if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));
    var nextSiblings = element.nextSiblings();
    return Object.isNumber(expression) ? nextSiblings[expression] :
      Selector.findElement(nextSiblings, expression, index);
  },

  select: function() {
    var args = $A(arguments), element = $(args.shift());
    return Selector.findChildElements(element, args);
  },

  adjacent: function() {
    var args = $A(arguments), element = $(args.shift());
    return Selector.findChildElements(element.parentNode, args).without(element);
  },

  identify: function(element) {
    element = $(element);
    var id = element.readAttribute('id');
    if (id) return id;
    do { id = 'anonymous_element_' + Element.idCounter++ } while ($(id));
    element.writeAttribute('id', id);
    return id;
  },

  readAttribute: function(element, name) {
    element = $(element);
    if (Prototype.Browser.IE) {
      var t = Element._attributeTranslations.read;
      if (t.values[name]) return t.values[name](element, name);
      if (t.names[name]) name = t.names[name];
      if (name.include(':')) {
        return (!element.attributes || !element.attributes[name]) ? null :
         element.attributes[name].value;
      }
    }
    return element.getAttribute(name);
  },

  writeAttribute: function(element, name, value) {
    element = $(element);
    var attributes = { }, t = Element._attributeTranslations.write;

    if (typeof name == 'object') attributes = name;
    else attributes[name] = Object.isUndefined(value) ? true : value;

    for (var attr in attributes) {
      name = t.names[attr] || attr;
      value = attributes[attr];
      if (t.values[attr]) name = t.values[attr](element, value);
      if (value === false || value === null)
        element.removeAttribute(name);
      else if (value === true)
        element.setAttribute(name, name);
      else element.setAttribute(name, value);
    }
    return element;
  },

  getHeight: function(element) {
    return $(element).getDimensions().height;
  },

  getWidth: function(element) {
    return $(element).getDimensions().width;
  },

  classNames: function(element) {
    return new Element.ClassNames(element);
  },

  hasClassName: function(element, className) {
    if (!(element = $(element))) return;
    var elementClassName = element.className;
    return (elementClassName.length > 0 && (elementClassName == className ||
      new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName)));
  },

  addClassName: function(element, className) {
    if (!(element = $(element))) return;
    if (!element.hasClassName(className))
      element.className += (element.className ? ' ' : '') + className;
    return element;
  },

  removeClassName: function(element, className) {
    if (!(element = $(element))) return;
    element.className = element.className.replace(
      new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip();
    return element;
  },

  toggleClassName: function(element, className) {
    if (!(element = $(element))) return;
    return element[element.hasClassName(className) ?
      'removeClassName' : 'addClassName'](className);
  },

  // removes whitespace-only text node children
  cleanWhitespace: function(element) {
    element = $(element);
    var node = element.firstChild;
    while (node) {
      var nextNode = node.nextSibling;
      if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
        element.removeChild(node);
      node = nextNode;
    }
    return element;
  },

  empty: function(element) {
    return $(element).innerHTML.blank();
  },

  descendantOf: function(element, ancestor) {
    element = $(element), ancestor = $(ancestor);

    if (element.compareDocumentPosition)
      return (element.compareDocumentPosition(ancestor) & 8) === 8;

    if (ancestor.contains)
      return ancestor.contains(element) && ancestor !== element;

    while (element = element.parentNode)
      if (element == ancestor) return true;

    return false;
  },

  scrollTo: function(element) {
    element = $(element);
    var pos = element.cumulativeOffset();
    window.scrollTo(pos[0], pos[1]);
    return element;
  },

  getStyle: function(element, style) {
    element = $(element);
    style = style == 'float' ? 'cssFloat' : style.camelize();
    var value = element.style[style];
    if (!value || value == 'auto') {
      var css = document.defaultView.getComputedStyle(element, null);
      value = css ? css[style] : null;
    }
    if (style == 'opacity') return value ? parseFloat(value) : 1.0;
    return value == 'auto' ? null : value;
  },

  getOpacity: function(element) {
    return $(element).getStyle('opacity');
  },

  setStyle: function(element, styles) {
    element = $(element);
    var elementStyle = element.style, match;
    if (Object.isString(styles)) {
      element.style.cssText += ';' + styles;
      return styles.include('opacity') ?
        element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element;
    }
    for (var property in styles)
      if (property == 'opacity') element.setOpacity(styles[property]);
      else
        elementStyle[(property == 'float' || property == 'cssFloat') ?
          (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') :
            property] = styles[property];

    return element;
  },

  setOpacity: function(element, value) {
    element = $(element);
    element.style.opacity = (value == 1 || value === '') ? '' :
      (value < 0.00001) ? 0 : value;
    return element;
  },

  getDimensions: function(element) {
    element = $(element);
    var display = element.getStyle('display');
    if (display != 'none' && display != null) // Safari bug
      return {width: element.offsetWidth, height: element.offsetHeight};

    // All *Width and *Height properties give 0 on elements with display none,
    // so enable the element temporarily
    var els = element.style;
    var originalVisibility = els.visibility;
    var originalPosition = els.position;
    var originalDisplay = els.display;
    els.visibility = 'hidden';
    els.position = 'absolute';
    els.display = 'block';
    var originalWidth = element.clientWidth;
    var originalHeight = element.clientHeight;
    els.display = originalDisplay;
    els.position = originalPosition;
    els.visibility = originalVisibility;
    return {width: originalWidth, height: originalHeight};
  },

  makePositioned: function(element) {
    element = $(element);
    var pos = Element.getStyle(element, 'position');
    if (pos == 'static' || !pos) {
      element._madePositioned = true;
      element.style.position = 'relative';
      // Opera returns the offset relative to the positioning context, when an
      // element is position relative but top and left have not been defined
      if (Prototype.Browser.Opera) {
        element.style.top = 0;
        element.style.left = 0;
      }
    }
    return element;
  },

  undoPositioned: function(element) {
    element = $(element);
    if (element._madePositioned) {
      element._madePositioned = undefined;
      element.style.position =
        element.style.top =
        element.style.left =
        element.style.bottom =
        element.style.right = '';
    }
    return element;
  },

  makeClipping: function(element) {
    element = $(element);
    if (element._overflow) return element;
    element._overflow = Element.getStyle(element, 'overflow') || 'auto';
    if (element._overflow !== 'hidden')
      element.style.overflow = 'hidden';
    return element;
  },

  undoClipping: function(element) {
    element = $(element);
    if (!element._overflow) return element;
    element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
    element._overflow = null;
    return element;
  },

  cumulativeOffset: function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;
      element = element.offsetParent;
    } while (element);
    return Element._returnOffset(valueL, valueT);
  },

  positionedOffset: function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;
      element = element.offsetParent;
      if (element) {
        if (element.tagName.toUpperCase() == 'BODY') break;
        var p = Element.getStyle(element, 'position');
        if (p !== 'static') break;
      }
    } while (element);
    return Element._returnOffset(valueL, valueT);
  },

  absolutize: function(element) {
    element = $(element);
    if (element.getStyle('position') == 'absolute') return element;
    // Position.prepare(); // To be done manually by Scripty when it needs it.

    var offsets = element.positionedOffset();
    var top     = offsets[1];
    var left    = offsets[0];
    var width   = element.clientWidth;
    var height  = element.clientHeight;

    element._originalLeft   = left - parseFloat(element.style.left  || 0);
    element._originalTop    = top  - parseFloat(element.style.top || 0);
    element._originalWidth  = element.style.width;
    element._originalHeight = element.style.height;

    element.style.position = 'absolute';
    element.style.top    = top + 'px';
    element.style.left   = left + 'px';
    element.style.width  = width + 'px';
    element.style.height = height + 'px';
    return element;
  },

  relativize: function(element) {
    element = $(element);
    if (element.getStyle('position') == 'relative') return element;
    // Position.prepare(); // To be done manually by Scripty when it needs it.

    element.style.position = 'relative';
    var top  = parseFloat(element.style.top  || 0) - (element._originalTop || 0);
    var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);

    element.style.top    = top + 'px';
    element.style.left   = left + 'px';
    element.style.height = element._originalHeight;
    element.style.width  = element._originalWidth;
    return element;
  },

  cumulativeScrollOffset: function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.scrollTop  || 0;
      valueL += element.scrollLeft || 0;
      element = element.parentNode;
    } while (element);
    return Element._returnOffset(valueL, valueT);
  },

  getOffsetParent: function(element) {
    if (element.offsetParent) return $(element.offsetParent);
    if (element == document.body) return $(element);
	if(element.tagName.toUpperCase()=='HTML') //for IE6,7
	  return $(document.body);     
    while ((element = element.parentNode) && element != document.body)
      if (Element.getStyle(element, 'position') != 'static')
        return $(element);

    return $(document.body);
  },

  viewportOffset: function(forElement) {
    var valueT = 0, valueL = 0;

    var element = forElement;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;

      // Safari fix
      if (element.offsetParent == document.body &&
        Element.getStyle(element, 'position') == 'absolute') break;

    } while (element = element.offsetParent);

    element = forElement;
    do {
      if (!Prototype.Browser.Opera || (element.tagName && (element.tagName.toUpperCase() == 'BODY'))) {
        valueT -= element.scrollTop  || 0;
        valueL -= element.scrollLeft || 0;
      }
    } while (element = element.parentNode);

    return Element._returnOffset(valueL, valueT);
  },

  clonePosition: function(element, source) {
    var options = Object.extend({
      setLeft:    true,
      setTop:     true,
      setWidth:   true,
      setHeight:  true,
      offsetTop:  0,
      offsetLeft: 0
    }, arguments[2] || { });

    // find page position of source
    source = $(source);
    var p = source.viewportOffset();

    // find coordinate system to use
    element = $(element);
    var delta = [0, 0];
    var parent = null;
    // delta [0,0] will do fine with position: fixed elements,
    // position:absolute needs offsetParent deltas

    if (Element.getStyle(element, 'position') == 'absolute') {
      parent = element.getOffsetParent();
      delta = parent.viewportOffset();
    }

    // correct by body offsets (fixes Safari)
    if (parent == document.body) {
      delta[0] -= document.body.offsetLeft;
      delta[1] -= document.body.offsetTop;
    }

    // set position
    if (options.setLeft)   element.style.left  = (p[0] - delta[0] + options.offsetLeft) + 'px';
    if (options.setTop)    element.style.top   = (p[1] - delta[1] + options.offsetTop) + 'px';
    if (options.setWidth)  element.style.width = source.offsetWidth + 'px';
    if (options.setHeight) element.style.height = source.offsetHeight + 'px';
    return element;
  }
};

Object.extend(Element.Methods, {
  getElementsBySelector: Element.Methods.select,
  childElements: Element.Methods.immediateDescendants
});

Element._attributeTranslations = {
  write: {
    names: {
      className: 'class',
      htmlFor:   'for'
    },
    values: { }
  }
};

if (Prototype.Browser.Opera) {
  Element.Methods.getStyle = Element.Methods.getStyle.wrap(
    function(proceed, element, style) {
      switch (style) {
        case 'left': case 'top': case 'right': case 'bottom':
          if (proceed(element, 'position') === 'static') return null;
        case 'height': case 'width':
          // returns '0px' for hidden elements; we want it to return null
          if (!Element.visible(element)) return null;

          // returns the border-box dimensions rather than the content-box
          // dimensions, so we subtract padding and borders from the value
          var dim = parseInt(proceed(element, style), 10);

          if (dim !== element['offset' + style.capitalize()])
            return dim + 'px';

          var properties;
          if (style === 'height') {
            properties = ['border-top-width', 'padding-top',
             'padding-bottom', 'border-bottom-width'];
          }
          else {
            properties = ['border-left-width', 'padding-left',
             'padding-right', 'border-right-width'];
          }
          return properties.inject(dim, function(memo, property) {
            var val = proceed(element, property);
            return val === null ? memo : memo - parseInt(val, 10);
          }) + 'px';
        default: return proceed(element, style);
      }
    }
  );

  Element.Methods.readAttribute = Element.Methods.readAttribute.wrap(
    function(proceed, element, attribute) {
      if (attribute === 'title') return element.title;
      return proceed(element, attribute);
    }
  );
}

else if (Prototype.Browser.IE) {
  // IE doesn't report offsets correctly for static elements, so we change them
  // to "relative" to get the values, then change them back.
  Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap(
    function(proceed, element) {
      element = $(element);
      // IE throws an error if element is not in document
      try { element.offsetParent }
      catch(e) { return $(document.body) }
      var position = element.getStyle('position');
      if (position !== 'static') return proceed(element);
      element.setStyle({ position: 'relative' });
      var value = proceed(element);
      element.setStyle({ position: position });
      return value;
    }
  );

  $w('positionedOffset viewportOffset').each(function(method) {
    Element.Methods[method] = Element.Methods[method].wrap(
      function(proceed, element) {
        element = $(element);
        try { element.offsetParent }
        catch(e) { return Element._returnOffset(0,0) }
        var position = element.getStyle('position');
        if (position !== 'static') return proceed(element);
        // Trigger hasLayout on the offset parent so that IE6 reports
        // accurate offsetTop and offsetLeft values for position: fixed.
        var offsetParent = element.getOffsetParent();
        if (offsetParent && offsetParent.getStyle('position') === 'fixed')
          offsetParent.setStyle({ zoom: 1 });
        element.setStyle({ position: 'relative' });
        var value = proceed(element);
        element.setStyle({ position: position });
        return value;
      }
    );
  });

  Element.Methods.cumulativeOffset = Element.Methods.cumulativeOffset.wrap(
    function(proceed, element) {
      try { element.offsetParent }
      catch(e) { return Element._returnOffset(0,0) }
      return proceed(element);
    }
  );

  Element.Methods.getStyle = function(element, style) {
    element = $(element);
    style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();
    var value = element.style[style];
    if (!value && element.currentStyle) value = element.currentStyle[style];

    if (style == 'opacity') {
      if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
        if (value[1]) return parseFloat(value[1]) / 100;
      return 1.0;
    }

    if (value == 'auto') {
      if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none'))
        return element['offset' + style.capitalize()] + 'px';
      return null;
    }
    return value;
  };

  Element.Methods.setOpacity = function(element, value) {
    function stripAlpha(filter){
      return filter.replace(/alpha\([^\)]*\)/gi,'');
    }
    element = $(element);
    var currentStyle = element.currentStyle;
    if ((currentStyle && !currentStyle.hasLayout) ||
      (!currentStyle && element.style.zoom == 'normal'))
        element.style.zoom = 1;

    var filter = element.getStyle('filter'), style = element.style;
    if (value == 1 || value === '') {
      (filter = stripAlpha(filter)) ?
        style.filter = filter : style.removeAttribute('filter');
      return element;
    } else if (value < 0.00001) value = 0;
    style.filter = stripAlpha(filter) +
      'alpha(opacity=' + (value * 100) + ')';
    return element;
  };

  Element._attributeTranslations = {
    read: {
      names: {
        'class': 'className',
        'for':   'htmlFor'
      },
      values: {
        _getAttr: function(element, attribute) {
          return element.getAttribute(attribute, 2);
        },
        _getAttrNode: function(element, attribute) {
          var node = element.getAttributeNode(attribute);
          return node ? node.value : "";
        },
        _getEv: function(element, attribute) {
          attribute = element.getAttribute(attribute);
          return attribute ? attribute.toString().slice(23, -2) : null;
        },
        _flag: function(element, attribute) {
          return $(element).hasAttribute(attribute) ? attribute : null;
        },
        style: function(element) {
          return element.style.cssText.toLowerCase();
        },
        title: function(element) {
          return element.title;
        }
      }
    }
  };

  Element._attributeTranslations.write = {
    names: Object.extend({
      cellpadding: 'cellPadding',
      cellspacing: 'cellSpacing'
    }, Element._attributeTranslations.read.names),
    values: {
      checked: function(element, value) {
        element.checked = !!value;
      },

      style: function(element, value) {
        element.style.cssText = value ? value : '';
      }
    }
  };

  Element._attributeTranslations.has = {};

  $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' +
      'encType maxLength readOnly longDesc frameBorder').each(function(attr) {
    Element._attributeTranslations.write.names[attr.toLowerCase()] = attr;
    Element._attributeTranslations.has[attr.toLowerCase()] = attr;
  });

  (function(v) {
    Object.extend(v, {
      href:        v._getAttr,
      src:         v._getAttr,
      type:        v._getAttr,
      action:      v._getAttrNode,
      disabled:    v._flag,
      checked:     v._flag,
      readonly:    v._flag,
      multiple:    v._flag,
      onload:      v._getEv,
      onunload:    v._getEv,
      onclick:     v._getEv,
      ondblclick:  v._getEv,
      onmousedown: v._getEv,
      onmouseup:   v._getEv,
      onmouseover: v._getEv,
      onmousemove: v._getEv,
      onmouseout:  v._getEv,
      onfocus:     v._getEv,
      onblur:      v._getEv,
      onkeypress:  v._getEv,
      onkeydown:   v._getEv,
      onkeyup:     v._getEv,
      onsubmit:    v._getEv,
      onreset:     v._getEv,
      onselect:    v._getEv,
      onchange:    v._getEv
    });
  })(Element._attributeTranslations.read.values);
}

else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) {
  Element.Methods.setOpacity = function(element, value) {
    element = $(element);
    element.style.opacity = (value == 1) ? 0.999999 :
      (value === '') ? '' : (value < 0.00001) ? 0 : value;
    return element;
  };
}

else if (Prototype.Browser.WebKit) {
  Element.Methods.setOpacity = function(element, value) {
    element = $(element);
    element.style.opacity = (value == 1 || value === '') ? '' :
      (value < 0.00001) ? 0 : value;

    if (value == 1)
      if(element.tagName.toUpperCase() == 'IMG' && element.width) {
        element.width++; element.width--;
      } else try {
        var n = document.createTextNode(' ');
        element.appendChild(n);
        element.removeChild(n);
      } catch (e) { }

    return element;
  };

  // Safari returns margins on body which is incorrect if the child is absolutely
  // positioned.  For performance reasons, redefine Element#cumulativeOffset for
  // KHTML/WebKit only.
  Element.Methods.cumulativeOffset = function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;
      if (element.offsetParent == document.body)
        if (Element.getStyle(element, 'position') == 'absolute') break;

      element = element.offsetParent;
    } while (element);

    return Element._returnOffset(valueL, valueT);
  };
}

if (Prototype.Browser.IE || Prototype.Browser.Opera) {
  // IE and Opera are missing .innerHTML support for TABLE-related and SELECT elements
  Element.Methods.update = function(element, content) {
    element = $(element);

    if (content && content.toElement) content = content.toElement();
    if (Object.isElement(content)) return element.update().insert(content);

    content = Object.toHTML(content);
    var tagName = element.tagName.toUpperCase();

    if (tagName in Element._insertionTranslations.tags) {
      $A(element.childNodes).each(function(node) { element.removeChild(node) });
      Element._getContentFromAnonymousElement(tagName, content.stripScripts())
        .each(function(node) { element.appendChild(node) });
    }
    else element.innerHTML = content.stripScripts();

    content.evalScripts.bind(content).defer();
    return element;
  };
}

if ('outerHTML' in document.createElement('div')) {
  Element.Methods.replace = function(element, content) {
    element = $(element);

    if (content && content.toElement) content = content.toElement();
    if (Object.isElement(content)) {
      element.parentNode.replaceChild(content, element);
      return element;
    }

    content = Object.toHTML(content);
    var parent = element.parentNode, tagName = parent.tagName.toUpperCase();

    if (Element._insertionTranslations.tags[tagName]) {
      var nextSibling = element.next();
      var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
      parent.removeChild(element);
      if (nextSibling)
        fragments.each(function(node) { parent.insertBefore(node, nextSibling) });
      else
        fragments.each(function(node) { parent.appendChild(node) });
    }
    else element.outerHTML = content.stripScripts();

    content.evalScripts.bind(content).defer();
    return element;
  };
}

Element._returnOffset = function(l, t) {
  var result = [l, t];
  result.left = l;
  result.top = t;
  return result;
};

Element._getContentFromAnonymousElement = function(tagName, html) {
  var div = new Element('div'), t = Element._insertionTranslations.tags[tagName];
  if (t) {
    div.innerHTML = t[0] + html + t[1];
    t[2].times(function() { div = div.firstChild });
  } else div.innerHTML = html;
  return $A(div.childNodes);
};

Element._insertionTranslations = {
  before: function(element, node) {
    element.parentNode.insertBefore(node, element);
  },
  top: function(element, node) {
    element.insertBefore(node, element.firstChild);
  },
  bottom: function(element, node) {
    element.appendChild(node);
  },
  after: function(element, node) {
    element.parentNode.insertBefore(node, element.nextSibling);
  },
  tags: {
    TABLE:  ['<table>',                '</table>',                   1],
    TBODY:  ['<table><tbody>',         '</tbody></table>',           2],
    TR:     ['<table><tbody><tr>',     '</tr></tbody></table>',      3],
    TD:     ['<table><tbody><tr><td>', '</td></tr></tbody></table>', 4],
    SELECT: ['<select>',               '</select>',                  1]
  }
};

(function() {
  Object.extend(this.tags, {
    THEAD: this.tags.TBODY,
    TFOOT: this.tags.TBODY,
    TH:    this.tags.TD
  });
}).call(Element._insertionTranslations);

Element.Methods.Simulated = {
  hasAttribute: function(element, attribute) {
    attribute = Element._attributeTranslations.has[attribute] || attribute;
    var node = $(element).getAttributeNode(attribute);
    return !!(node && node.specified);
  }
};

Element.Methods.ByTag = { };

Object.extend(Element, Element.Methods);

if (!Prototype.BrowserFeatures.ElementExtensions &&
    document.createElement('div')['__proto__']) {
  window.HTMLElement = { };
  window.HTMLElement.prototype = document.createElement('div')['__proto__'];
  Prototype.BrowserFeatures.ElementExtensions = true;
}

Element.extend = (function() {
  if (Prototype.BrowserFeatures.SpecificElementExtensions)
    return Prototype.K;

  var Methods = { }, ByTag = Element.Methods.ByTag;

  var extend = Object.extend(function(element) {
    if (!element || element._extendedByPrototype ||
        element.nodeType != 1 || element == window) return element;

    var methods = Object.clone(Methods),
      tagName = element.tagName.toUpperCase(), property, value;

    // extend methods for specific tags
    if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);

    for (property in methods) {
      value = methods[property];
      if (Object.isFunction(value) && !(property in element))
        element[property] = value.methodize();
    }

    element._extendedByPrototype = Prototype.emptyFunction;
    return element;

  }, {
    refresh: function() {
      // extend methods for all tags (Safari doesn't need this)
      if (!Prototype.BrowserFeatures.ElementExtensions) {
        Object.extend(Methods, Element.Methods);
        Object.extend(Methods, Element.Methods.Simulated);
      }
    }
  });

  extend.refresh();
  return extend;
})();

Element.hasAttribute = function(element, attribute) {
  if (element.hasAttribute) return element.hasAttribute(attribute);
  return Element.Methods.Simulated.hasAttribute(element, attribute);
};

Element.addMethods = function(methods) {
  var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag;

  if (!methods) {
    Object.extend(Form, Form.Methods);
    Object.extend(Form.Element, Form.Element.Methods);
    Object.extend(Element.Methods.ByTag, {
      "FORM":     Object.clone(Form.Methods),
      "INPUT":    Object.clone(Form.Element.Methods),
      "SELECT":   Object.clone(Form.Element.Methods),
      "TEXTAREA": Object.clone(Form.Element.Methods)
    });
  }

  if (arguments.length == 2) {
    var tagName = methods;
    methods = arguments[1];
  }

  if (!tagName) Object.extend(Element.Methods, methods || { });
  else {
    if (Object.isArray(tagName)) tagName.each(extend);
    else extend(tagName);
  }

  function extend(tagName) {
    tagName = tagName.toUpperCase();
    if (!Element.Methods.ByTag[tagName])
      Element.Methods.ByTag[tagName] = { };
    Object.extend(Element.Methods.ByTag[tagName], methods);
  }

  function copy(methods, destination, onlyIfAbsent) {
    onlyIfAbsent = onlyIfAbsent || false;
    for (var property in methods) {
      var value = methods[property];
      if (!Object.isFunction(value)) continue;
      if (!onlyIfAbsent || !(property in destination))
        destination[property] = value.methodize();
    }
  }

  function findDOMClass(tagName) {
    var klass;
    var trans = {
      "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",
      "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",
      "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",
      "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",
      "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":
      "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":
      "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":
      "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":
      "FrameSet", "IFRAME": "IFrame"
    };
    if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';
    if (window[klass]) return window[klass];
    klass = 'HTML' + tagName + 'Element';
    if (window[klass]) return window[klass];
    klass = 'HTML' + tagName.capitalize() + 'Element';
    if (window[klass]) return window[klass];

    window[klass] = { };
    window[klass].prototype = document.createElement(tagName)['__proto__'];
    return window[klass];
  }

  if (F.ElementExtensions) {
    copy(Element.Methods, HTMLElement.prototype);
    copy(Element.Methods.Simulated, HTMLElement.prototype, true);
  }

  if (F.SpecificElementExtensions) {
    for (var tag in Element.Methods.ByTag) {
      var klass = findDOMClass(tag);
      if (Object.isUndefined(klass)) continue;
      copy(T[tag], klass.prototype);
    }
  }

  Object.extend(Element, Element.Methods);
  delete Element.ByTag;

  if (Element.extend.refresh) Element.extend.refresh();
  Element.cache = { };
};

document.viewport = {
  getDimensions: function() {
    return { width: this.getWidth(), height: this.getHeight() };
  },

  getScrollOffsets: function() {
    return Element._returnOffset(
      window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,
      window.pageYOffset || document.documentElement.scrollTop  || document.body.scrollTop);
  }
};

(function(viewport) {
  var B = Prototype.Browser, doc = document, element, property = {};

  function getRootElement() {
    // Older versions of Safari.
    if (B.WebKit && !doc.evaluate)
      return document;

    // Older versions of Opera.
    if (B.Opera && window.parseFloat(window.opera.version()) < 9.5)
      return document.body;

    return document.documentElement;
  }

  function define(D) {
    if (!element) element = getRootElement();

    property[D] = 'client' + D;

    viewport['get' + D] = function() { return element[property[D]] };
    return viewport['get' + D]();
  }

  viewport.getWidth  = define.curry('Width');
  viewport.getHeight = define.curry('Height');
})(document.viewport);


Element.Storage = {
  UID: 1
};

Element.addMethods({
  getStorage: function(element) {
    if (!(element = $(element))) return;

    var uid;
    if (element === window) {
      uid = 0;
    } else {
      if (Object.isUndefined(element._prototypeUID))
        element._prototypeUID = [Element.Storage.UID++];
      uid = element._prototypeUID[0];
    }

    if (!Element.Storage[uid])
      Element.Storage[uid] = $H();

    return Element.Storage[uid];
  },

  store: function(element, key, value) {
    if (!(element = $(element))) return;

    if (arguments.length === 2) {
      // Assume we've been passed an object full of key/value pairs.
      element.getStorage().update(key);
    } else {
      element.getStorage().set(key, value);
    }

    return element;
  },

  retrieve: function(element, key, defaultValue) {
    if (!(element = $(element))) return;
    var hash = Element.getStorage(element), value = hash.get(key);

    if (Object.isUndefined(value)) {
      hash.set(key, defaultValue);
      value = defaultValue;
    }

    return value;
  }
});
/* Portions of the Selector class are derived from Jack Slocum's DomQuery,
 * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style
 * license.  Please see http://www.yui-ext.com/ for more information. */

var Selector = Class.create({
  initialize: function(expression) {
    this.expression = expression.strip();

    if (this.shouldUseSelectorsAPI()) {
      this.mode = 'selectorsAPI';
    } else if (this.shouldUseXPath()) {
      this.mode = 'xpath';
      this.compileXPathMatcher();
    } else {
      this.mode = "normal";
      this.compileMatcher();
    }

  },

  shouldUseXPath: function() {
    if (!Prototype.BrowserFeatures.XPath) return false;

    var e = this.expression;

    // Safari 3 chokes on :*-of-type and :empty
    if (Prototype.Browser.WebKit &&
     (e.include("-of-type") || e.include(":empty")))
      return false;

    // XPath can't do namespaced attributes, nor can it read
    // the "checked" property from DOM nodes
    if ((/(\[[\w-]*?:|:checked)/).test(e))
      return false;

    return true;
  },

  shouldUseSelectorsAPI: function() {
    if (!Prototype.BrowserFeatures.SelectorsAPI) return false;

    if (Selector.CASE_INSENSITIVE_CLASS_NAMES) return false;

    if (!Selector._div) Selector._div = new Element('div');

    // Make sure the browser treats the selector as valid. Test on an
    // isolated element to minimize cost of this check.
    try {
      Selector._div.querySelector(this.expression);
    } catch(e) {
      return false;
    }

    return true;
  },

  compileMatcher: function() {
    var e = this.expression, ps = Selector.patterns, h = Selector.handlers,
        c = Selector.criteria, le, p, m, len = ps.length, name;

    if (Selector._cache[e]) {
      this.matcher = Selector._cache[e];
      return;
    }

    this.matcher = ["this.matcher = function(root) {",
                    "var r = root, h = Selector.handlers, c = false, n;"];

    while (e && le != e && (/\S/).test(e)) {
      le = e;
      for (var i = 0; i<len; i++) {
        p = ps[i].re;
        name = ps[i].name;
        if (m = e.match(p)) {
          this.matcher.push(Object.isFunction(c[name]) ? c[name](m) :
            new Template(c[name]).evaluate(m));
          e = e.replace(m[0], '');
          break;
        }
      }
    }

    this.matcher.push("return h.unique(n);\n}");
    eval(this.matcher.join('\n'));
    Selector._cache[this.expression] = this.matcher;
  },

  compileXPathMatcher: function() {
    var e = this.expression, ps = Selector.patterns,
        x = Selector.xpath, le, m, len = ps.length, name;

    if (Selector._cache[e]) {
      this.xpath = Selector._cache[e]; return;
    }

    this.matcher = ['.//*'];
    while (e && le != e && (/\S/).test(e)) {
      le = e;
      for (var i = 0; i<len; i++) {
        name = ps[i].name;
        if (m = e.match(ps[i].re)) {
          this.matcher.push(Object.isFunction(x[name]) ? x[name](m) :
            new Template(x[name]).evaluate(m));
          e = e.replace(m[0], '');
          break;
        }
      }
    }

    this.xpath = this.matcher.join('');
    Selector._cache[this.expression] = this.xpath;
  },

  findElements: function(root) {
    root = root || document;
    var e = this.expression, results;

    switch (this.mode) {
      case 'selectorsAPI':
        // querySelectorAll queries document-wide, then filters to descendants
        // of the context element. That's not what we want.
        // Add an explicit context to the selector if necessary.
        if (root !== document) {
          var oldId = root.id, id = $(root).identify();
    //      id = id.replace(/[\.:]/g, "\\$0");
		  id = id.replace(/([\.:])/g, "\\$1");
          e = "#" + id + " " + e;
        }

        results = $A(root.querySelectorAll(e)).map(Element.extend);
        root.id = oldId;

        return results;
      case 'xpath':
        return document._getElementsByXPath(this.xpath, root);
      default:
       return this.matcher(root);
    }
  },

  match: function(element) {
    this.tokens = [];

    var e = this.expression, ps = Selector.patterns, as = Selector.assertions;
    var le, p, m, len = ps.length, name;

    while (e && le !== e && (/\S/).test(e)) {
      le = e;
      for (var i = 0; i<len; i++) {
        p = ps[i].re;
        name = ps[i].name;
        if (m = e.match(p)) {
          // use the Selector.assertions methods unless the selector
          // is too complex.
          if (as[name]) {
            this.tokens.push([name, Object.clone(m)]);
            e = e.replace(m[0], '');
          } else {
            // reluctantly do a document-wide search
            // and look for a match in the array
            return this.findElements(document).include(element);
          }
        }
      }
    }

    var match = true, name, matches;
    for (var i = 0, token; token = this.tokens[i]; i++) {
      name = token[0], matches = token[1];
      if (!Selector.assertions[name](element, matches)) {
        match = false; break;
      }
    }

    return match;
  },

  toString: function() {
    return this.expression;
  },

  inspect: function() {
    return "#<Selector:" + this.expression.inspect() + ">";
  }
});

if (Prototype.BrowserFeatures.SelectorsAPI &&
 document.compatMode === 'BackCompat') {
  // Versions of Safari 3 before 3.1.2 treat class names case-insensitively in
  // quirks mode. If we detect this behavior, we should use a different
  // approach.
  Selector.CASE_INSENSITIVE_CLASS_NAMES = (function(){
    var div = document.createElement('div'),
     span = document.createElement('span');

    div.id = "prototype_test_id";
    span.className = 'Test';
    div.appendChild(span);
    var isIgnored = (div.querySelector('#prototype_test_id .test') !== null);
    div = span = null;
    return isIgnored;
  })();
}

Object.extend(Selector, {
  _cache: { },

  xpath: {
    descendant:   "//*",
    child:        "/*",
    adjacent:     "/following-sibling::*[1]",
    laterSibling: '/following-sibling::*',
    tagName:      function(m) {
      if (m[1] == '*') return '';
      return "[local-name()='" + m[1].toLowerCase() +
             "' or local-name()='" + m[1].toUpperCase() + "']";
    },
    className:    "[contains(concat(' ', @class, ' '), ' #{1} ')]",
    id:           "[@id='#{1}']",
    attrPresence: function(m) {
      m[1] = m[1].toLowerCase();
      return new Template("[@#{1}]").evaluate(m);
    },
    attr: function(m) {
      m[1] = m[1].toLowerCase();
      m[3] = m[5] || m[6];
      return new Template(Selector.xpath.operators[m[2]]).evaluate(m);
    },
    pseudo: function(m) {
      var h = Selector.xpath.pseudos[m[1]];
      if (!h) return '';
      if (Object.isFunction(h)) return h(m);
      return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m);
    },
    operators: {
      '=':  "[@#{1}='#{3}']",
      '!=': "[@#{1}!='#{3}']",
      '^=': "[starts-with(@#{1}, '#{3}')]",
      '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']",
      '*=': "[contains(@#{1}, '#{3}')]",
      '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]",
      '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]"
    },
    pseudos: {
      'first-child': '[not(preceding-sibling::*)]',
      'last-child':  '[not(following-sibling::*)]',
      'only-child':  '[not(preceding-sibling::* or following-sibling::*)]',
      'empty':       "[count(*) = 0 and (count(text()) = 0)]",
      'checked':     "[@checked]",
      'disabled':    "[(@disabled) and (@type!='hidden')]",
      'enabled':     "[not(@disabled) and (@type!='hidden')]",
      'not': function(m) {
        var e = m[6], p = Selector.patterns,
            x = Selector.xpath, le, v, len = p.length, name;

        var exclusion = [];
        while (e && le != e && (/\S/).test(e)) {
          le = e;
          for (var i = 0; i<len; i++) {
            name = p[i].name
            if (m = e.match(p[i].re)) {
              v = Object.isFunction(x[name]) ? x[name](m) : new Template(x[name]).evaluate(m);
              exclusion.push("(" + v.substring(1, v.length - 1) + ")");
              e = e.replace(m[0], '');
              break;
            }
          }
        }
        return "[not(" + exclusion.join(" and ") + ")]";
      },
      'nth-child':      function(m) {
        return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m);
      },
      'nth-last-child': function(m) {
        return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m);
      },
      'nth-of-type':    function(m) {
        return Selector.xpath.pseudos.nth("position() ", m);
      },
      'nth-last-of-type': function(m) {
        return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m);
      },
      'first-of-type':  function(m) {
        m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m);
      },
      'last-of-type':   function(m) {
        m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m);
      },
      'only-of-type':   function(m) {
        var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m);
      },
      nth: function(fragment, m) {
        var mm, formula = m[6], predicate;
        if (formula == 'even') formula = '2n+0';
        if (formula == 'odd')  formula = '2n+1';
        if (mm = formula.match(/^(\d+)$/)) // digit only
          return '[' + fragment + "= " + mm[1] + ']';
        if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
          if (mm[1] == "-") mm[1] = -1;
          var a = mm[1] ? Number(mm[1]) : 1;
          var b = mm[2] ? Number(mm[2]) : 0;
          predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " +
          "((#{fragment} - #{b}) div #{a} >= 0)]";
          return new Template(predicate).evaluate({
            fragment: fragment, a: a, b: b });
        }
      }
    }
  },

  criteria: {
    tagName:      'n = h.tagName(n, r, "#{1}", c);      c = false;',
    className:    'n = h.className(n, r, "#{1}", c);    c = false;',
    id:           'n = h.id(n, r, "#{1}", c);           c = false;',
    attrPresence: 'n = h.attrPresence(n, r, "#{1}", c); c = false;',
    attr: function(m) {
      m[3] = (m[5] || m[6]);
      return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); c = false;').evaluate(m);
    },
    pseudo: function(m) {
      if (m[6]) m[6] = m[6].replace(/"/g, '\\"');
      return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m);
    },
    descendant:   'c = "descendant";',
    child:        'c = "child";',
    adjacent:     'c = "adjacent";',
    laterSibling: 'c = "laterSibling";'
  },

  patterns: [
    // combinators must be listed first
    // (and descendant needs to be last combinator)
    { name: 'laterSibling', re: /^\s*~\s*/ },
    { name: 'child',        re: /^\s*>\s*/ },
    { name: 'adjacent',     re: /^\s*\+\s*/ },
    { name: 'descendant',   re: /^\s/ },

    // selectors follow
    { name: 'tagName',      re: /^\s*(\*|[\w\-]+)(\b|$)?/ },
    { name: 'id',           re: /^#([\w\-\*]+)(\b|$)/ },
    { name: 'className',    re: /^\.([\w\-\*]+)(\b|$)/ },
    { name: 'pseudo',       re: /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/ },
    { name: 'attrPresence', re: /^\[((?:[\w]+:)?[\w]+)\]/ },
    { name: 'attr',         re: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/ }
  ],

  // for Selector.match and Element#match
  assertions: {
    tagName: function(element, matches) {
      return matches[1].toUpperCase() == element.tagName.toUpperCase();
    },

    className: function(element, matches) {
      return Element.hasClassName(element, matches[1]);
    },

    id: function(element, matches) {
      return element.id === matches[1];
    },

    attrPresence: function(element, matches) {
      return Element.hasAttribute(element, matches[1]);
    },

    attr: function(element, matches) {
      var nodeValue = Element.readAttribute(element, matches[1]);
      return nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]);
    }
  },

  handlers: {
    // UTILITY FUNCTIONS
    // joins two collections
    concat: function(a, b) {
      for (var i = 0, node; node = b[i]; i++)
        a.push(node);
      return a;
    },

    // marks an array of nodes for counting
    mark: function(nodes) {
      var _true = Prototype.emptyFunction;
      for (var i = 0, node; node = nodes[i]; i++)
        node._countedByPrototype = _true;
      return nodes;
    },

    unmark: function(nodes) {
      for (var i = 0, node; node = nodes[i]; i++)
        node._countedByPrototype = undefined;
      return nodes;
    },

    // mark each child node with its position (for nth calls)
    // "ofType" flag indicates whether we're indexing for nth-of-type
    // rather than nth-child
    index: function(parentNode, reverse, ofType) {
      parentNode._countedByPrototype = Prototype.emptyFunction;
      if (reverse) {
        for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) {
          var node = nodes[i];
          if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;
        }
      } else {
        for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++)
          if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;
      }
    },

    // filters out duplicates and extends all nodes
    unique: function(nodes) {
      if (nodes.length == 0) return nodes;
      var results = [], n;
      for (var i = 0, l = nodes.length; i < l; i++)
        if (!(n = nodes[i])._countedByPrototype) {
          n._countedByPrototype = Prototype.emptyFunction;
          results.push(Element.extend(n));
        }
      return Selector.handlers.unmark(results);
    },

    // COMBINATOR FUNCTIONS
    descendant: function(nodes) {
      var h = Selector.handlers;
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        h.concat(results, node.getElementsByTagName('*'));
      return results;
    },

    child: function(nodes) {
      var h = Selector.handlers;
      for (var i = 0, results = [], node; node = nodes[i]; i++) {
        for (var j = 0, child; child = node.childNodes[j]; j++)
          if (child.nodeType == 1 && child.tagName != '!') results.push(child);
      }
      return results;
    },

    adjacent: function(nodes) {
      for (var i = 0, results = [], node; node = nodes[i]; i++) {
        var next = this.nextElementSibling(node);
        if (next) results.push(next);
      }
      return results;
    },

    laterSibling: function(nodes) {
      var h = Selector.handlers;
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        h.concat(results, Element.nextSiblings(node));
      return results;
    },

    nextElementSibling: function(node) {
      while (node = node.nextSibling)
        if (node.nodeType == 1) return node;
      return null;
    },

    previousElementSibling: function(node) {
      while (node = node.previousSibling)
        if (node.nodeType == 1) return node;
      return null;
    },

    // TOKEN FUNCTIONS
    tagName: function(nodes, root, tagName, combinator) {
      var uTagName = tagName.toUpperCase();
      var results = [], h = Selector.handlers;
      if (nodes) {
        if (combinator) {
          // fastlane for ordinary descendant combinators
          if (combinator == "descendant") {
            for (var i = 0, node; node = nodes[i]; i++)
              h.concat(results, node.getElementsByTagName(tagName));
            return results;
          } else nodes = this[combinator](nodes);
          if (tagName == "*") return nodes;
        }
        for (var i = 0, node; node = nodes[i]; i++)
          if (node.tagName.toUpperCase() === uTagName) results.push(node);
        return results;
      } else return root.getElementsByTagName(tagName);
    },

    id: function(nodes, root, id, combinator) {
      var targetNode = $(id), h = Selector.handlers;
      if (!targetNode) return [];
      if (!nodes && root == document) return [targetNode];
      if (nodes) {
        if (combinator) {
          if (combinator == 'child') {
            for (var i = 0, node; node = nodes[i]; i++)
              if (targetNode.parentNode == node) return [targetNode];
          } else if (combinator == 'descendant') {
            for (var i = 0, node; node = nodes[i]; i++)
              if (Element.descendantOf(targetNode, node)) return [targetNode];
          } else if (combinator == 'adjacent') {
            for (var i = 0, node; node = nodes[i]; i++)
              if (Selector.handlers.previousElementSibling(targetNode) == node)
                return [targetNode];
          } else nodes = h[combinator](nodes);
        }
        for (var i = 0, node; node = nodes[i]; i++)
          if (node == targetNode) return [targetNode];
        return [];
      }
      return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : [];
    },

    className: function(nodes, root, className, combinator) {
      if (nodes && combinator) nodes = this[combinator](nodes);
      return Selector.handlers.byClassName(nodes, root, className);
    },

    byClassName: function(nodes, root, className) {
      if (!nodes) nodes = Selector.handlers.descendant([root]);
      var needle = ' ' + className + ' ';
      for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) {
        nodeClassName = node.className;
        if (nodeClassName.length == 0) continue;
        if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle))
          results.push(node);
      }
      return results;
    },

    attrPresence: function(nodes, root, attr, combinator) {
      if (!nodes) nodes = root.getElementsByTagName("*");
      if (nodes && combinator) nodes = this[combinator](nodes);
      var results = [];
      for (var i = 0, node; node = nodes[i]; i++)
        if (Element.hasAttribute(node, attr)) results.push(node);
      return results;
    },

    attr: function(nodes, root, attr, value, operator, combinator) {
      if (!nodes) nodes = root.getElementsByTagName("*");
      if (nodes && combinator) nodes = this[combinator](nodes);
      var handler = Selector.operators[operator], results = [];
      for (var i = 0, node; node = nodes[i]; i++) {
        var nodeValue = Element.readAttribute(node, attr);
        if (nodeValue === null) continue;
        if (handler(nodeValue, value)) results.push(node);
      }
      return results;
    },

    pseudo: function(nodes, name, value, root, combinator) {
      if (nodes && combinator) nodes = this[combinator](nodes);
      if (!nodes) nodes = root.getElementsByTagName("*");
      return Selector.pseudos[name](nodes, value, root);
    }
  },

  pseudos: {
    'first-child': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++) {
        if (Selector.handlers.previousElementSibling(node)) continue;
          results.push(node);
      }
      return results;
    },
    'last-child': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++) {
        if (Selector.handlers.nextElementSibling(node)) continue;
          results.push(node);
      }
      return results;
    },
    'only-child': function(nodes, value, root) {
      var h = Selector.handlers;
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        if (!h.previousElementSibling(node) && !h.nextElementSibling(node))
          results.push(node);
      return results;
    },
    'nth-child':        function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, formula, root);
    },
    'nth-last-child':   function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, formula, root, true);
    },
    'nth-of-type':      function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, formula, root, false, true);
    },
    'nth-last-of-type': function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, formula, root, true, true);
    },
    'first-of-type':    function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, "1", root, false, true);
    },
    'last-of-type':     function(nodes, formula, root) {
      return Selector.pseudos.nth(nodes, "1", root, true, true);
    },
    'only-of-type':     function(nodes, formula, root) {
      var p = Selector.pseudos;
      return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root);
    },

    // handles the an+b logic
    getIndices: function(a, b, total) {
      if (a == 0) return b > 0 ? [b] : [];
      return $R(1, total).inject([], function(memo, i) {
        if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i);
        return memo;
      });
    },

    // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type
    nth: function(nodes, formula, root, reverse, ofType) {
      if (nodes.length == 0) return [];
      if (formula == 'even') formula = '2n+0';
      if (formula == 'odd')  formula = '2n+1';
      var h = Selector.handlers, results = [], indexed = [], m;
      h.mark(nodes);
      for (var i = 0, node; node = nodes[i]; i++) {
        if (!node.parentNode._countedByPrototype) {
          h.index(node.parentNode, reverse, ofType);
          indexed.push(node.parentNode);
        }
      }
      if (formula.match(/^\d+$/)) { // just a number
        formula = Number(formula);
        for (var i = 0, node; node = nodes[i]; i++)
          if (node.nodeIndex == formula) results.push(node);
      } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
        if (m[1] == "-") m[1] = -1;
        var a = m[1] ? Number(m[1]) : 1;
        var b = m[2] ? Number(m[2]) : 0;
        var indices = Selector.pseudos.getIndices(a, b, nodes.length);
        for (var i = 0, node, l = indices.length; node = nodes[i]; i++) {
          for (var j = 0; j < l; j++)
            if (node.nodeIndex == indices[j]) results.push(node);
        }
      }
      h.unmark(nodes);
      h.unmark(indexed);
      return results;
    },

    'empty': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++) {
        // IE treats comments as element nodes
        if (node.tagName == '!' || node.firstChild) continue;
        results.push(node);
      }
      return results;
    },

    'not': function(nodes, selector, root) {
      var h = Selector.handlers, selectorType, m;
      var exclusions = new Selector(selector).findElements(root);
      h.mark(exclusions);
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        if (!node._countedByPrototype) results.push(node);
      h.unmark(exclusions);
      return results;
    },

    'enabled': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        if (!node.disabled && (!node.type || node.type !== 'hidden'))
          results.push(node);
      return results;
    },

    'disabled': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        if (node.disabled) results.push(node);
      return results;
    },

    'checked': function(nodes, value, root) {
      for (var i = 0, results = [], node; node = nodes[i]; i++)
        if (node.checked) results.push(node);
      return results;
    }
  },

  operators: {
    '=':  function(nv, v) { return nv == v; },
    '!=': function(nv, v) { return nv != v; },
    '^=': function(nv, v) { return nv == v || nv && nv.startsWith(v); },
    '$=': function(nv, v) { return nv == v || nv && nv.endsWith(v); },
    '*=': function(nv, v) { return nv == v || nv && nv.include(v); },
    '$=': function(nv, v) { return nv.endsWith(v); },
    '*=': function(nv, v) { return nv.include(v); },
    '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); },
    '|=': function(nv, v) { return ('-' + (nv || "").toUpperCase() +
     '-').include('-' + (v || "").toUpperCase() + '-'); }
  },

  split: function(expression) {
    var expressions = [];
    expression.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
      expressions.push(m[1].strip());
    });
    return expressions;
  },

  matchElements: function(elements, expression) {
    var matches = $$(expression), h = Selector.handlers;
    h.mark(matches);
    for (var i = 0, results = [], element; element = elements[i]; i++)
      if (element._countedByPrototype) results.push(element);
    h.unmark(matches);
    return results;
  },

  findElement: function(elements, expression, index) {
    if (Object.isNumber(expression)) {
      index = expression; expression = false;
    }
    return Selector.matchElements(elements, expression || '*')[index || 0];
  },

  findChildElements: function(element, expressions) {
    expressions = Selector.split(expressions.join(','));
    var results = [], h = Selector.handlers;
    for (var i = 0, l = expressions.length, selector; i < l; i++) {
      selector = new Selector(expressions[i].strip());
      h.concat(results, selector.findElements(element));
    }
    return (l > 1) ? h.unique(results) : results;
  }
});

if (Prototype.Browser.IE) {
  Object.extend(Selector.handlers, {
    // IE returns comment nodes on getElementsByTagName("*").
    // Filter them out.
    concat: function(a, b) {
      for (var i = 0, node; node = b[i]; i++)
        if (node.tagName !== "!") a.push(node);
      return a;
    },

    // IE improperly serializes _countedByPrototype in (inner|outer)HTML.
    unmark: function(nodes) {
      for (var i = 0, node; node = nodes[i]; i++)
        node.removeAttribute('_countedByPrototype');
      return nodes;
    }
  });
}

function $$() {
  return Selector.findChildElements(document, $A(arguments));
}
var Form = {
  reset: function(form) {
    $(form).reset();
    return form;
  },

  serializeElements: function(elements, options) {
    if (typeof options != 'object') options = { hash: !!options };
    else if (Object.isUndefined(options.hash)) options.hash = true;
    var key, value, submitted = false, submit = options.submit;

    var data = elements.inject({ }, function(result, element) {
      if (!element.disabled && element.name) {
        key = element.name; value = $(element).getValue();
        if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted &&
            submit !== false && (!submit || key == submit) && (submitted = true)))) {
          if (key in result) {
            // a key is already present; construct an array of values
            if (!Object.isArray(result[key])) result[key] = [result[key]];
            result[key].push(value);
          }
          else result[key] = value;
        }
      }
      return result;
    });

    return options.hash ? data : Object.toQueryString(data);
  }
};

Form.Methods = {
  serialize: function(form, options) {
    return Form.serializeElements(Form.getElements(form), options);
  },

  getElements: function(form) {
    return $A($(form).getElementsByTagName('*')).inject([],
      function(elements, child) {
        if (Form.Element.Serializers[child.tagName.toLowerCase()])
          elements.push(Element.extend(child));
        return elements;
      }
    );
  },

  getInputs: function(form, typeName, name) {
    form = $(form);
    var inputs = form.getElementsByTagName('input');

    if (!typeName && !name) return $A(inputs).map(Element.extend);

    for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
      var input = inputs[i];
      if ((typeName && input.type != typeName) || (name && input.name != name))
        continue;
      matchingInputs.push(Element.extend(input));
    }

    return matchingInputs;
  },

  disable: function(form) {
    form = $(form);
    Form.getElements(form).invoke('disable');
    return form;
  },

  enable: function(form) {
    form = $(form);
    Form.getElements(form).invoke('enable');
    return form;
  },

  findFirstElement: function(form) {
    var elements = $(form).getElements().findAll(function(element) {
      return 'hidden' != element.type && !element.disabled;
    });
    var firstByIndex = elements.findAll(function(element) {
      return element.hasAttribute('tabIndex') && element.tabIndex >= 0;
    }).sortBy(function(element) { return element.tabIndex }).first();

    return firstByIndex ? firstByIndex : elements.find(function(element) {
      return ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
    });
  },

  focusFirstElement: function(form) {
    form = $(form);
    form.findFirstElement().activate();
    return form;
  },

  request: function(form, options) {
    form = $(form), options = Object.clone(options || { });

    var params = options.parameters, action = form.readAttribute('action') || '';
    if (action.blank()) action = window.location.href;
    options.parameters = form.serialize(true);

    if (params) {
      if (Object.isString(params)) params = params.toQueryParams();
      Object.extend(options.parameters, params);
    }

    if (form.hasAttribute('method') && !options.method)
      options.method = form.method;

    return new Ajax.Request(action, options);
  }
};

/*--------------------------------------------------------------------------*/

Form.Element = {
  focus: function(element) {
    $(element).focus();
    return element;
  },

  select: function(element) {
    $(element).select();
    return element;
  }
};

Form.Element.Methods = {
  serialize: function(element) {
    element = $(element);
    if (!element.disabled && element.name) {
      var value = element.getValue();
      if (value != undefined) {
        var pair = { };
        pair[element.name] = value;
        return Object.toQueryString(pair);
      }
    }
    return '';
  },

  getValue: function(element) {
    element = $(element);
    var method = element.tagName.toLowerCase();
    return Form.Element.Serializers[method](element);
  },

  setValue: function(element, value) {
    element = $(element);
    var method = element.tagName.toLowerCase();
    Form.Element.Serializers[method](element, value);
    return element;
  },

  clear: function(element) {
    $(element).value = '';
    return element;
  },

  present: function(element) {
    return $(element).value != '';
  },

  activate: function(element) {
    element = $(element);
    try {
      element.focus();
      if (element.select && (element.tagName.toLowerCase() != 'input' ||
          !['button', 'reset', 'submit'].include(element.type)))
        element.select();
    } catch (e) { }
    return element;
  },

  disable: function(element) {
    element = $(element);
    element.disabled = true;
    return element;
  },

  enable: function(element) {
    element = $(element);
    element.disabled = false;
    return element;
  }
};

/*--------------------------------------------------------------------------*/

var Field = Form.Element;
var $F = Form.Element.Methods.getValue;

/*--------------------------------------------------------------------------*/

Form.Element.Serializers = {
  input: function(element, value) {
    switch (element.type.toLowerCase()) {
      case 'checkbox':
      case 'radio':
        return Form.Element.Serializers.inputSelector(element, value);
      default:
        return Form.Element.Serializers.textarea(element, value);
    }
  },

  inputSelector: function(element, value) {
    if (Object.isUndefined(value)) return element.checked ? element.value : null;
    else element.checked = !!value;
  },

  textarea: function(element, value) {
    if (Object.isUndefined(value)) return element.value;
    else element.value = value;
  },

  select: function(element, value) {
    if (Object.isUndefined(value))
      return this[element.type == 'select-one' ?
        'selectOne' : 'selectMany'](element);
    else {
      var opt, currentValue, single = !Object.isArray(value);
      for (var i = 0, length = element.length; i < length; i++) {
        opt = element.options[i];
        currentValue = this.optionValue(opt);
        if (single) {
          if (currentValue == value) {
            opt.selected = true;
            return;
          }
        }
        else opt.selected = value.include(currentValue);
      }
    }
  },

  selectOne: function(element) {
    var index = element.selectedIndex;
    return index >= 0 ? this.optionValue(element.options[index]) : null;
  },

  selectMany: function(element) {
    var values, length = element.length;
    if (!length) return null;

    for (var i = 0, values = []; i < length; i++) {
      var opt = element.options[i];
      if (opt.selected) values.push(this.optionValue(opt));
    }
    return values;
  },

  optionValue: function(opt) {
    // extend element because hasAttribute may not be native
    return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
  }
};

/*--------------------------------------------------------------------------*/

Abstract.TimedObserver = Class.create(PeriodicalExecuter, {
  initialize: function($super, element, frequency, callback) {
    $super(callback, frequency);
    this.element   = $(element);
    this.lastValue = this.getValue();
  },

  execute: function() {
    var value = this.getValue();
    if (Object.isString(this.lastValue) && Object.isString(value) ?
        this.lastValue != value : String(this.lastValue) != String(value)) {
      this.callback(this.element, value);
      this.lastValue = value;
    }
  }
});

Form.Element.Observer = Class.create(Abstract.TimedObserver, {
  getValue: function() {
    return Form.Element.getValue(this.element);
  }
});

Form.Observer = Class.create(Abstract.TimedObserver, {
  getValue: function() {
    return Form.serialize(this.element);
  }
});

/*--------------------------------------------------------------------------*/

Abstract.EventObserver = Class.create({
  initialize: function(element, callback) {
    this.element  = $(element);
    this.callback = callback;

    this.lastValue = this.getValue();
    if (this.element.tagName.toLowerCase() == 'form')
      this.registerFormCallbacks();
    else
      this.registerCallback(this.element);
  },

  onElementEvent: function() {
    var value = this.getValue();
    if (this.lastValue != value) {
      this.callback(this.element, value);
      this.lastValue = value;
    }
  },

  registerFormCallbacks: function() {
    Form.getElements(this.element).each(this.registerCallback, this);
  },

  registerCallback: function(element) {
    if (element.type) {
      switch (element.type.toLowerCase()) {
        case 'checkbox':
        case 'radio':
          Event.observe(element, 'click', this.onElementEvent.bind(this));
          break;
        default:
          Event.observe(element, 'change', this.onElementEvent.bind(this));
          break;
      }
    }
  }
});

Form.Element.EventObserver = Class.create(Abstract.EventObserver, {
  getValue: function() {
    return Form.Element.getValue(this.element);
  }
});

Form.EventObserver = Class.create(Abstract.EventObserver, {
  getValue: function() {
    return Form.serialize(this.element);
  }
});
(function() {
  var Event = {
    KEY_BACKSPACE: 8,
    KEY_TAB:       9,
    KEY_RETURN:   13,
    KEY_ESC:      27,
    KEY_LEFT:     37,
    KEY_UP:       38,
    KEY_RIGHT:    39,
    KEY_DOWN:     40,
    KEY_DELETE:   46,
    KEY_HOME:     36,
    KEY_END:      35,
    KEY_PAGEUP:   33,
    KEY_PAGEDOWN: 34,
    KEY_INSERT:   45,

    cache: {}
  };

  var _isButton;
  if (Prototype.Browser.IE) {
    // IE doesn't map left/right/middle the same way.
    var buttonMap = { 0: 1, 1: 4, 2: 2 };
    _isButton = function(event, code) {
      return event.button === buttonMap[code];
    };
  } else if (Prototype.Browser.WebKit) {
    // In Safari we have to account for when the user holds down
    // the "meta" key.
    _isButton = function(event, code) {
      switch (code) {
        case 0: return event.which == 1 && !event.metaKey;
        case 1: return event.which == 1 && event.metaKey;
        default: return false;
      }
    };
  } else {
    _isButton = function(event, code) {
      return event.which ? (event.which === code + 1) : (event.button === code);
    };
  }

  function isLeftClick(event)   { return _isButton(event, 0) }
  function isMiddleClick(event) { return _isButton(event, 1) }
  function isRightClick(event)  { return _isButton(event, 2) }

  function element(event) {
    event = Event.extend(event);

    var node = event.target, type = event.type,
     currentTarget = event.currentTarget;

    if (currentTarget && currentTarget.tagName) {
      // Firefox screws up the "click" event when moving between radio buttons
      // via arrow keys. It also screws up the "load" and "error" events on images,
      // reporting the document as the target instead of the original image.
      if (type === 'load' || type === 'error' ||
        (type === 'click' && currentTarget.tagName.toLowerCase() === 'input'
          && currentTarget.type === 'radio'))
            node = currentTarget;
    }

    // Fix a Safari bug where a text node gets passed as the target of an
    // anchor click rather than the anchor itself.
    if (node.nodeType == Node.TEXT_NODE)
      node = node.parentNode;

    return Element.extend(node);
  }

  function findElement(event, expression) {
    var element = Event.element(event);
    if (!expression) return element;
    var elements = [element].concat(element.ancestors());
    return Selector.findElement(elements, expression, 0);
  }

  function pointer(event) {
    var docElement = document.documentElement,
     body = document.body || { scrollLeft: 0, scrollTop: 0 };
    return {
      x: event.pageX || (event.clientX +
        (docElement.scrollLeft || body.scrollLeft) -
        (docElement.clientLeft || 0)),
      y: event.pageY || (event.clientY +
        (docElement.scrollTop || body.scrollTop) -
        (docElement.clientTop || 0))
    };
  }

  function pointerX(event) { return Event.pointer(event).x }
  function pointerY(event) { return Event.pointer(event).y }

  function stop(event) {
    Event.extend(event);
    event.preventDefault();
    event.stopPropagation();

    // Set a "stopped" property so that a custom event can be inspected
    // after the fact to determine whether or not it was stopped.
    event.stopped = true;
  }

  Event.Methods = {
    isLeftClick: isLeftClick,
    isMiddleClick: isMiddleClick,
    isRightClick: isRightClick,

    element: element,
    findElement: findElement,

    pointer: pointer,
    pointerX: pointerX,
    pointerY: pointerY,

    stop: stop
  };


  // Compile the list of methods that get extended onto Events.
  var methods = Object.keys(Event.Methods).inject({ }, function(m, name) {
    m[name] = Event.Methods[name].methodize();
    return m;
  });

  if (Prototype.Browser.IE) {
    function _relatedTarget(event) {
      var element;
      switch (event.type) {
        case 'mouseover': element = event.fromElement; break;
        case 'mouseout':  element = event.toElement;   break;
        default: return null;
      }
      return Element.extend(element);
    }

    Object.extend(methods, {
      stopPropagation: function() { this.cancelBubble = true },
      preventDefault:  function() { this.returnValue = false },
      inspect: function() { return '[object Event]' }
    });

    // IE's method for extending events.
    Event.extend = function(event) {
      if (!event) return false;
      if (event._extendedByPrototype) return event;

      event._extendedByPrototype = Prototype.emptyFunction;
      var pointer = Event.pointer(event);
      Object.extend(event, {
        target: event.srcElement,
        relatedTarget: _relatedTarget(event),
        pageX:  pointer.x,
        pageY:  pointer.y
      });
      return Object.extend(event, methods);
    };
  } else {
    Event.prototype = window.Event.prototype || document.createEvent('HTMLEvents').__proto__;
    Object.extend(Event.prototype, methods);
    Event.extend = Prototype.K;
  }

  function _createResponder(element, eventName, handler) {
    // We don't set a default on the call to Element#retrieve so that we can
    // handle the element's "virgin" state.
    var registry = Element.retrieve(element, 'prototype_event_registry');

    if (Object.isUndefined(registry)) {
      // First time we've handled this element. Put it into the cache.
      CACHE.push(element);
      registry = Element.retrieve(element, 'prototype_event_registry', $H());
    }

    var respondersForEvent = registry.get(eventName);
    if (Object.isUndefined()) {
      respondersForEvent = [];
      registry.set(eventName, respondersForEvent);
    }

    // Work around the issue that permits a handler to be attached more than
    // once to the same element & event type.
    if (respondersForEvent.pluck('handler').include(handler)) return false;

    var responder;
    if (eventName.include(":")) {
      // Custom event.
      responder = function(event) {
        // If it's not a custom event, ignore it.
        if (Object.isUndefined(event.eventName))
          return false;

        // If it's a custom event, but not the _correct_ custom event, ignore it.
        if (event.eventName !== eventName)
          return false;

        Event.extend(event);
        handler.call(element, event);
      };
    } else {
      // Ordinary event.
      responder = function(event) {
        Event.extend(event);
        handler.call(element, event);
      };
    }

    responder.handler = handler;
    respondersForEvent.push(responder);
    return responder;
  }

  function _destroyCache() {
    for (var i = 0, length = CACHE.length; i < length; i++)
      Event.stopObserving(CACHE[i]);
  }

  var CACHE = [];

  // Internet Explorer needs to remove event handlers on page unload
  // in order to avoid memory leaks.
  if (Prototype.Browser.IE)
    window.attachEvent('onunload', _destroyCache);

  // Safari needs a dummy event handler on page unload so that it won't
  // use its bfcache. Safari <= 3.1 has an issue with restoring the "document"
  // object when page is returned to via the back button using its bfcache.
  if (Prototype.Browser.WebKit)
    window.addEventListener('unload', Prototype.emptyFunction, false);


  function observe(element, eventName, handler) {
    element = $(element);

    var responder = _createResponder(element, eventName, handler);

    if (!responder) return element;

    if (eventName.include(':')) {
      // Custom event.
      if (element.addEventListener)
        element.addEventListener("dataavailable", responder, false);
      else {
        // We observe two IE-proprietarty events: one for custom events that
        // bubble and one for custom events that do not bubble.
        element.attachEvent("ondataavailable", responder);
        element.attachEvent("onfilterchange", responder);
      }
    } else {
      // Ordinary event.
      if (element.addEventListener)
        element.addEventListener(eventName, responder, false);
      else
        element.attachEvent("on" + eventName, responder);
    }

    return element;
  }

  function stopObserving(element, eventName, handler) {
    element = $(element);

    var registry = Element.retrieve(element, 'prototype_event_registry');

    if (Object.isUndefined(registry)) return element;

    if (eventName && !handler) {
      // If an event name is passed without a handler, we stop observing all
      // handlers of that type.
      var responders = registry.get(eventName);

      if (Object.isUndefined(responders)) return element;

      responders.each( function(r) {
        Element.stopObserving(element, eventName, r.handler);
      });
      return element;
    } else if (!eventName) {
      // If both the event name and the handler are omitted, we stop observing
      // _all_ handlers on the element.
      registry.each( function(pair) {
        var eventName = pair.key, responders = pair.value;

        responders.each( function(r) {
          Element.stopObserving(element, eventName, r.handler);
        });
      });
      return element;
    }

    var responders = registry.get(eventName);
    var responder = responders.find( function(r) { return r.handler === handler; });
    if (!responder) return element;

    if (eventName.include(':')) {
      // Custom event.
      if (element.removeEventListener)
        element.removeEventListener("dataavailable", responder, false);
      else {
        element.detachEvent("ondataavailable", responder);
        element.detachEvent("onfilterchange",  responder);
      }
    } else {
      // Ordinary event.
      if (element.removeEventListener)
        element.removeEventListener(eventName, responder, false);
      else
        element.detachEvent('on' + eventName, responder);
    }

    registry.set(eventName, responders.without(responder));

    return element;
  }

  function fire(element, eventName, memo, bubble) {
    element = $(element);

    if (Object.isUndefined(bubble))
      bubble = true;

    if (element == document && document.createEvent && !element.dispatchEvent)
      element = document.documentElement;

    var event;
    if (document.createEvent) {
      event = document.createEvent('HTMLEvents');
      event.initEvent('dataavailable', true, true);
    } else {
      event = document.createEventObject();
      event.eventType = bubble ? 'ondataavailable' : 'onfilterchange';
    }

    event.eventName = eventName;
    event.memo = memo || { };

    if (document.createEvent)
      element.dispatchEvent(event);
    else
      element.fireEvent(event.eventType, event);

    return Event.extend(event);
  }


  Object.extend(Event, Event.Methods);

  Object.extend(Event, {
    fire:          fire,
    observe:       observe,
    stopObserving: stopObserving
  });

  Element.addMethods({
    fire:          fire,
    observe:       observe,
    stopObserving: stopObserving
  });

  Object.extend(document, {
    fire:          fire.methodize(),
    observe:       observe.methodize(),
    stopObserving: stopObserving.methodize(),
    loaded:        false
  });

  // Export to the global scope.
  if (window.Event) Object.extend(window.Event, Event);
  else window.Event = Event;
})();

(function() {
  /* Support for the DOMContentLoaded event is based on work by Dan Webb,
     Matthias Miller, Dean Edwards, John Resig, and Diego Perini. */

  var timer;

  function fireContentLoadedEvent() {
    if (document.loaded) return;
    if (timer) window.clearTimeout(timer);
    document.loaded = true;
    document.fire('dom:loaded');
  }

  function checkReadyState() {
    if (document.readyState === 'complete') {
      document.stopObserving('readystatechange', checkReadyState);
      fireContentLoadedEvent();
    }
  }

  function pollDoScroll() {
    try { document.documentElement.doScroll('left'); }
    catch(e) {
      timer = pollDoScroll.defer();
      return;
    }
    fireContentLoadedEvent();
  }

  if (document.addEventListener) {
    document.addEventListener('DOMContentLoaded', fireContentLoadedEvent, false);
  } else {
    document.observe('readystatechange', checkReadyState);
    if (window === top)
      timer = pollDoScroll.defer();
  }

  // Worst-case fallback
  Event.observe(window, 'load', fireContentLoadedEvent);
})();

/*------------------------------- DEPRECATED -------------------------------*/

Hash.toQueryString = Object.toQueryString;

var Toggle = { display: Element.toggle };

Element.Methods.childOf = Element.Methods.descendantOf;

var Insertion = {
  Before: function(element, content) {
    return Element.insert(element, {before:content});
  },

  Top: function(element, content) {
    return Element.insert(element, {top:content});
  },

  Bottom: function(element, content) {
    return Element.insert(element, {bottom:content});
  },

  After: function(element, content) {
    return Element.insert(element, {after:content});
  }
};

var $continue = new Error('"throw $continue" is deprecated, use "return" instead');

// This should be moved to script.aculo.us; notice the deprecated methods
// further below, that map to the newer Element methods.
var Position = {
  // set to true if needed, warning: firefox performance problems
  // NOT neeeded for page scrolling, only if draggable contained in
  // scrollable elements
  includeScrollOffsets: false,

  // must be called before calling withinIncludingScrolloffset, every time the
  // page is scrolled
  prepare: function() {
    this.deltaX =  window.pageXOffset
                || document.documentElement.scrollLeft
                || document.body.scrollLeft
                || 0;
    this.deltaY =  window.pageYOffset
                || document.documentElement.scrollTop
                || document.body.scrollTop
                || 0;
  },

  // caches x/y coordinate pair to use with overlap
  within: function(element, x, y) {
    if (this.includeScrollOffsets)
      return this.withinIncludingScrolloffsets(element, x, y);
    this.xcomp = x;
    this.ycomp = y;
    this.offset = Element.cumulativeOffset(element);

    return (y >= this.offset[1] &&
            y <  this.offset[1] + element.offsetHeight &&
            x >= this.offset[0] &&
            x <  this.offset[0] + element.offsetWidth);
  },

  withinIncludingScrolloffsets: function(element, x, y) {
    var offsetcache = Element.cumulativeScrollOffset(element);

    this.xcomp = x + offsetcache[0] - this.deltaX;
    this.ycomp = y + offsetcache[1] - this.deltaY;
    this.offset = Element.cumulativeOffset(element);

    return (this.ycomp >= this.offset[1] &&
            this.ycomp <  this.offset[1] + element.offsetHeight &&
            this.xcomp >= this.offset[0] &&
            this.xcomp <  this.offset[0] + element.offsetWidth);
  },

  // within must be called directly before
  overlap: function(mode, element) {
    if (!mode) return 0;
    if (mode == 'vertical')
      return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
        element.offsetHeight;
    if (mode == 'horizontal')
      return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
        element.offsetWidth;
  },

  // Deprecation layer -- use newer Element methods now (1.5.2).

  cumulativeOffset: Element.Methods.cumulativeOffset,

  positionedOffset: Element.Methods.positionedOffset,

  absolutize: function(element) {
    Position.prepare();
    return Element.absolutize(element);
  },

  relativize: function(element) {
    Position.prepare();
    return Element.relativize(element);
  },

  realOffset: Element.Methods.cumulativeScrollOffset,

  offsetParent: Element.Methods.getOffsetParent,

  page: Element.Methods.viewportOffset,

  clone: function(source, target, options) {
    options = options || { };
    return Element.clonePosition(target, source, options);
  }
};

/*--------------------------------------------------------------------------*/

if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){
  function iter(name) {
    return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]";
  }

  instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ?
  function(element, className) {
    className = className.toString().strip();
    var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className);
    return cond ? document._getElementsByXPath('.//*' + cond, element) : [];
  } : function(element, className) {
    className = className.toString().strip();
    var elements = [], classNames = (/\s/.test(className) ? $w(className) : null);
    if (!classNames && !className) return elements;

    var nodes = $(element).getElementsByTagName('*');
    className = ' ' + className + ' ';

    for (var i = 0, child, cn; child = nodes[i]; i++) {
      if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) ||
          (classNames && classNames.all(function(name) {
            return !name.toString().blank() && cn.include(' ' + name + ' ');
          }))))
        elements.push(Element.extend(child));
    }
    return elements;
  };

  return function(className, parentElement) {
    return $(parentElement || document.body).getElementsByClassName(className);
  };
}(Element.Methods);

/*--------------------------------------------------------------------------*/

Element.ClassNames = Class.create();
Element.ClassNames.prototype = {
  initialize: function(element) {
    this.element = $(element);
  },

  _each: function(iterator) {
    this.element.className.split(/\s+/).select(function(name) {
      return name.length > 0;
    })._each(iterator);
  },

  set: function(className) {
    this.element.className = className;
  },

  add: function(classNameToAdd) {
    if (this.include(classNameToAdd)) return;
    this.set($A(this).concat(classNameToAdd).join(' '));
  },

  remove: function(classNameToRemove) {
    if (!this.include(classNameToRemove)) return;
    this.set($A(this).without(classNameToRemove).join(' '));
  },

  toString: function() {
    return $A(this).join(' ');
  }
};

Object.extend(Element.ClassNames.prototype, Enumerable);

/*--------------------------------------------------------------------------*/

Element.addMethods();
/*
**
** File 'scriptaculous.js'
**
*/
// script.aculo.us scriptaculous.js v1.8.2, Tue Nov 18 18:30:58 +0100 2008

// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// For details, see the script.aculo.us web site: http://script.aculo.us/

var Scriptaculous = {
  Version: '1.8.2',
  require: function(libraryName) {
    // inserting via DOM fails in Safari 2.0, so brute force approach
    document.write('<script type="text/javascript" src="'+libraryName+'"><\/script>');
  },
  REQUIRED_PROTOTYPE: '1.6.0.3',
  load: function() {
    function convertVersionString(versionString) {
      var v = versionString.replace(/_.*|\./g, '');
      v = parseInt(v + '0'.times(4-v.length));
      return versionString.indexOf('_') > -1 ? v-1 : v;
    }

    if((typeof Prototype=='undefined') ||
       (typeof Element == 'undefined') ||
       (typeof Element.Methods=='undefined') ||
       (convertVersionString(Prototype.Version) <
        convertVersionString(Scriptaculous.REQUIRED_PROTOTYPE)))
       throw("script.aculo.us requires the Prototype JavaScript framework >= " +
        Scriptaculous.REQUIRED_PROTOTYPE);

    var js = /scriptaculous\.js(\?.*)?$/;
    $$('head script[src]').findAll(function(s) {
      return s.src.match(js);
    }).each(function(s) {
      var path = s.src.replace(js, ''),
      includes = s.src.match(/\?.*load=([a-z,]*)/);
      (includes ? includes[1] : 'builder,effects,dragdrop,controls,slider,sound').split(',').each(
       function(include) { Scriptaculous.require(path+include+'.js') });
    });
  }
};

Scriptaculous.load();
/*
**
** File 'effects.js'
**
*/
// script.aculo.us effects.js v1.8.2, Tue Nov 18 18:30:58 +0100 2008

// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// Contributors:
//  Justin Palmer (http://encytemedia.com/)
//  Mark Pilgrim (http://diveintomark.org/)
//  Martin Bialasinki
//
// script.aculo.us is freely distributable under the terms of an MIT-style license.
// For details, see the script.aculo.us web site: http://script.aculo.us/

// converts rgb() and #xxx to #xxxxxx format,
// returns self (or first argument) if not convertable
String.prototype.parseColor = function() {
  var color = '#';
  if (this.slice(0,4) == 'rgb(') {
    var cols = this.slice(4,this.length-1).split(',');
    var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);
  } else {
    if (this.slice(0,1) == '#') {
      if (this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();
      if (this.length==7) color = this.toLowerCase();
    }
  }
  return (color.length==7 ? color : (arguments[0] || this));
};

/*--------------------------------------------------------------------------*/

Element.collectTextNodes = function(element) {
  return $A($(element).childNodes).collect( function(node) {
    return (node.nodeType==3 ? node.nodeValue :
      (node.hasChildNodes() ? Element.collectTextNodes(node) : ''));
  }).flatten().join('');
};

Element.collectTextNodesIgnoreClass = function(element, className) {
  return $A($(element).childNodes).collect( function(node) {
    return (node.nodeType==3 ? node.nodeValue :
      ((node.hasChildNodes() && !Element.hasClassName(node,className)) ?
        Element.collectTextNodesIgnoreClass(node, className) : ''));
  }).flatten().join('');
};

Element.setContentZoom = function(element, percent) {
  element = $(element);
  element.setStyle({fontSize: (percent/100) + 'em'});
  if (Prototype.Browser.WebKit) window.scrollBy(0,0);
  return element;
};

Element.getInlineOpacity = function(element){
  return $(element).style.opacity || '';
};

Element.forceRerendering = function(element) {
  try {
    element = $(element);
    var n = document.createTextNode(' ');
    element.appendChild(n);
    element.removeChild(n);
  } catch(e) { }
};

/*--------------------------------------------------------------------------*/

var Effect = {
  _elementDoesNotExistError: {
    name: 'ElementDoesNotExistError',
    message: 'The specified DOM element does not exist, but is required for this effect to operate'
  },
  Transitions: {
    linear: Prototype.K,
    sinoidal: function(pos) {
      return (-Math.cos(pos*Math.PI)/2) + .5;
    },
    reverse: function(pos) {
      return 1-pos;
    },
    flicker: function(pos) {
      var pos = ((-Math.cos(pos*Math.PI)/4) + .75) + Math.random()/4;
      return pos > 1 ? 1 : pos;
    },
    wobble: function(pos) {
      return (-Math.cos(pos*Math.PI*(9*pos))/2) + .5;
    },
    pulse: function(pos, pulses) {
      return (-Math.cos((pos*((pulses||5)-.5)*2)*Math.PI)/2) + .5;
    },
    spring: function(pos) {
      return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6));
    },
    none: function(pos) {
      return 0;
    },
    full: function(pos) {
      return 1;
    }
  },
  DefaultOptions: {
    duration:   1.0,   // seconds
    fps:        100,   // 100= assume 66fps max.
    sync:       false, // true for combining
    from:       0.0,
    to:         1.0,
    delay:      0.0,
    queue:      'parallel'
  },
  tagifyText: function(element) {
    var tagifyStyle = 'position:relative';
    if (Prototype.Browser.IE) tagifyStyle += ';zoom:1';

    element = $(element);
    $A(element.childNodes).each( function(child) {
      if (child.nodeType==3) {
        child.nodeValue.toArray().each( function(character) {
          element.insertBefore(
            new Element('span', {style: tagifyStyle}).update(
              character == ' ' ? String.fromCharCode(160) : character),
              child);
        });
        Element.remove(child);
      }
    });
  },
  multiple: function(element, effect) {
    var elements;
    if (((typeof element == 'object') ||
        Object.isFunction(element)) &&
       (element.length))
      elements = element;
    else
      elements = $(element).childNodes;

    var options = Object.extend({
      speed: 0.1,
      delay: 0.0
    }, arguments[2] || { });
    var masterDelay = options.delay;

    $A(elements).each( function(element, index) {
      new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay }));
    });
  },
  PAIRS: {
    'slide':  ['SlideDown','SlideUp'],
    'blind':  ['BlindDown','BlindUp'],
    'appear': ['Appear','Fade']
  },
  toggle: function(element, effect) {
    element = $(element);
    effect = (effect || 'appear').toLowerCase();
    var options = Object.extend({
      queue: { position:'end', scope:(element.id || 'global'), limit: 1 }
    }, arguments[2] || { });
    Effect[element.visible() ?
      Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options);
  }
};

Effect.DefaultOptions.transition = Effect.Transitions.sinoidal;

/* ------------- core effects ------------- */

Effect.ScopedQueue = Class.create(Enumerable, {
  initialize: function() {
    this.effects  = [];
    this.interval = null;
  },
  _each: function(iterator) {
    this.effects._each(iterator);
  },
  add: function(effect) {
    var timestamp = new Date().getTime();

    var position = Object.isString(effect.options.queue) ?
      effect.options.queue : effect.options.queue.position;

    switch(position) {
      case 'front':
        // move unstarted effects after this effect
        this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) {
            e.startOn  += effect.finishOn;
            e.finishOn += effect.finishOn;
          });
        break;
      case 'with-last':
        timestamp = this.effects.pluck('startOn').max() || timestamp;
        break;
      case 'end':
        // start effect after last queued effect has finished
        timestamp = this.effects.pluck('finishOn').max() || timestamp;
        break;
    }

    effect.startOn  += timestamp;
    effect.finishOn += timestamp;

    if (!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))
      this.effects.push(effect);

    if (!this.interval)
      this.interval = setInterval(this.loop.bind(this), 15);
  },
  remove: function(effect) {
    this.effects = this.effects.reject(function(e) { return e==effect });
    if (this.effects.length == 0) {
      clearInterval(this.interval);
      this.interval = null;
    }
  },
  loop: function() {
    var timePos = new Date().getTime();
    for(var i=0, len=this.effects.length;i<len;i++)
      this.effects[i] && this.effects[i].loop(timePos);
  }
});

Effect.Queues = {
  instances: $H(),
  get: function(queueName) {
    if (!Object.isString(queueName)) return queueName;

    return this.instances.get(queueName) ||
      this.instances.set(queueName, new Effect.ScopedQueue());
  }
};
Effect.Queue = Effect.Queues.get('global');

Effect.Base = Class.create({
  position: null,
  start: function(options) {
    function codeForEvent(options,eventName){
      return (
        (options[eventName+'Internal'] ? 'this.options.'+eventName+'Internal(this);' : '') +
        (options[eventName] ? 'this.options.'+eventName+'(this);' : '')
      );
    }
    if (options && options.transition === false) options.transition = Effect.Transitions.linear;
    this.options      = Object.extend(Object.extend({ },Effect.DefaultOptions), options || { });
    this.currentFrame = 0;
    this.state        = 'idle';
    this.startOn      = this.options.delay*1000;
    this.finishOn     = this.startOn+(this.options.duration*1000);
    this.fromToDelta  = this.options.to-this.options.from;
    this.totalTime    = this.finishOn-this.startOn;
    this.totalFrames  = this.options.fps*this.options.duration;

    this.render = (function() {
      function dispatch(effect, eventName) {
        if (effect.options[eventName + 'Internal'])
          effect.options[eventName + 'Internal'](effect);
        if (effect.options[eventName])
          effect.options[eventName](effect);
      }

      return function(pos) {
        if (this.state === "idle") {
          this.state = "running";
          dispatch(this, 'beforeSetup');
          if (this.setup) this.setup();
          dispatch(this, 'afterSetup');
        }
        if (this.state === "running") {
          pos = (this.options.transition(pos) * this.fromToDelta) + this.options.from;
          this.position = pos;
          dispatch(this, 'beforeUpdate');
          if (this.update) this.update(pos);
          dispatch(this, 'afterUpdate');
        }
      };
    })();

    this.event('beforeStart');
    if (!this.options.sync)
      Effect.Queues.get(Object.isString(this.options.queue) ?
        'global' : this.options.queue.scope).add(this);
  },
  loop: function(timePos) {
    if (timePos >= this.startOn) {
      if (timePos >= this.finishOn) {
        this.render(1.0);
        this.cancel();
        this.event('beforeFinish');
        if (this.finish) this.finish();
        this.event('afterFinish');
        return;
      }
      var pos   = (timePos - this.startOn) / this.totalTime,
          frame = (pos * this.totalFrames).round();
      if (frame > this.currentFrame) {
        this.render(pos);
        this.currentFrame = frame;
      }
    }
  },
  cancel: function() {
    if (!this.options.sync)
      Effect.Queues.get(Object.isString(this.options.queue) ?
        'global' : this.options.queue.scope).remove(this);
    this.state = 'finished';
  },
  event: function(eventName) {
    if (this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this);
    if (this.options[eventName]) this.options[eventName](this);
  },
  inspect: function() {
    var data = $H();
    for(property in this)
      if (!Object.isFunction(this[property])) data.set(property, this[property]);
    return '#<Effect:' + data.inspect() + ',options:' + $H(this.options).inspect() + '>';
  }
});

Effect.Parallel = Class.create(Effect.Base, {
  initialize: function(effects) {
    this.effects = effects || [];
    this.start(arguments[1]);
  },
  update: function(position) {
    this.effects.invoke('render', position);
  },
  finish: function(position) {
    this.effects.each( function(effect) {
      effect.render(1.0);
      effect.cancel();
      effect.event('beforeFinish');
      if (effect.finish) effect.finish(position);
      effect.event('afterFinish');
    });
  }
});

Effect.Tween = Class.create(Effect.Base, {
  initialize: function(object, from, to) {
    object = Object.isString(object) ? $(object) : object;
    var args = $A(arguments), method = args.last(),
      options = args.length == 5 ? args[3] : null;
    this.method = Object.isFunction(method) ? method.bind(object) :
      Object.isFunction(object[method]) ? object[method].bind(object) :
      function(value) { object[method] = value };
    this.start(Object.extend({ from: from, to: to }, options || { }));
  },
  update: function(position) {
    this.method(position);
  }
});

Effect.Event = Class.create(Effect.Base, {
  initialize: function() {
    this.start(Object.extend({ duration: 0 }, arguments[0] || { }));
  },
  update: Prototype.emptyFunction
});

Effect.Opacity = Class.create(Effect.Base, {
  initialize: function(element) {
    this.element = $(element);
    if (!this.element) throw(Effect._elementDoesNotExistError);
    // make this work on IE on elements without 'layout'
    if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
      this.element.setStyle({zoom: 1});
    var options = Object.extend({
      from: this.element.getOpacity() || 0.0,
      to:   1.0
    }, arguments[1] || { });
    this.start(options);
  },
  update: function(position) {
    this.element.setOpacity(position);
  }
});

Effect.Move = Class.create(Effect.Base, {
  initialize: function(element) {
    this.element = $(element);
    if (!this.element) throw(Effect._elementDoesNotExistError);
    var options = Object.extend({
      x:    0,
      y:    0,
      mode: 'relative'
    }, arguments[1] || { });
    this.start(options);
  },
  setup: function() {
    this.element.makePositioned();
    this.originalLeft = parseFloat(this.element.getStyle('left') || '0');
    this.originalTop  = parseFloat(this.element.getStyle('top')  || '0');
    if (this.options.mode == 'absolute') {
      this.options.x = this.options.x - this.originalLeft;
      this.options.y = this.options.y - this.originalTop;
    }
  },
  update: function(position) {
    this.element.setStyle({
      left: (this.options.x  * position + this.originalLeft).round() + 'px',
      top:  (this.options.y  * position + this.originalTop).round()  + 'px'
    });
  }
});

// for backwards compatibility
Effect.MoveBy = function(element, toTop, toLeft) {
  return new Effect.Move(element,
    Object.extend({ x: toLeft, y: toTop }, arguments[3] || { }));
};

Effect.Scale = Class.create(Effect.Base, {
  initialize: function(element, percent) {
    this.element = $(element);
    if (!this.element) throw(Effect._elementDoesNotExistError);
    var options = Object.extend({
      scaleX: true,
      scaleY: true,
      scaleContent: true,
      scaleFromCenter: false,
      scaleMode: 'box',        // 'box' or 'contents' or { } with provided values
      scaleFrom: 100.0,
      scaleTo:   percent
    }, arguments[2] || { });
    this.start(options);
  },
  setup: function() {
    this.restoreAfterFinish = this.options.restoreAfterFinish || false;
    this.elementPositioning = this.element.getStyle('position');

    this.originalStyle = { };
    ['top','left','width','height','fontSize'].each( function(k) {
      this.originalStyle[k] = this.element.style[k];
    }.bind(this));

    this.originalTop  = this.element.offsetTop;
    this.originalLeft = this.element.offsetLeft;

    var fontSize = this.element.getStyle('font-size') || '100%';
    ['em','px','%','pt'].each( function(fontSizeType) {
      if (fontSize.indexOf(fontSizeType)>0) {
        this.fontSize     = parseFloat(fontSize);
        this.fontSizeType = fontSizeType;
      }
    }.bind(this));

    this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;

    this.dims = null;
    if (this.options.scaleMode=='box')
      this.dims = [this.element.offsetHeight, this.element.offsetWidth];
    if (/^content/.test(this.options.scaleMode))
      this.dims = [this.element.scrollHeight, this.element.scrollWidth];
    if (!this.dims)
      this.dims = [this.options.scaleMode.originalHeight,
                   this.options.scaleMode.originalWidth];
  },
  update: function(position) {
    var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position);
    if (this.options.scaleContent && this.fontSize)
      this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType });
    this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);
  },
  finish: function(position) {
    if (this.restoreAfterFinish) this.element.setStyle(this.originalStyle);
  },
  setDimensions: function(height, width) {
    var d = { };
    if (this.options.scaleX) d.width = width.round() + 'px';
    if (this.options.scaleY) d.height = height.round() + 'px';
    if (this.options.scaleFromCenter) {
      var topd  = (height - this.dims[0])/2;
      var leftd = (width  - this.dims[1])/2;
      if (this.elementPositioning == 'absolute') {
        if (this.options.scaleY) d.top = this.originalTop-topd + 'px';
        if (this.options.scaleX) d.left = this.originalLeft-leftd + 'px';
      } else {
        if (this.options.scaleY) d.top = -topd + 'px';
        if (this.options.scaleX) d.left = -leftd + 'px';
      }
    }
    this.element.setStyle(d);
  }
});

Effect.Highlight = Class.create(Effect.Base, {
  initialize: function(element) {
    this.element = $(element);
    if (!this.element) throw(Effect._elementDoesNotExistError);
    var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || { });
    this.start(options);
  },
  setup: function() {
    // Prevent executing on elements not in the layout flow
    if (this.element.getStyle('display')=='none') { this.cancel(); return; }
    // Disable background image during the effect
    this.oldStyle = { };
    if (!this.options.keepBackgroundImage) {
      this.oldStyle.backgroundImage = this.element.getStyle('background-image');
      this.element.setStyle({backgroundImage: 'none'});
    }
    if (!this.options.endcolor)
      this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff');
    if (!this.options.restorecolor)
      this.options.restorecolor = this.element.getStyle('background-color');
    // init color calculations
    this._base  = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this));
    this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this));
  },
  update: function(position) {
    this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){
      return m+((this._base[i]+(this._delta[i]*position)).round().toColorPart()); }.bind(this)) });
  },
  finish: function() {
    this.element.setStyle(Object.extend(this.oldStyle, {
      backgroundColor: this.options.restorecolor
    }));
  }
});

Effect.ScrollTo = function(element) {
  var options = arguments[1] || { },
  scrollOffsets = document.viewport.getScrollOffsets(),
  elementOffsets = $(element).cumulativeOffset();

  if (options.offset) elementOffsets[1] += options.offset;

  return new Effect.Tween(null,
    scrollOffsets.top,
    elementOffsets[1],
    options,
    function(p){ scrollTo(scrollOffsets.left, p.round()); }
  );
};

/* ------------- combination effects ------------- */

Effect.Fade = function(element) {
  element = $(element);
  var oldOpacity = element.getInlineOpacity();
  var options = Object.extend({
    from: element.getOpacity() || 1.0,
    to:   0.0,
    afterFinishInternal: function(effect) {
      if (effect.options.to!=0) return;
      effect.element.hide().setStyle({opacity: oldOpacity});
    }
  }, arguments[1] || { });
  return new Effect.Opacity(element,options);
};

Effect.Appear = function(element) {
  element = $(element);
  var options = Object.extend({
  from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0),
  to:   1.0,
  // force Safari to render floated elements properly
  afterFinishInternal: function(effect) {
    effect.element.forceRerendering();
  },
  beforeSetup: function(effect) {
    effect.element.setOpacity(effect.options.from).show();
  }}, arguments[1] || { });
  return new Effect.Opacity(element,options);
};

Effect.Puff = function(element) {
  element = $(element);
  var oldStyle = {
    opacity: element.getInlineOpacity(),
    position: element.getStyle('position'),
    top:  element.style.top,
    left: element.style.left,
    width: element.style.width,
    height: element.style.height
  };
  return new Effect.Parallel(
   [ new Effect.Scale(element, 200,
      { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }),
     new Effect.Opacity(element, { sync: true, to: 0.0 } ) ],
     Object.extend({ duration: 1.0,
      beforeSetupInternal: function(effect) {
        Position.absolutize(effect.effects[0].element);
      },
      afterFinishInternal: function(effect) {
         effect.effects[0].element.hide().setStyle(oldStyle); }
     }, arguments[1] || { })
   );
};

Effect.BlindUp = function(element) {
  element = $(element);
  element.makeClipping();
  return new Effect.Scale(element, 0,
    Object.extend({ scaleContent: false,
      scaleX: false,
      restoreAfterFinish: true,
      afterFinishInternal: function(effect) {
        effect.element.hide().undoClipping();
      }
    }, arguments[1] || { })
  );
};

Effect.BlindDown = function(element) {
  element = $(element);
  var elementDimensions = element.getDimensions();
  return new Effect.Scale(element, 100, Object.extend({
    scaleContent: false,
    scaleX: false,
    scaleFrom: 0,
    scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
    restoreAfterFinish: true,
    afterSetup: function(effect) {
      effect.element.makeClipping().setStyle({height: '0px'}).show();
    },
    afterFinishInternal: function(effect) {
      effect.element.undoClipping();
    }
  }, arguments[1] || { }));
};

Effect.SwitchOff = function(element) {
  element = $(element);
  var oldOpacity = element.getInlineOpacity();
  return new Effect.Appear(element, Object.extend({
    duration: 0.4,
    from: 0,
    transition: Effect.Transitions.flicker,
    afterFinishInternal: function(effect) {
      new Effect.Scale(effect.element, 1, {
        duration: 0.3, scaleFromCenter: true,
        scaleX: false, scaleContent: false, restoreAfterFinish: true,
        beforeSetup: function(effect) {
          effect.element.makePositioned().makeClipping();
        },
        afterFinishInternal: function(effect) {
          effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity});
        }
      });
    }
  }, arguments[1] || { }));
};

Effect.DropOut = function(element) {
  element = $(element);
  var oldStyle = {
    top: element.getStyle('top'),
    left: element.getStyle('left'),
    opacity: element.getInlineOpacity() };
  return new Effect.Parallel(
    [ new Effect.Move(element, {x: 0, y: 100, sync: true }),
      new Effect.Opacity(element, { sync: true, to: 0.0 }) ],
    Object.extend(
      { duration: 0.5,
        beforeSetup: function(effect) {
          effect.effects[0].element.makePositioned();
        },
        afterFinishInternal: function(effect) {
          effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle);
        }
      }, arguments[1] || { }));
};

Effect.Shake = function(element) {
  element = $(element);
  var options = Object.extend({
    distance: 20,
    duration: 0.5
  }, arguments[1] || {});
  var distance = parseFloat(options.distance);
  var split = parseFloat(options.duration) / 10.0;
  var oldStyle = {
    top: element.getStyle('top'),
    left: element.getStyle('left') };
    return new Effect.Move(element,
      { x:  distance, y: 0, duration: split, afterFinishInternal: function(effect) {
    new Effect.Move(effect.element,
      { x: -distance*2, y: 0, duration: split*2,  afterFinishInternal: function(effect) {
    new Effect.Move(effect.element,
      { x:  distance*2, y: 0, duration: split*2,  afterFinishInternal: function(effect) {
    new Effect.Move(effect.element,
      { x: -distance*2, y: 0, duration: split*2,  afterFinishInternal: function(effect) {
    new Effect.Move(effect.element,
      { x:  distance*2, y: 0, duration: split*2,  afterFinishInternal: function(effect) {
    new Effect.Move(effect.element,
      { x: -distance, y: 0, duration: split, afterFinishInternal: function(effect) {
        effect.element.undoPositioned().setStyle(oldStyle);
  }}); }}); }}); }}); }}); }});
};

Effect.SlideDown = function(element) {
  element = $(element).cleanWhitespace();
  // SlideDown need to have the content of the element wrapped in a container element with fixed height!
  var oldInnerBottom = element.down().getStyle('bottom');
  var elementDimensions = element.getDimensions();
  return new Effect.Scale(element, 100, Object.extend({
    scaleContent: false,
    scaleX: false,
    scaleFrom: window.opera ? 0 : 1,
    scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
    restoreAfterFinish: true,
    afterSetup: function(effect) {
      effect.element.makePositioned();
      effect.element.down().makePositioned();
      if (window.opera) effect.element.setStyle({top: ''});
      effect.element.makeClipping().setStyle({height: '0px'}).show();
    },
    afterUpdateInternal: function(effect) {
      effect.element.down().setStyle({bottom:
        (effect.dims[0] - effect.element.clientHeight) + 'px' });
    },
    afterFinishInternal: function(effect) {
      effect.element.undoClipping().undoPositioned();
      effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); }
    }, arguments[1] || { })
  );
};

Effect.SlideUp = function(element) {
  element = $(element).cleanWhitespace();
  var oldInnerBottom = element.down().getStyle('bottom');
  var elementDimensions = element.getDimensions();
  return new Effect.Scale(element, window.opera ? 0 : 1,
   Object.extend({ scaleContent: false,
    scaleX: false,
    scaleMode: 'box',
    scaleFrom: 100,
    scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
    restoreAfterFinish: true,
    afterSetup: function(effect) {
      effect.element.makePositioned();
      effect.element.down().makePositioned();
      if (window.opera) effect.element.setStyle({top: ''});
      effect.element.makeClipping().show();
    },
    afterUpdateInternal: function(effect) {
      effect.element.down().setStyle({bottom:
        (effect.dims[0] - effect.element.clientHeight) + 'px' });
    },
    afterFinishInternal: function(effect) {
      effect.element.hide().undoClipping().undoPositioned();
      effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom});
    }
   }, arguments[1] || { })
  );
};

// Bug in opera makes the TD containing this element expand for a instance after finish
Effect.Squish = function(element) {
  return new Effect.Scale(element, window.opera ? 1 : 0, {
    restoreAfterFinish: true,
    beforeSetup: function(effect) {
      effect.element.makeClipping();
    },
    afterFinishInternal: function(effect) {
      effect.element.hide().undoClipping();
    }
  });
};

Effect.Grow = function(element) {
  element = $(element);
  var options = Object.extend({
    direction: 'center',
    moveTransition: Effect.Transitions.sinoidal,
    scaleTransition: Effect.Transitions.sinoidal,
    opacityTransition: Effect.Transitions.full
  }, arguments[1] || { });
  var oldStyle = {
    top: element.style.top,
    left: element.style.left,
    height: element.style.height,
    width: element.style.width,
    opacity: element.getInlineOpacity() };

  var dims = element.getDimensions();
  var initialMoveX, initialMoveY;
  var moveX, moveY;

  switch (options.direction) {
    case 'top-left':
      initialMoveX = initialMoveY = moveX = moveY = 0;
      break;
    case 'top-right':
      initialMoveX = dims.width;
      initialMoveY = moveY = 0;
      moveX = -dims.width;
      break;
    case 'bottom-left':
      initialMoveX = moveX = 0;
      initialMoveY = dims.height;
      moveY = -dims.height;
      break;
    case 'bottom-right':
      initialMoveX = dims.width;
      initialMoveY = dims.height;
      moveX = -dims.width;
      moveY = -dims.height;
      break;
    case 'center':
      initialMoveX = dims.width / 2;
      initialMoveY = dims.height / 2;
      moveX = -dims.width / 2;
      moveY = -dims.height / 2;
      break;
  }

  return new Effect.Move(element, {
    x: initialMoveX,
    y: initialMoveY,
    duration: 0.01,
    beforeSetup: function(effect) {
      effect.element.hide().makeClipping().makePositioned();
    },
    afterFinishInternal: function(effect) {
      new Effect.Parallel(
        [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }),
          new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }),
          new Effect.Scale(effect.element, 100, {
            scaleMode: { originalHeight: dims.height, originalWidth: dims.width },
            sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true})
        ], Object.extend({
             beforeSetup: function(effect) {
               effect.effects[0].element.setStyle({height: '0px'}).show();
             },
             afterFinishInternal: function(effect) {
               effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle);
             }
           }, options)
      );
    }
  });
};

Effect.Shrink = function(element) {
  element = $(element);
  var options = Object.extend({
    direction: 'center',
    moveTransition: Effect.Transitions.sinoidal,
    scaleTransition: Effect.Transitions.sinoidal,
    opacityTransition: Effect.Transitions.none
  }, arguments[1] || { });
  var oldStyle = {
    top: element.style.top,
    left: element.style.left,
    height: element.style.height,
    width: element.style.width,
    opacity: element.getInlineOpacity() };

  var dims = element.getDimensions();
  var moveX, moveY;

  switch (options.direction) {
    case 'top-left':
      moveX = moveY = 0;
      break;
    case 'top-right':
      moveX = dims.width;
      moveY = 0;
      break;
    case 'bottom-left':
      moveX = 0;
      moveY = dims.height;
      break;
    case 'bottom-right':
      moveX = dims.width;
      moveY = dims.height;
      break;
    case 'center':
      moveX = dims.width / 2;
      moveY = dims.height / 2;
      break;
  }

  return new Effect.Parallel(
    [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }),
      new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}),
      new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition })
    ], Object.extend({
         beforeStartInternal: function(effect) {
           effect.effects[0].element.makePositioned().makeClipping();
         },
         afterFinishInternal: function(effect) {
           effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); }
       }, options)
  );
};

Effect.Pulsate = function(element) {
  element = $(element);
  var options    = arguments[1] || { },
    oldOpacity = element.getInlineOpacity(),
    transition = options.transition || Effect.Transitions.linear,
    reverser   = function(pos){
      return 1 - transition((-Math.cos((pos*(options.pulses||5)*2)*Math.PI)/2) + .5);
    };

  return new Effect.Opacity(element,
    Object.extend(Object.extend({  duration: 2.0, from: 0,
      afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); }
    }, options), {transition: reverser}));
};

Effect.Fold = function(element) {
  element = $(element);
  var oldStyle = {
    top: element.style.top,
    left: element.style.left,
    width: element.style.width,
    height: element.style.height };
  element.makeClipping();
  return new Effect.Scale(element, 5, Object.extend({
    scaleContent: false,
    scaleX: false,
    afterFinishInternal: function(effect) {
    new Effect.Scale(element, 1, {
      scaleContent: false,
      scaleY: false,
      afterFinishInternal: function(effect) {
        effect.element.hide().undoClipping().setStyle(oldStyle);
      } });
  }}, arguments[1] || { }));
};

Effect.Morph = Class.create(Effect.Base, {
  initialize: function(element) {
    this.element = $(element);
    if (!this.element) throw(Effect._elementDoesNotExistError);
    var options = Object.extend({
      style: { }
    }, arguments[1] || { });

    if (!Object.isString(options.style)) this.style = $H(options.style);
    else {
      if (options.style.include(':'))
        this.style = options.style.parseStyle();
      else {
        this.element.addClassName(options.style);
        this.style = $H(this.element.getStyles());
        this.element.removeClassName(options.style);
        var css = this.element.getStyles();
        this.style = this.style.reject(function(style) {
          return style.value == css[style.key];
        });
        options.afterFinishInternal = function(effect) {
          effect.element.addClassName(effect.options.style);
          effect.transforms.each(function(transform) {
            effect.element.style[transform.style] = '';
          });
        };
      }
    }
    this.start(options);
  },

  setup: function(){
    function parseColor(color){
      if (!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff';
      color = color.parseColor();
      return $R(0,2).map(function(i){
        return parseInt( color.slice(i*2+1,i*2+3), 16 );
      });
    }
    this.transforms = this.style.map(function(pair){
      var property = pair[0], value = pair[1], unit = null;

      if (value.parseColor('#zzzzzz') != '#zzzzzz') {
        value = value.parseColor();
        unit  = 'color';
      } else if (property == 'opacity') {
        value = parseFloat(value);
        if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
          this.element.setStyle({zoom: 1});
      } else if (Element.CSS_LENGTH.test(value)) {
          var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/);
          value = parseFloat(components[1]);
          unit = (components.length == 3) ? components[2] : null;
      }

      var originalValue = this.element.getStyle(property);
      return {
        style: property.camelize(),
        originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0),
        targetValue: unit=='color' ? parseColor(value) : value,
        unit: unit
      };
    }.bind(this)).reject(function(transform){
      return (
        (transform.originalValue == transform.targetValue) ||
        (
          transform.unit != 'color' &&
          (isNaN(transform.originalValue) || isNaN(transform.targetValue))
        )
      );
    });
  },
  update: function(position) {
    var style = { }, transform, i = this.transforms.length;
    while(i--)
      style[(transform = this.transforms[i]).style] =
        transform.unit=='color' ? '#'+
          (Math.round(transform.originalValue[0]+
            (transform.targetValue[0]-transform.originalValue[0])*position)).toColorPart() +
          (Math.round(transform.originalValue[1]+
            (transform.targetValue[1]-transform.originalValue[1])*position)).toColorPart() +
          (Math.round(transform.originalValue[2]+
            (transform.targetValue[2]-transform.originalValue[2])*position)).toColorPart() :
        (transform.originalValue +
          (transform.targetValue - transform.originalValue) * position).toFixed(3) +
            (transform.unit === null ? '' : transform.unit);
    this.element.setStyle(style, true);
  }
});

Effect.Transform = Class.create({
  initialize: function(tracks){
    this.tracks  = [];
    this.options = arguments[1] || { };
    this.addTracks(tracks);
  },
  addTracks: function(tracks){
    tracks.each(function(track){
      track = $H(track);
      var data = track.values().first();
      this.tracks.push($H({
        ids:     track.keys().first(),
        effect:  Effect.Morph,
        options: { style: data }
      }));
    }.bind(this));
    return this;
  },
  play: function(){
    return new Effect.Parallel(
      this.tracks.map(function(track){
        var ids = track.get('ids'), effect = track.get('effect'), options = track.get('options');
        var elements = [$(ids) || $$(ids)].flatten();
        return elements.map(function(e){ return new effect(e, Object.extend({ sync:true }, options)) });
      }).flatten(),
      this.options
    );
  }
});

Element.CSS_PROPERTIES = $w(
  'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' +
  'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' +
  'borderRightColor borderRightStyle borderRightWidth borderSpacing ' +
  'borderTopColor borderTopStyle borderTopWidth bottom clip color ' +
  'fontSize fontWeight height left letterSpacing lineHeight ' +
  'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+
  'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' +
  'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' +
  'right textIndent top width wordSpacing zIndex');

Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;

String.__parseStyleElement = document.createElement('div');
String.prototype.parseStyle = function(){
  var style, styleRules = $H();
  if (Prototype.Browser.WebKit)
    style = new Element('div',{style:this}).style;
  else {
    String.__parseStyleElement.innerHTML = '<div style="' + this + '"></div>';
    style = String.__parseStyleElement.childNodes[0].style;
  }

  Element.CSS_PROPERTIES.each(function(property){
    if (style[property]) styleRules.set(property, style[property]);
  });

  if (Prototype.Browser.IE && this.include('opacity'))
    styleRules.set('opacity', this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1]);

  return styleRules;
};

if (document.defaultView && document.defaultView.getComputedStyle) {
  Element.getStyles = function(element) {
    var css = document.defaultView.getComputedStyle($(element), null);
    return Element.CSS_PROPERTIES.inject({ }, function(styles, property) {
      styles[property] = css[property];
      return styles;
    });
  };
} else {
  Element.getStyles = function(element) {
    element = $(element);
    var css = element.currentStyle, styles;
    styles = Element.CSS_PROPERTIES.inject({ }, function(results, property) {
      results[property] = css[property];
      return results;
    });
    if (!styles.opacity) styles.opacity = element.getOpacity();
    return styles;
  };
}

Effect.Methods = {
  morph: function(element, style) {
    element = $(element);
    new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || { }));
    return element;
  },
  visualEffect: function(element, effect, options) {
    element = $(element);
    var s = effect.dasherize().camelize(), klass = s.charAt(0).toUpperCase() + s.substring(1);
    new Effect[klass](element, options);
    return element;
  },
  highlight: function(element, options) {
    element = $(element);
    new Effect.Highlight(element, options);
    return element;
  }
};

$w('fade appear grow shrink fold blindUp blindDown slideUp slideDown '+
  'pulsate shake puff squish switchOff dropOut').each(
  function(effect) {
    Effect.Methods[effect] = function(element, options){
      element = $(element);
      Effect[effect.charAt(0).toUpperCase() + effect.substring(1)](element, options);
      return element;
    };
  }
);

$w('getInlineOpacity forceRerendering setContentZoom collectTextNodes collectTextNodesIgnoreClass getStyles').each(
  function(f) { Effect.Methods[f] = Element[f]; }
);

Element.addMethods(Effect.Methods);
/*
**
** File 'kbEffects.js'
**
*/

//adds onDraw and constrainToViewport option to draggable
if(typeof(Effect) != 'undefined'){
	Effect.Slide = function(element){
		if (!$(element)) return null;
		var element = $(element).cleanWhitespace();
		var options = Object.extend({
			duration: 1.0, // duration of the effect in seconds, given as a float.
			delay: 0.0, // Sets the number of seconds to wait before the effect actually starts.
			direction: 'left', // Welcher Effect: (Fade, Blind, Slide)
			heading: null, // Welcher Effect: (Fade, Blind, Slide)
			width: element.getWidth(), // einblenden bzw. ausblenden erzwingen... (hide | show)
			force:'', // einblenden bzw. ausblenden erzwingen... (hide | show)
			queue:{scope:'global'} // um auf die queue zuzugreifen...
		}, KB.parseArgument(arguments[1]));
		
		var width = (options.direction.search(/^l/i) > -1)?-1*options.width:options.width;
		if (!options.heading) options.heading = (element.visible())?'out':'in';
		var wrapper = element.up();
		
		if (!wrapper.hasClassName('slide_wrapper')) {
			element.wrap(new Element('div',{className:'slide_wrapper'}));
			wrapper = element.up();
			element.show();
			wrapper.setStyle(Object.extend({},{
				overflow:'hidden',
				width:element.getStyle('width'),
				height:element.getStyle('height'),
				position:element.getStyle('position'),
				left:element.getStyle('left'),
				top:element.getStyle('top')
			}));
			element.setStyle({top:'0px',left:'0px'});
			element.show();
			if (options.heading == 'in') {
				
				element.setStyle({left:(-1*width)+'px'});
			}
		}	
			
		Object.extend(element,{
			options:options
		});
		
		new Effect.Move(element, { 
			x: width,
			afterFinish: function(effect){			
				
				var parent = effect.element.up();
				var visible = Math.abs(element.getStyle('left').replace(/px/,'')) < 5;
				effect.element.setStyle(Object.extend({},{
					overflow:'visible',
					position:parent.getStyle('position'),
					width:element.getStyle('width'),
					height:element.getStyle('height'),
					left:parent.getStyle('left'),
					top:parent.getStyle('top'),
					display:parent.getStyle('display')
				}));
				parent.insert({before:effect.element});
				if (!visible) effect.element.hide(effect.element);
									
				parent.remove();					
			}
		});	
	}
}

//adds onDraw and constrainToViewport option to draggable
if(typeof(Draggable) != 'undefined'){
	//allows the point to be modified with an onDraw callback
	Draggable.prototype.draw = function(point) {
		var pos = Position.cumulativeOffset(this.element);
		if(this.options.ghosting) {
			var r = Position.realOffset(this.element);
			pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY;
		}
		
		var d = this.currentDelta();
		pos[0] -= d[0]; pos[1] -= d[1];
		
		if(this.options.scroll && (this.options.scroll != window && this._isScrollChild)) {
			pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft;
			pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop;
		}
		
		var p = [0,1].map(function(i){ 
			return (point[i]-pos[i]-this.offset[i]) 
		}.bind(this));
		
		if(this.options.snap) {
			if(typeof this.options.snap == 'function') {
				p = this.options.snap(p[0],p[1],this);
			} else {
				if(this.options.snap instanceof Array) {
					p = p.map( function(v, i) {return Math.round(v/this.options.snap[i])*this.options.snap[i] }.bind(this))
				} else {
					p = p.map( function(v) {return Math.round(v/this.options.snap)*this.options.snap }.bind(this))
	  			}
			}
		}
		
		if(this.options.onDraw)
			this.options.onDraw.bind(this)(p);
		else{
			var style = this.element.style;
			if(this.options.constrainToViewport){
				var viewport_dimensions = document.viewport.getDimensions();
				var container_dimensions = this.element.getDimensions();
				var margin_top = parseInt(this.element.getStyle('margin-top'));
				var margin_left = parseInt(this.element.getStyle('margin-left'));
				var boundary = [[
					0 - margin_left,
					0 - margin_top
				],[
					(viewport_dimensions.width - container_dimensions.width) - margin_left,
					(viewport_dimensions.height - container_dimensions.height) - margin_top
				]];
				if((!this.options.constraint) || (this.options.constraint=='horizontal')){ 
					if((p[0] >= boundary[0][0]) && (p[0] <= boundary[1][0]))
						this.element.style.left = p[0] + "px";
					else
						this.element.style.left = ((p[0] < boundary[0][0]) ? boundary[0][0] : boundary[1][0]) + "px";
				} 
				if((!this.options.constraint) || (this.options.constraint=='vertical')){ 
					if((p[1] >= boundary[0][1] ) && (p[1] <= boundary[1][1]))
						this.element.style.top = p[1] + "px";
				  else
						this.element.style.top = ((p[1] <= boundary[0][1]) ? boundary[0][1] : boundary[1][1]) + "px";			   
				}
			}else{
				if((!this.options.constraint) || (this.options.constraint=='horizontal'))
				  style.left = p[0] + "px";
				if((!this.options.constraint) || (this.options.constraint=='vertical'))
				  style.top	 = p[1] + "px";
			}
			if(style.visibility=="hidden")
				style.visibility = ""; // fix gecko rendering
		}
	};
}


/*
**
** File 'swfobject_2_1.js'
**
*/
/* SWFObject v2.1 <http://code.google.com/p/swfobject/>
	Copyright (c) 2007-2008 Geoff Stearns, Michael Williams, and Bobby van der Sluis
	This software is released under the MIT License <http://www.opensource.org/licenses/mit-license.php>
*/
var swfobject=function(){var b="undefined",Q="object",n="Shockwave Flash",p="ShockwaveFlash.ShockwaveFlash",P="application/x-shockwave-flash",m="SWFObjectExprInst",j=window,K=document,T=navigator,o=[],N=[],i=[],d=[],J,Z=null,M=null,l=null,e=false,A=false;var h=function(){var v=typeof K.getElementById!=b&&typeof K.getElementsByTagName!=b&&typeof K.createElement!=b,AC=[0,0,0],x=null;if(typeof T.plugins!=b&&typeof T.plugins[n]==Q){x=T.plugins[n].description;if(x&&!(typeof T.mimeTypes!=b&&T.mimeTypes[P]&&!T.mimeTypes[P].enabledPlugin)){x=x.replace(/^.*\s+(\S+\s+\S+$)/,"$1");AC[0]=parseInt(x.replace(/^(.*)\..*$/,"$1"),10);AC[1]=parseInt(x.replace(/^.*\.(.*)\s.*$/,"$1"),10);AC[2]=/r/.test(x)?parseInt(x.replace(/^.*r(.*)$/,"$1"),10):0}}else{if(typeof j.ActiveXObject!=b){var y=null,AB=false;try{y=new ActiveXObject(p+".7")}catch(t){try{y=new ActiveXObject(p+".6");AC=[6,0,21];y.AllowScriptAccess="always"}catch(t){if(AC[0]==6){AB=true}}if(!AB){try{y=new ActiveXObject(p)}catch(t){}}}if(!AB&&y){try{x=y.GetVariable("$version");if(x){x=x.split(" ")[1].split(",");AC=[parseInt(x[0],10),parseInt(x[1],10),parseInt(x[2],10)]}}catch(t){}}}}var AD=T.userAgent.toLowerCase(),r=T.platform.toLowerCase(),AA=/webkit/.test(AD)?parseFloat(AD.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,q=false,z=r?/win/.test(r):/win/.test(AD),w=r?/mac/.test(r):/mac/.test(AD);/*@cc_on q=true;@if(@_win32)z=true;@elif(@_mac)w=true;@end@*/return{w3cdom:v,pv:AC,webkit:AA,ie:q,win:z,mac:w}}();var L=function(){if(!h.w3cdom){return }f(H);if(h.ie&&h.win){try{K.write("<script id=__ie_ondomload defer=true src=//:><\/script>");J=C("__ie_ondomload");if(J){I(J,"onreadystatechange",S)}}catch(q){}}if(h.webkit&&typeof K.readyState!=b){Z=setInterval(function(){if(/loaded|complete/.test(K.readyState)){E()}},10)}if(typeof K.addEventListener!=b){K.addEventListener("DOMContentLoaded",E,null)}R(E)}();function S(){if(J.readyState=="complete"){J.parentNode.removeChild(J);E()}}function E(){if(e){return }if(h.ie&&h.win){var v=a("span");try{var u=K.getElementsByTagName("body")[0].appendChild(v);u.parentNode.removeChild(u)}catch(w){return }}e=true;if(Z){clearInterval(Z);Z=null}var q=o.length;for(var r=0;r<q;r++){o[r]()}}function f(q){if(e){q()}else{o[o.length]=q}}function R(r){if(typeof j.addEventListener!=b){j.addEventListener("load",r,false)}else{if(typeof K.addEventListener!=b){K.addEventListener("load",r,false)}else{if(typeof j.attachEvent!=b){I(j,"onload",r)}else{if(typeof j.onload=="function"){var q=j.onload;j.onload=function(){q();r()}}else{j.onload=r}}}}}function H(){var t=N.length;for(var q=0;q<t;q++){var u=N[q].id;if(h.pv[0]>0){var r=C(u);if(r){N[q].width=r.getAttribute("width")?r.getAttribute("width"):"0";N[q].height=r.getAttribute("height")?r.getAttribute("height"):"0";if(c(N[q].swfVersion)){if(h.webkit&&h.webkit<312){Y(r)}W(u,true)}else{if(N[q].expressInstall&&!A&&c("6.0.65")&&(h.win||h.mac)){k(N[q])}else{O(r)}}}}else{W(u,true)}}}function Y(t){var q=t.getElementsByTagName(Q)[0];if(q){var w=a("embed"),y=q.attributes;if(y){var v=y.length;for(var u=0;u<v;u++){if(y[u].nodeName=="DATA"){w.setAttribute("src",y[u].nodeValue)}else{w.setAttribute(y[u].nodeName,y[u].nodeValue)}}}var x=q.childNodes;if(x){var z=x.length;for(var r=0;r<z;r++){if(x[r].nodeType==1&&x[r].nodeName=="PARAM"){w.setAttribute(x[r].getAttribute("name"),x[r].getAttribute("value"))}}}t.parentNode.replaceChild(w,t)}}function k(w){A=true;var u=C(w.id);if(u){if(w.altContentId){var y=C(w.altContentId);if(y){M=y;l=w.altContentId}}else{M=G(u)}if(!(/%$/.test(w.width))&&parseInt(w.width,10)<310){w.width="310"}if(!(/%$/.test(w.height))&&parseInt(w.height,10)<137){w.height="137"}K.title=K.title.slice(0,47)+" - Flash Player Installation";var z=h.ie&&h.win?"ActiveX":"PlugIn",q=K.title,r="MMredirectURL="+j.location+"&MMplayerType="+z+"&MMdoctitle="+q,x=w.id;if(h.ie&&h.win&&u.readyState!=4){var t=a("div");x+="SWFObjectNew";t.setAttribute("id",x);u.parentNode.insertBefore(t,u);u.style.display="none";var v=function(){u.parentNode.removeChild(u)};I(j,"onload",v)}U({data:w.expressInstall,id:m,width:w.width,height:w.height},{flashvars:r},x)}}function O(t){if(h.ie&&h.win&&t.readyState!=4){var r=a("div");t.parentNode.insertBefore(r,t);r.parentNode.replaceChild(G(t),r);t.style.display="none";var q=function(){t.parentNode.removeChild(t)};I(j,"onload",q)}else{t.parentNode.replaceChild(G(t),t)}}function G(v){var u=a("div");if(h.win&&h.ie){u.innerHTML=v.innerHTML}else{var r=v.getElementsByTagName(Q)[0];if(r){var w=r.childNodes;if(w){var q=w.length;for(var t=0;t<q;t++){if(!(w[t].nodeType==1&&w[t].nodeName=="PARAM")&&!(w[t].nodeType==8)){u.appendChild(w[t].cloneNode(true))}}}}}return u}function U(AG,AE,t){var q,v=C(t);if(v){if(typeof AG.id==b){AG.id=t}if(h.ie&&h.win){var AF="";for(var AB in AG){if(AG[AB]!=Object.prototype[AB]){if(AB.toLowerCase()=="data"){AE.movie=AG[AB]}else{if(AB.toLowerCase()=="styleclass"){AF+=' class="'+AG[AB]+'"'}else{if(AB.toLowerCase()!="classid"){AF+=" "+AB+'="'+AG[AB]+'"'}}}}}var AD="";for(var AA in AE){if(AE[AA]!=Object.prototype[AA]){AD+='<param name="'+AA+'" value="'+AE[AA]+'" />'}}v.outerHTML='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"'+AF+">"+AD+"</object>";i[i.length]=AG.id;q=C(AG.id)}else{if(h.webkit&&h.webkit<312){var AC=a("embed");AC.setAttribute("type",P);for(var z in AG){if(AG[z]!=Object.prototype[z]){if(z.toLowerCase()=="data"){AC.setAttribute("src",AG[z])}else{if(z.toLowerCase()=="styleclass"){AC.setAttribute("class",AG[z])}else{if(z.toLowerCase()!="classid"){AC.setAttribute(z,AG[z])}}}}}for(var y in AE){if(AE[y]!=Object.prototype[y]){if(y.toLowerCase()!="movie"){AC.setAttribute(y,AE[y])}}}v.parentNode.replaceChild(AC,v);q=AC}else{var u=a(Q);u.setAttribute("type",P);for(var x in AG){if(AG[x]!=Object.prototype[x]){if(x.toLowerCase()=="styleclass"){u.setAttribute("class",AG[x])}else{if(x.toLowerCase()!="classid"){u.setAttribute(x,AG[x])}}}}for(var w in AE){if(AE[w]!=Object.prototype[w]&&w.toLowerCase()!="movie"){F(u,w,AE[w])}}v.parentNode.replaceChild(u,v);q=u}}}return q}function F(t,q,r){var u=a("param");u.setAttribute("name",q);u.setAttribute("value",r);t.appendChild(u)}function X(r){var q=C(r);if(q&&(q.nodeName=="OBJECT"||q.nodeName=="EMBED")){if(h.ie&&h.win){if(q.readyState==4){B(r)}else{j.attachEvent("onload",function(){B(r)})}}else{q.parentNode.removeChild(q)}}}function B(t){var r=C(t);if(r){for(var q in r){if(typeof r[q]=="function"){r[q]=null}}r.parentNode.removeChild(r)}}function C(t){var q=null;try{q=K.getElementById(t)}catch(r){}return q}function a(q){return K.createElement(q)}function I(t,q,r){t.attachEvent(q,r);d[d.length]=[t,q,r]}function c(t){var r=h.pv,q=t.split(".");q[0]=parseInt(q[0],10);q[1]=parseInt(q[1],10)||0;q[2]=parseInt(q[2],10)||0;return(r[0]>q[0]||(r[0]==q[0]&&r[1]>q[1])||(r[0]==q[0]&&r[1]==q[1]&&r[2]>=q[2]))?true:false}function V(v,r){if(h.ie&&h.mac){return }var u=K.getElementsByTagName("head")[0],t=a("style");t.setAttribute("type","text/css");t.setAttribute("media","screen");if(!(h.ie&&h.win)&&typeof K.createTextNode!=b){t.appendChild(K.createTextNode(v+" {"+r+"}"))}u.appendChild(t);if(h.ie&&h.win&&typeof K.styleSheets!=b&&K.styleSheets.length>0){var q=K.styleSheets[K.styleSheets.length-1];if(typeof q.addRule==Q){q.addRule(v,r)}}}function W(t,q){var r=q?"visible":"hidden";if(e&&C(t)){C(t).style.visibility=r}else{V("#"+t,"visibility:"+r)}}function g(s){var r=/[\\\"<>\.;]/;var q=r.exec(s)!=null;return q?encodeURIComponent(s):s}var D=function(){if(h.ie&&h.win){window.attachEvent("onunload",function(){var w=d.length;for(var v=0;v<w;v++){d[v][0].detachEvent(d[v][1],d[v][2])}var t=i.length;for(var u=0;u<t;u++){X(i[u])}for(var r in h){h[r]=null}h=null;for(var q in swfobject){swfobject[q]=null}swfobject=null})}}();return{registerObject:function(u,q,t){if(!h.w3cdom||!u||!q){return }var r={};r.id=u;r.swfVersion=q;r.expressInstall=t?t:false;N[N.length]=r;W(u,false)},getObjectById:function(v){var q=null;if(h.w3cdom){var t=C(v);if(t){var u=t.getElementsByTagName(Q)[0];if(!u||(u&&typeof t.SetVariable!=b)){q=t}else{if(typeof u.SetVariable!=b){q=u}}}}return q},embedSWF:function(x,AE,AB,AD,q,w,r,z,AC){if(!h.w3cdom||!x||!AE||!AB||!AD||!q){return }AB+="";AD+="";if(c(q)){W(AE,false);var AA={};if(AC&&typeof AC===Q){for(var v in AC){if(AC[v]!=Object.prototype[v]){AA[v]=AC[v]}}}AA.data=x;AA.width=AB;AA.height=AD;var y={};if(z&&typeof z===Q){for(var u in z){if(z[u]!=Object.prototype[u]){y[u]=z[u]}}}if(r&&typeof r===Q){for(var t in r){if(r[t]!=Object.prototype[t]){if(typeof y.flashvars!=b){y.flashvars+="&"+t+"="+r[t]}else{y.flashvars=t+"="+r[t]}}}}f(function(){U(AA,y,AE);if(AA.id==AE){W(AE,true)}})}else{if(w&&!A&&c("6.0.65")&&(h.win||h.mac)){A=true;W(AE,false);f(function(){var AF={};AF.id=AF.altContentId=AE;AF.width=AB;AF.height=AD;AF.expressInstall=w;k(AF)})}}},getFlashPlayerVersion:function(){return{major:h.pv[0],minor:h.pv[1],release:h.pv[2]}},hasFlashPlayerVersion:c,createSWF:function(t,r,q){if(h.w3cdom){return U(t,r,q)}else{return undefined}},removeSWF:function(q){if(h.w3cdom){X(q)}},createCSS:function(r,q){if(h.w3cdom){V(r,q)}},addDomLoadEvent:f,addLoadEvent:R,getQueryParamValue:function(v){var u=K.location.search||K.location.hash;if(v==null){return g(u)}if(u){var t=u.substring(1).split("&");for(var r=0;r<t.length;r++){if(t[r].substring(0,t[r].indexOf("="))==v){return g(t[r].substring((t[r].indexOf("=")+1)))}}}return""},expressInstallCallback:function(){if(A&&M){var q=C(m);if(q){q.parentNode.replaceChild(M,q);if(l){W(l,true);if(h.ie&&h.win){M.style.display="block"}}M=null;l=null;A=false}}}}}();
/*
**
** File 'rounded_corners.inc.js'
**
*/

 /****************************************************************
  *                                                              *
  *  curvyCorners                                                *
  *  ------------                                                *
  *                                                              *
  *  This script generates rounded corners for your divs.        *
  *                                                              *
  *  Version 1.2.9                                               *
  *  Copyright (c) 2006 Cameron Cooke                            *
  *  By: Cameron Cooke and Tim Hutchison.                        *
  *                                                              *
  *                                                              *
  *  Website: http://www.curvycorners.net                        *
  *  Email:   info@totalinfinity.com                             *
  *  Forum:   http://www.curvycorners.net/forum/                 *
  *                                                              *
  *                                                              *
  *  This library is free software; you can redistribute         *
  *  it and/or modify it under the terms of the GNU              *
  *  Lesser General Public License as published by the           *
  *  Free Software Foundation; either version 2.1 of the         *
  *  License, or (at your option) any later version.             *
  *                                                              *
  *  This library is distributed in the hope that it will        *
  *  be useful, but WITHOUT ANY WARRANTY; without even the       *
  *  implied warranty of MERCHANTABILITY or FITNESS FOR A        *
  *  PARTICULAR PURPOSE. See the GNU Lesser General Public       *
  *  License for more details.                                   *
  *                                                              *
  *  You should have received a copy of the GNU Lesser           *
  *  General Public License along with this library;             *
  *  Inc., 59 Temple Place, Suite 330, Boston,                   *
  *  MA 02111-1307 USA                                           *
  *                                                              *
  ****************************************************************/

  // Browser detection
  var isIE     = navigator.userAgent.toLowerCase().indexOf("msie") > -1;
  var isMoz    = document.implementation && document.implementation.createDocument;
  var isSafari = ((navigator.userAgent.toLowerCase().indexOf('safari')!=-1)&&(navigator.userAgent.toLowerCase().indexOf('mac')!=-1))?true:false;

  /*
  Usage:

  newCornersObj = new curvyCorners(settingsObj, "classNameStr");
  newCornersObj = new curvyCorners(settingsObj, divObj1[, divObj2[, divObj3[, . . . [, divObjN]]]]);
  */
  function curvyCorners()
  {
      // Check parameters
      if(typeof(arguments[0]) != "object") throw newCurvyError("First parameter of curvyCorners() must be an object.");
      if(typeof(arguments[1]) != "object" && typeof(arguments[1]) != "string") throw newCurvyError("Second parameter of curvyCorners() must be an object or a class name.");

      // Get object(s)
      if(typeof(arguments[1]) == "string")
      {
          // Get elements by class name
          var startIndex = 0;
          var boxCol = getElementsByClass(arguments[1]);
      }
      else
      {
          // Get objects
          var startIndex = 1;
          var boxCol = arguments;
      }

      // Create return collection/object
      var curvyCornersCol = new Array();

      // Create array of html elements that can have rounded corners
      if(arguments[0].validTags)
        var validElements = arguments[0].validTags;
      else
        var validElements = ["div"]; // Default

      // Loop through each argument
      for(var i = startIndex, j = boxCol.length; i < j; i++)
      {
          // Current element tag name
          var currentTag = boxCol[i].tagName.toLowerCase();

          if(inArray(validElements, currentTag) !== false)
          {
              curvyCornersCol[curvyCornersCol.length] = new curvyObject(arguments[0], boxCol[i]);
          }
      }

      this.objects = curvyCornersCol;

      // Applys the curvyCorners to all objects
      this.applyCornersToAll = function()
      {
          for(var x = 0, k = this.objects.length; x < k; x++)
          {
              this.objects[x].applyCorners();
          }
      }
  }

  // curvyCorners object (can be called directly)
  function curvyObject()
  {
      // Setup Globals
      this.box              = arguments[1];
      this.settings         = arguments[0];
      this.topContainer     = null;
      this.bottomContainer  = null;
      this.masterCorners    = new Array();
      this.contentDIV       = null;

      // Get box formatting details
      var boxHeight       = get_style(this.box, "height", "height");
      var boxWidth        = get_style(this.box, "width", "width");
      var borderWidth     = get_style(this.box, "borderTopWidth", "border-top-width");
      var borderColour    = get_style(this.box, "borderTopColor", "border-top-color");
      var boxColour       = get_style(this.box, "backgroundColor", "background-color");
      var backgroundImage = get_style(this.box, "backgroundImage", "background-image");
      var boxPosition     = get_style(this.box, "position", "position");
      var boxPadding      = get_style(this.box, "paddingTop", "padding-top");

      // Set formatting propertes
      this.boxHeight       = parseInt(((boxHeight != "" && boxHeight != "auto" && boxHeight.indexOf("%") == -1)? boxHeight.substring(0, boxHeight.indexOf("px")) : this.box.scrollHeight));
      this.boxWidth        = parseInt(((boxWidth != "" && boxWidth != "auto" && boxWidth.indexOf("%") == -1)? boxWidth.substring(0, boxWidth.indexOf("px")) : this.box.scrollWidth));
      this.borderWidth     = parseInt(((borderWidth != "" && borderWidth.indexOf("px") !== -1)? borderWidth.slice(0, borderWidth.indexOf("px")) : 0));
      this.boxColour       = format_colour(boxColour);
      this.boxPadding      = parseInt(((boxPadding != "" && boxPadding.indexOf("px") !== -1)? boxPadding.slice(0, boxPadding.indexOf("px")) : 0));
      this.borderColour    = format_colour(borderColour);
      this.borderString    = this.borderWidth + "px" + " solid " + this.borderColour;
      this.backgroundImage = ((backgroundImage != "none")? backgroundImage : "");
      this.boxContent      = this.box.innerHTML;

      // Make box relative if not already absolute and remove any padding
      if(boxPosition != "absolute") this.box.style.position = "relative";
      this.box.style.padding = "0px";

      // If IE and height and width are not set, we need to set width so that we get positioning
      if(isIE && boxWidth == "auto" && boxHeight == "auto") this.box.style.width = "100%";

      // Resize box so that it stays to the orignal height


      // Remove content if box is using autoPad
      if(this.settings.autoPad == true && this.boxPadding > 0)
        this.box.innerHTML = "";

      /*
      This method creates the corners and
      applies them to the div element.
      */
      this.applyCorners = function()
      {
          /*
          Create top and bottom containers.
          These will be used as a parent for the corners and bars.
          */
          for(var t = 0; t < 2; t++)
          {
              switch(t)
              {
                  // Top
                  case 0:

                      // Only build top bar if a top corner is to be draw
                      if(this.settings.tl || this.settings.tr)
                      {
                          var newMainContainer = document.createElement("DIV");
                          newMainContainer.style.width    = "100%";
                          newMainContainer.style.fontSize = "1px";
                          newMainContainer.style.overflow = "hidden";
                          newMainContainer.style.position = "absolute";
                          newMainContainer.style.paddingLeft  = this.borderWidth + "px";
                          newMainContainer.style.paddingRight = this.borderWidth + "px";
                          var topMaxRadius = Math.max(this.settings.tl ? this.settings.tl.radius : 0, this.settings.tr ? this.settings.tr.radius : 0);
                          newMainContainer.style.height = topMaxRadius + "px";
                          newMainContainer.style.top    = 0 - topMaxRadius + "px";
                          newMainContainer.style.left   = 0 - this.borderWidth + "px";
                          this.topContainer = this.box.appendChild(newMainContainer);
                      }
                      break;

                  // Bottom
                  case 1:

                      // Only build bottom bar if a top corner is to be draw
                      if(this.settings.bl || this.settings.br)
                      {
                          var newMainContainer = document.createElement("DIV");
                          newMainContainer.style.width    = "100%";
                          newMainContainer.style.fontSize = "1px";
                          newMainContainer.style.overflow = "hidden";
                          newMainContainer.style.position = "absolute";
                          newMainContainer.style.paddingLeft  = this.borderWidth + "px";
                          newMainContainer.style.paddingRight = this.borderWidth + "px";
                          var botMaxRadius = Math.max(this.settings.bl ? this.settings.bl.radius : 0, this.settings.br ? this.settings.br.radius : 0);
                          newMainContainer.style.height  = botMaxRadius + "px";
                          newMainContainer.style.bottom  =  0 - botMaxRadius + "px";
                          newMainContainer.style.left    =  0 - this.borderWidth + "px";
                          this.bottomContainer = this.box.appendChild(newMainContainer);
                      }
                      break;
              }
          }

          // Turn off current borders
          if(this.topContainer) this.box.style.borderTopWidth = "0px";
          if(this.bottomContainer) this.box.style.borderBottomWidth = "0px";

          // Create array of available corners
          var corners = ["tr", "tl", "br", "bl"];

          /*
          Loop for each corner
          */
          for(var i in corners)
          {
              // FIX for prototype lib
              if(i > -1 < 4)
              {
                  // Get current corner type from array
                  var cc = corners[i];

                  // Has the user requested the currentCorner be round?
                  if(!this.settings[cc])
                  {
                      // No
                      if(((cc == "tr" || cc == "tl") && this.topContainer != null) || ((cc == "br" || cc == "bl") && this.bottomContainer != null))
                      {
                          // We need to create a filler div to fill the space upto the next horzontal corner.
                          var newCorner = document.createElement("DIV");

                          // Setup corners properties
                          newCorner.style.position = "relative";
                          newCorner.style.fontSize = "1px";
                          newCorner.style.overflow = "hidden";

                          // Add background image?
                          if(this.backgroundImage == "")
                            newCorner.style.backgroundColor = this.boxColour;
                          else
                            newCorner.style.backgroundImage = this.backgroundImage;

                          switch(cc)
                          {
                              case "tl":
                                  newCorner.style.height      = topMaxRadius - this.borderWidth + "px";
                                  newCorner.style.marginRight = this.settings.tr.radius - (this.borderWidth*2) + "px";
                                  newCorner.style.borderLeft  = this.borderString;
                                  newCorner.style.borderTop   = this.borderString;
                                  newCorner.style.left        = -this.borderWidth + "px";
                                  break;

                              case "tr":
                                  newCorner.style.height      = topMaxRadius - this.borderWidth + "px";
                                  newCorner.style.marginLeft  = this.settings.tl.radius - (this.borderWidth*2) + "px";
                                  newCorner.style.borderRight = this.borderString;
                                  newCorner.style.borderTop   = this.borderString;
                                  newCorner.style.backgroundPosition  = "-" + (topMaxRadius + this.borderWidth) + "px 0px";
                                  newCorner.style.left        = this.borderWidth + "px";
                                  break;

                              case "bl":
                                  newCorner.style.height       = botMaxRadius - this.borderWidth + "px";
                                  newCorner.style.marginRight  = this.settings.br.radius - (this.borderWidth*2) + "px";
                                  newCorner.style.borderLeft   = this.borderString;
                                  newCorner.style.borderBottom = this.borderString;
                                  newCorner.style.left         = -this.borderWidth + "px";
                                  newCorner.style.backgroundPosition = "-" + (this.borderWidth) + "px -" + (this.boxHeight + (botMaxRadius + this.borderWidth)) + "px";
                                  break;

                              case "br":
                                  newCorner.style.height       = botMaxRadius - this.borderWidth + "px";
                                  newCorner.style.marginLeft   = this.settings.bl.radius - (this.borderWidth*2) + "px";
                                  newCorner.style.borderRight  = this.borderString;
                                  newCorner.style.borderBottom = this.borderString;
                                  newCorner.style.left         = this.borderWidth + "px"
                                  newCorner.style.backgroundPosition = "-" + (botMaxRadius + this.borderWidth) + "px -" + (this.boxHeight + (botMaxRadius + this.borderWidth)) + "px";
                                  break;
                          }
                      }
                  }
                  else
                  {
                      /*
                      PERFORMANCE NOTE:

                      If more than one corner is requested and a corner has been already
                      created for the same radius then that corner will be used as a master and cloned.
                      The pixel bars will then be repositioned to form the new corner type.
                      All new corners start as a bottom right corner.
                      */
                      if(this.masterCorners[this.settings[cc].radius])
                      {
                          // Create clone of the master corner
                          var newCorner = this.masterCorners[this.settings[cc].radius].cloneNode(true);
                      }
                      else
                      {
                          // Yes, we need to create a new corner
                          var newCorner = document.createElement("DIV");
                          newCorner.style.height = this.settings[cc].radius + "px";
                          newCorner.style.width  = this.settings[cc].radius + "px";
                          newCorner.style.position = "absolute";
                          newCorner.style.fontSize = "1px";
                          newCorner.style.overflow = "hidden";

                          // THE FOLLOWING BLOCK OF CODE CREATES A ROUNDED CORNER
                          // ---------------------------------------------------- TOP

                          // Get border radius
                          var borderRadius = parseInt(this.settings[cc].radius - this.borderWidth);

                          // Cycle the x-axis
                          for(var intx = 0, j = this.settings[cc].radius; intx < j; intx++)
                          {
                              // Calculate the value of y1 which identifies the pixels inside the border
                              if((intx +1) >= borderRadius)
                                var y1 = -1;
                              else
                                var y1 = (Math.floor(Math.sqrt(Math.pow(borderRadius, 2) - Math.pow((intx+1), 2))) - 1);

                              // Only calculate y2 and y3 if there is a border defined
                              if(borderRadius != j)
                              {
                                  if((intx) >= borderRadius)
                                    var y2 = -1;
                                  else
                                    var y2 = Math.ceil(Math.sqrt(Math.pow(borderRadius,2) - Math.pow(intx, 2)));

                                  if((intx+1) >= j)
                                    var y3 = -1;
                                  else
                                    var y3 = (Math.floor(Math.sqrt(Math.pow(j ,2) - Math.pow((intx+1), 2))) - 1);
                              }

                              // Calculate y4
                              if((intx) >= j)
                                var y4 = -1;
                              else
                                var y4 = Math.ceil(Math.sqrt(Math.pow(j ,2) - Math.pow(intx, 2)));

                              // Draw bar on inside of the border with foreground colour
                              if(y1 > -1) this.drawPixel(intx, 0, this.boxColour, 100, (y1+1), newCorner, -1, this.settings[cc].radius);

                              // Only draw border/foreground antialiased pixels and border if there is a border defined
                              if(borderRadius != j)
                              {
                                  // Cycle the y-axis
                                  for(var inty = (y1 + 1); inty < y2; inty++)
                                  {
                                      // Draw anti-alias pixels
                                      if(this.settings.antiAlias)
                                      {
                                          // For each of the pixels that need anti aliasing between the foreground and border colour draw single pixel divs
                                          if(this.backgroundImage != "")
                                          {
                                              var borderFract = (pixelFraction(intx, inty, borderRadius) * 100);

                                              if(borderFract < 30)
                                              {
										                                        this.drawPixel(intx, inty, this.borderColour, 100, 1, newCorner, 0, this.settings[cc].radius);
                                              }
									                                     else
                                              {
									                                         this.drawPixel(intx, inty, this.borderColour, 100, 1, newCorner, -1, this.settings[cc].radius);
                                              }
                                          }
                                          else
                                          {
                                              var pixelcolour = BlendColour(this.boxColour, this.borderColour, pixelFraction(intx, inty, borderRadius));
                                              this.drawPixel(intx, inty, pixelcolour, 100, 1, newCorner, 0, this.settings[cc].radius, cc);
                                          }
                                      }
                                  }

                                  // Draw bar for the border
                                  if(this.settings.antiAlias)
                                  {
                                      if(y3 >= y2)
                                      {
                                         if (y2 == -1) y2 = 0;
                                         this.drawPixel(intx, y2, this.borderColour, 100, (y3 - y2 + 1), newCorner, 0, 0);
                                      }
                                  }
                                  else
                                  {
                                      if(y3 >= y1)
                                      {
                                          this.drawPixel(intx, (y1 + 1), this.borderColour, 100, (y3 - y1), newCorner, 0, 0);
                                      }
                                  }

                                  // Set the colour for the outside curve
                                  var outsideColour = this.borderColour;
                              }
                              else
                              {
                                  // Set the coour for the outside curve
                                  var outsideColour = this.boxColour;
                                  var y3 = y1;
                              }

                              // Draw aa pixels?
                              if(this.settings.antiAlias)
                              {
                                  // Cycle the y-axis and draw the anti aliased pixels on the outside of the curve
                                  for(var inty = (y3 + 1); inty < y4; inty++)
                                  {
                                      // For each of the pixels that need anti aliasing between the foreground/border colour & background draw single pixel divs
                                      this.drawPixel(intx, inty, outsideColour, (pixelFraction(intx, inty , j) * 100), 1, newCorner, ((this.borderWidth > 0)? 0 : -1), this.settings[cc].radius);
                                  }
                              }
                          }

                          // END OF CORNER CREATION
                          // ---------------------------------------------------- END

                          // We now need to store the current corner in the masterConers array
                          this.masterCorners[this.settings[cc].radius] = newCorner.cloneNode(true);
                      }

                      /*
                      Now we have a new corner we need to reposition all the pixels unless
                      the current corner is the bottom right.
                      */
                      if(cc != "br")
                      {
                          // Loop through all children (pixel bars)
                          for(var t = 0, k = newCorner.childNodes.length; t < k; t++)
                          {
                              // Get current pixel bar
                              var pixelBar = newCorner.childNodes[t];

                              // Get current top and left properties
                              var pixelBarTop    = parseInt(pixelBar.style.top.substring(0, pixelBar.style.top.indexOf("px")));
                              var pixelBarLeft   = parseInt(pixelBar.style.left.substring(0, pixelBar.style.left.indexOf("px")));
                              var pixelBarHeight = parseInt(pixelBar.style.height.substring(0, pixelBar.style.height.indexOf("px")));

                              // Reposition pixels
                              if(cc == "tl" || cc == "bl"){
                                  pixelBar.style.left = this.settings[cc].radius -pixelBarLeft -1 + "px"; // Left
                              }
                              if(cc == "tr" || cc == "tl"){
                                  pixelBar.style.top =  this.settings[cc].radius -pixelBarHeight -pixelBarTop + "px"; // Top
                              }

                              switch(cc)
                              {
                                  case "tr":
                                      pixelBar.style.backgroundPosition  = "-" + Math.abs((this.boxWidth - this.settings[cc].radius + this.borderWidth) + pixelBarLeft) + "px -" + Math.abs(this.settings[cc].radius -pixelBarHeight -pixelBarTop - this.borderWidth) + "px";
                                      break;

                                  case "tl":
                                      pixelBar.style.backgroundPosition = "-" + Math.abs((this.settings[cc].radius -pixelBarLeft -1)  - this.borderWidth) + "px -" + Math.abs(this.settings[cc].radius -pixelBarHeight -pixelBarTop - this.borderWidth) + "px";
                                      break;

                                  case "bl":
                                      pixelBar.style.backgroundPosition = "-" + Math.abs((this.settings[cc].radius -pixelBarLeft -1) - this.borderWidth) + "px -" + Math.abs((this.boxHeight + this.settings[cc].radius + pixelBarTop) -this.borderWidth) + "px";
                                      break;
                              }
                          }
                      }
                  }

                  if(newCorner)
                  {
                      // Position the container
                      switch(cc)
                      {
                          case "tl":
                            if(newCorner.style.position == "absolute") newCorner.style.top  = "0px";
                            if(newCorner.style.position == "absolute") newCorner.style.left = "0px";
                            if(this.topContainer) this.topContainer.appendChild(newCorner);
                            break;

                          case "tr":
                            if(newCorner.style.position == "absolute") newCorner.style.top  = "0px";
                            if(newCorner.style.position == "absolute") newCorner.style.right = "0px";
                            if(this.topContainer) this.topContainer.appendChild(newCorner);
                            break;

                          case "bl":
                            if(newCorner.style.position == "absolute") newCorner.style.bottom  = "0px";
                            if(newCorner.style.position == "absolute") newCorner.style.left = "0px";
                            if(this.bottomContainer) this.bottomContainer.appendChild(newCorner);
                            break;

                          case "br":
                            if(newCorner.style.position == "absolute") newCorner.style.bottom   = "0px";
                            if(newCorner.style.position == "absolute") newCorner.style.right = "0px";
                            if(this.bottomContainer) this.bottomContainer.appendChild(newCorner);
                            break;
                      }
                  }
              }
          }

          /*
          The last thing to do is draw the rest of the filler DIVs.
          We only need to create a filler DIVs when two corners have
          diffrent radiuses in either the top or bottom container.
          */

          // Find out which corner has the biiger radius and get the difference amount
          var radiusDiff = new Array();
          radiusDiff["t"] = Math.abs(this.settings.tl.radius - this.settings.tr.radius)
          radiusDiff["b"] = Math.abs(this.settings.bl.radius - this.settings.br.radius);

          for(z in radiusDiff)
          {
              // FIX for prototype lib
              if(z == "t" || z == "b")
              {
                  if(radiusDiff[z])
                  {
                      // Get the type of corner that is the smaller one
                      var smallerCornerType = ((this.settings[z + "l"].radius < this.settings[z + "r"].radius)? z +"l" : z +"r");

                      // First we need to create a DIV for the space under the smaller corner
                      var newFiller = document.createElement("DIV");
                      newFiller.style.height = radiusDiff[z] + "px";
                      newFiller.style.width  =  this.settings[smallerCornerType].radius+ "px"
                      newFiller.style.position = "absolute";
                      newFiller.style.fontSize = "1px";
                      newFiller.style.overflow = "hidden";
                      newFiller.style.backgroundColor = this.boxColour;
                      //newFiller.style.backgroundColor = get_random_color();

                      // Position filler
                      switch(smallerCornerType)
                      {
                          case "tl":
                              newFiller.style.bottom = "0px";
                              newFiller.style.left   = "0px";
                              newFiller.style.borderLeft = this.borderString;
                              this.topContainer.appendChild(newFiller);
                              break;

                          case "tr":
                              newFiller.style.bottom = "0px";
                              newFiller.style.right  = "0px";
                              newFiller.style.borderRight = this.borderString;
                              this.topContainer.appendChild(newFiller);
                              break;

                          case "bl":
                              newFiller.style.top    = "0px";
                              newFiller.style.left   = "0px";
                              newFiller.style.borderLeft = this.borderString;
                              this.bottomContainer.appendChild(newFiller);
                              break;

                          case "br":
                              newFiller.style.top    = "0px";
                              newFiller.style.right  = "0px";
                              newFiller.style.borderRight = this.borderString;
                              this.bottomContainer.appendChild(newFiller);
                              break;
                      }
                  }

                  // Create the bar to fill the gap between each corner horizontally
                  var newFillerBar = document.createElement("DIV");
                  newFillerBar.style.position = "relative";
                  newFillerBar.style.fontSize = "1px";
                  newFillerBar.style.overflow = "hidden";
                  newFillerBar.style.backgroundColor = this.boxColour;
                  newFillerBar.style.backgroundImage = this.backgroundImage;

                  switch(z)
                  {
                      case "t":
                          // Top Bar
                          if(this.topContainer)
                          {
                              // Edit by Asger Hallas: Check if settings.xx.radius is not false
                              if(this.settings.tl.radius && this.settings.tr.radius)
                              {
                                  newFillerBar.style.height      = topMaxRadius - this.borderWidth + "px";
                                  newFillerBar.style.marginLeft  = this.settings.tl.radius - this.borderWidth + "px";
                                  newFillerBar.style.marginRight = this.settings.tr.radius - this.borderWidth + "px";
                                  newFillerBar.style.borderTop   = this.borderString;

                                  if(this.backgroundImage != "")
                                    newFillerBar.style.backgroundPosition  = "-" + (topMaxRadius + this.borderWidth) + "px 0px";

                                  this.topContainer.appendChild(newFillerBar);
                              }

                              // Repos the boxes background image
                              this.box.style.backgroundPosition      = "0px -" + (topMaxRadius - this.borderWidth) + "px";
                          }
                          break;

                      case "b":
                          if(this.bottomContainer)
                          {
                              // Edit by Asger Hallas: Check if settings.xx.radius is not false
                              if(this.settings.bl.radius && this.settings.br.radius)
                              {
                                  // Bottom Bar
                                  newFillerBar.style.height       = botMaxRadius - this.borderWidth + "px";
                                  newFillerBar.style.marginLeft   = this.settings.bl.radius - this.borderWidth + "px";
                                  newFillerBar.style.marginRight  = this.settings.br.radius - this.borderWidth + "px";
                                  newFillerBar.style.borderBottom = this.borderString;

                                  if(this.backgroundImage != "")
                                    newFillerBar.style.backgroundPosition  = "-" + (botMaxRadius + this.borderWidth) + "px -" + (this.boxHeight + (topMaxRadius + this.borderWidth)) + "px";

                                  this.bottomContainer.appendChild(newFillerBar);
                              }
                          }
                          break;
                  }
              }
          }

          /*
          AutoPad! apply padding if set.
          */
          if(this.settings.autoPad == true && this.boxPadding > 0)
          {
              // Create content container
              var contentContainer = document.createElement("DIV");

              // Set contentContainer's properties
              contentContainer.style.position = "relative";
              contentContainer.innerHTML      = this.boxContent;
              contentContainer.className      = "autoPadDiv";

              // Get padding amounts
              var topPadding = Math.abs(topMaxRadius - this.boxPadding);
              var botPadding = Math.abs(botMaxRadius - this.boxPadding);

              // Apply top padding
              if(topMaxRadius < this.boxPadding)
                contentContainer.style.paddingTop = topPadding + "px";

              // Apply Bottom padding
              if(botMaxRadius < this.boxPadding)
                contentContainer.style.paddingBottom = botMaxRadius + "px";

              // Apply left and right padding
              contentContainer.style.paddingLeft = this.boxPadding + "px";
              contentContainer.style.paddingRight = this.boxPadding + "px";

              // Append contentContainer
              this.contentDIV = this.box.appendChild(contentContainer);
          }
      }

      /*
      This function draws the pixles
      */
      this.drawPixel = function(intx, inty, colour, transAmount, height, newCorner, image, cornerRadius)
      {
          // Create pixel
          var pixel = document.createElement("DIV");
          pixel.style.height   = height + "px";
          pixel.style.width    = "1px";
          pixel.style.position = "absolute";
          pixel.style.fontSize = "1px";
          pixel.style.overflow = "hidden";

          // Max Top Radius
          var topMaxRadius = Math.max(this.settings["tr"].radius, this.settings["tl"].radius);

          // Dont apply background image to border pixels
          if(image == -1 && this.backgroundImage != "")
          {
              pixel.style.backgroundImage = this.backgroundImage;
			           pixel.style.backgroundPosition  = "-" + (this.boxWidth - (cornerRadius - intx) + this.borderWidth) + "px -" + ((this.boxHeight + topMaxRadius + inty) -this.borderWidth) + "px";
		        }
          else
          {
              pixel.style.backgroundColor = colour;
          }

          // Set opacity if the transparency is anything other than 100
          if (transAmount != 100)
            setOpacity(pixel, transAmount);

          // Set the pixels position
          pixel.style.top = inty + "px";
          pixel.style.left = intx + "px";

          newCorner.appendChild(pixel);
      }
  }

  // ------------- UTILITY FUNCTIONS

  // Inserts a element after another
  function insertAfter(parent, node, referenceNode)
  {
	     parent.insertBefore(node, referenceNode.nextSibling);
  }

  /*
  Blends the two colours by the fraction
  returns the resulting colour as a string in the format "#FFFFFF"
  */
  function BlendColour(Col1, Col2, Col1Fraction)
  {
      var red1 = parseInt(Col1.substr(1,2),16);
      var green1 = parseInt(Col1.substr(3,2),16);
      var blue1 = parseInt(Col1.substr(5,2),16);
      var red2 = parseInt(Col2.substr(1,2),16);
      var green2 = parseInt(Col2.substr(3,2),16);
      var blue2 = parseInt(Col2.substr(5,2),16);

      if(Col1Fraction > 1 || Col1Fraction < 0) Col1Fraction = 1;

      var endRed = Math.round((red1 * Col1Fraction) + (red2 * (1 - Col1Fraction)));
      if(endRed > 255) endRed = 255;
      if(endRed < 0) endRed = 0;

      var endGreen = Math.round((green1 * Col1Fraction) + (green2 * (1 - Col1Fraction)));
      if(endGreen > 255) endGreen = 255;
      if(endGreen < 0) endGreen = 0;

      var endBlue = Math.round((blue1 * Col1Fraction) + (blue2 * (1 - Col1Fraction)));
      if(endBlue > 255) endBlue = 255;
      if(endBlue < 0) endBlue = 0;

      return "#" + IntToHex(endRed)+ IntToHex(endGreen)+ IntToHex(endBlue);
  }

  /*
  Converts a number to hexadecimal format
  */
  function IntToHex(strNum)
  {
      base = strNum / 16;
      rem = strNum % 16;
      base = base - (rem / 16);
      baseS = MakeHex(base);
      remS = MakeHex(rem);

      return baseS + '' + remS;
  }


  /*
  gets the hex bits of a number
  */
  function MakeHex(x)
  {
      if((x >= 0) && (x <= 9))
      {
          return x;
      }
      else
      {
          switch(x)
          {
              case 10: return "A";
              case 11: return "B";
              case 12: return "C";
              case 13: return "D";
              case 14: return "E";
              case 15: return "F";
          }
      }
  }


  /*
  For a pixel cut by the line determines the fraction of the pixel on the 'inside' of the
  line.  Returns a number between 0 and 1
  */
  function pixelFraction(x, y, r)
  {
      var pixelfraction = 0;

      /*
      determine the co-ordinates of the two points on the perimeter of the pixel that the
      circle crosses
      */
      var xvalues = new Array(1);
      var yvalues = new Array(1);
      var point = 0;
      var whatsides = "";

      // x + 0 = Left
      var intersect = Math.sqrt((Math.pow(r,2) - Math.pow(x,2)));

      if ((intersect >= y) && (intersect < (y+1)))
      {
          whatsides = "Left";
          xvalues[point] = 0;
          yvalues[point] = intersect - y;
          point =  point + 1;
      }
      // y + 1 = Top
      var intersect = Math.sqrt((Math.pow(r,2) - Math.pow(y+1,2)));

      if ((intersect >= x) && (intersect < (x+1)))
      {
          whatsides = whatsides + "Top";
          xvalues[point] = intersect - x;
          yvalues[point] = 1;
          point = point + 1;
      }
      // x + 1 = Right
      var intersect = Math.sqrt((Math.pow(r,2) - Math.pow(x+1,2)));

      if ((intersect >= y) && (intersect < (y+1)))
      {
          whatsides = whatsides + "Right";
          xvalues[point] = 1;
          yvalues[point] = intersect - y;
          point =  point + 1;
      }
      // y + 0 = Bottom
      var intersect = Math.sqrt((Math.pow(r,2) - Math.pow(y,2)));

      if ((intersect >= x) && (intersect < (x+1)))
      {
          whatsides = whatsides + "Bottom";
          xvalues[point] = intersect - x;
          yvalues[point] = 0;
      }

      /*
      depending on which sides of the perimeter of the pixel the circle crosses calculate the
      fraction of the pixel inside the circle
      */
      switch (whatsides)
      {
              case "LeftRight":
              pixelfraction = Math.min(yvalues[0],yvalues[1]) + ((Math.max(yvalues[0],yvalues[1]) - Math.min(yvalues[0],yvalues[1]))/2);
              break;

              case "TopRight":
              pixelfraction = 1-(((1-xvalues[0])*(1-yvalues[1]))/2);
              break;

              case "TopBottom":
              pixelfraction = Math.min(xvalues[0],xvalues[1]) + ((Math.max(xvalues[0],xvalues[1]) - Math.min(xvalues[0],xvalues[1]))/2);
              break;

              case "LeftBottom":
              pixelfraction = (yvalues[0]*xvalues[1])/2;
              break;

              default:
              pixelfraction = 1;
      }

      return pixelfraction;
  }


  // This function converts CSS rgb(x, x, x) to hexadecimal
  function rgb2Hex(rgbColour)
  {
      try{

          // Get array of RGB values
          var rgbArray = rgb2Array(rgbColour);

          // Get RGB values
          var red   = parseInt(rgbArray[0]);
          var green = parseInt(rgbArray[1]);
          var blue  = parseInt(rgbArray[2]);

          // Build hex colour code
          var hexColour = "#" + IntToHex(red) + IntToHex(green) + IntToHex(blue);
      }
      catch(e){

          alert("There was an error converting the RGB value to Hexadecimal in function rgb2Hex");
      }

      return hexColour;
  }

  // Returns an array of rbg values
  function rgb2Array(rgbColour)
  {
      // Remove rgb()
      var rgbValues = rgbColour.substring(4, rgbColour.indexOf(")"));

      // Split RGB into array
      var rgbArray = rgbValues.split(", ");

      return rgbArray;
  }

  /*
  Function by Simon Willison from sitepoint.com
  Modified by Cameron Cooke adding Safari's rgba support
  */
  function setOpacity(obj, opacity)
  {
      opacity = (opacity == 100)?99.999:opacity;

      if(isSafari && obj.tagName != "IFRAME")
      {
          // Get array of RGB values
          var rgbArray = rgb2Array(obj.style.backgroundColor);

          // Get RGB values
          var red   = parseInt(rgbArray[0]);
          var green = parseInt(rgbArray[1]);
          var blue  = parseInt(rgbArray[2]);

          // Safari using RGBA support
          obj.style.backgroundColor = "rgba(" + red + ", " + green + ", " + blue + ", " + opacity/100 + ")";
      }
      else if(typeof(obj.style.opacity) != "undefined")
      {
          // W3C
          obj.style.opacity = opacity/100;
      }
      else if(typeof(obj.style.MozOpacity) != "undefined")
      {
          // Older Mozilla
          obj.style.MozOpacity = opacity/100;
      }
      else if(typeof(obj.style.filter) != "undefined")
      {
          // IE
          obj.style.filter = "alpha(opacity:" + opacity + ")";
      }
      else if(typeof(obj.style.KHTMLOpacity) != "undefined")
      {
          // Older KHTML Based Browsers
          obj.style.KHTMLOpacity = opacity/100;
      }
  }

  /*
  Returns index if the passed value is found in the
  array otherwise returns false.
  */
  function inArray(array, value)
  {
      for(var i = 0; i < array.length; i++){

          // Matches identical (===), not just similar (==).
          if (array[i] === value) return i;
      }

      return false;
  }

  /*
  Returns true if the passed value is found as a key
  in the array otherwise returns false.
  */
  function inArrayKey(array, value)
  {
      for(key in array){

          // Matches identical (===), not just similar (==).
          if(key === value) return true;
      }

      return false;
  }

  // Cross browser add event wrapper
  function addEvent(elm, evType, fn, useCapture) {
	  if (elm.addEventListener) {
		  elm.addEventListener(evType, fn, useCapture);
		  return true;
	  }
	  else if (elm.attachEvent) {
		  var r = elm.attachEvent('on' + evType, fn);
		  return r;
	  }
	  else {
		  elm['on' + evType] = fn;
	  }
  }

  // Cross browser remove event wrapper
  function removeEvent(obj, evType, fn, useCapture){
    if (obj.removeEventListener){
      obj.removeEventListener(evType, fn, useCapture);
      return true;
    } else if (obj.detachEvent){
      var r = obj.detachEvent("on"+evType, fn);
      return r;
    } else {
      alert("Handler could not be removed");
    }
  }

  // Formats colours
  function format_colour(colour)
  {
      var returnColour = "#ffffff";

      // Make sure colour is set and not transparent
      if(colour != "" && colour != "transparent")
      {
          // RGB Value?
          if(colour.substr(0, 3) == "rgb")
          {
              // Get HEX aquiv.
              returnColour = rgb2Hex(colour);
          }
          else if(colour.length == 4)
          {
              // 3 chr colour code add remainder
              returnColour = "#" + colour.substring(1, 2) + colour.substring(1, 2) + colour.substring(2, 3) + colour.substring(2, 3) + colour.substring(3, 4) + colour.substring(3, 4);
          }
          else
          {
              // Normal valid hex colour
              returnColour = colour;
          }
      }

      return returnColour;
  }

  // Returns the style value for the property specfied
  function get_style(obj, property, propertyNS)
  {
      try
      {
          if(obj.currentStyle)
          {
              var returnVal = eval("obj.currentStyle." + property);
          }
          else
          {
              /*
              Safari does not expose any information for the object if display is
              set to none is set so we temporally enable it.
              */
              if(isSafari && obj.style.display == "none")
              {
                obj.style.display = "";
                var wasHidden = true;
              }

              var returnVal = document.defaultView.getComputedStyle(obj, '').getPropertyValue(propertyNS);

              // Rehide the object
              if(isSafari && wasHidden)
              {
                  obj.style.display = "none";
              }
          }
      }
      catch(e)
      {
          // Do nothing
      }

      return returnVal;
  }

  // Get elements by class by Dustin Diaz.
  function getElementsByClass(searchClass, node, tag)
  {
	     var classElements = new Array();

      if(node == null)
		      node = document;
	     if(tag == null)
		      tag = '*';

	     var els = node.getElementsByTagName(tag);
	     var elsLen = els.length;
	     var pattern = new RegExp("(^|\s)"+searchClass+"(\s|$)");

	     for (i = 0, j = 0; i < elsLen; i++)
      {
		        if(pattern.test(els[i].className))
          {
			           classElements[j] = els[i];
			           j++;
		        }
	     }

	     return classElements;
  }

  // Displays error message
  function newCurvyError(errorMessage)
  {
      return new Error("curvyCorners Error:\n" + errorMessage)
  }
/*
**
** File 'functions.js'
**
*/
function createListener(id,method){
//declaring the class
alert(id+ ' ' + method);
var CheckboxWatcher = Class.create();

//defining the rest of the class implementation
CheckboxWatcher.prototype = {

  initialize: function(chkBox, message) {
    this.chkBox = $(chkBox);
    this.message = message;
    //assigning our method to the event

    this.chkBox.onclick = this.showMessage.bindAsEventListener(this);
  },

  showMessage: function(evt) {
    alert(this.message + ' (' + evt.type + ')');
  }
};

var watcher = new CheckboxWatcher(id, method);
}

/**
@param string rowid the id o fthe row you want to make disappear
@param oject  opts  Effect options such as {duration:3}
*/
function fadeTableRow(rowid,opts){
	element = $(rowid);
	if(!opts){
	    opts = {};
	}
	if(Element.visible(element)) {	

	    var row  = $(rowid);
	    var cells= row.childNodes;
	    for(i=0;i<cells.length;i++){
	        if(cells[i].tagName == 'TD'){
	            new Effect.Fade(cells[i],opts);
	        }
	    }
	    new Effect.Fade(row,opts);
	} else {

	    var row  = $(rowid);
	    var cells= row.childNodes;
	    for(i=0;i<cells.length;i++){
	        if(cells[i].tagName == 'TD'){
	            new Effect.Appear(cells[i],opts);
	        }
	    }
	    new Effect.Appear(row,opts);
	}
}

/**
@param string rowid the id o fthe row you want to make disappear
@param oject  opts  Effect options such as {duration:3}
*/
function SlideUpAndDownSet(id,opts){
	element = $(id);
	if(Element.visible(element)) {	
	    if(!opts){
	        opts = {};
	    }
	    var row  = $(id);
	    var cells= row.childNodes;
	    for(i=0;i<cells.length;i++){
	        if(cells[i].tagName == 'TD'){
	            new Effect.SlideUp(cells[i],opts);
	        }
	    }
	    new Effect.SlideUp(row,opts);
	} else {
		if(!opts){
	        opts = {};
	    }
	    var row  = $(id);
	    var cells= row.childNodes;
	    for(i=0;i<cells.length;i++){
	        if(cells[i].tagName == 'TD'){
	            new Effect.SlideDown(cells[i],opts);
	        }
	    }
	    new Effect.SlideDown(row,opts);
	}
}


function switchBtnText(id,visibleText,invisibleText){
	element = $(id);
	
	testtext=visibleText.toLowerCase();
	if (element.innerHTML.toLowerCase() == testtext.toLowerCase()){
		element.innerHTML = invisibleText;
	} else {
		element.innerHTML = visibleText;
	}
	
}


function updateCheckbox(formname,values) {

    var what = formname;
	var i=0;
alert(what);
	alert("Length: "+what.length);
alert("Length1: "+values.length);
alert("Length1: "+values);
    for (i=0; i<what.length; i++) {
		alert("what["+i+"]: "+what[i].value);

    }
}


function replaceChars(text,search_str,replace_str) {
	var result = text;
	var count=result.length;
	var search = search_str.split(",");
	var replace = replace_str.split(",");
	for (i=0;i<search.length;i++){
		search[i] = new RegExp(search[i]);
		for (j=0;j<count;j++){
			result = result.replace(search[i],replace[i]);
		}		
	}	
	return result;
}


// SORTABLES

	function createNewSection(name,parentid) {
		//var name = $F('sectionName');
		if (name != '') {
			var newDiv = Builder.node('div', {id: 'group' + (sections.length + 1), className: 'section', style: 'display:none;' }, [
				Builder.node('h3', {className: 'handle'}, name)
			]);

			sections.push(newDiv.id);
			$(parentid).appendChild(newDiv);
			Effect.Appear(newDiv.id);
			destroyLineItemSortables();
			createLineItemSortables();
			createGroupSortable();
		}
	}

	function createLineItemSortables() {
		for(var i = 0; i < sections.length; i++) {
			Sortable.create(sections[i],{tag:'div',dropOnEmpty: true, containment: sections,only:'lineitem'});
		}
	}

	function destroyLineItemSortables() {
		for(var i = 0; i < sections.length; i++) {
			Sortable.destroy(sections[i]);
		}
	}

	function createGroupSortable() {
		Sortable.create('page',{tag:'div',only:'section',handle:'handle'});
	}
	
/** **/
var myGlobalHandlers = {
	onCreate: function(){
		//Element.show('systemWorking');
		if ($('systemWorking') != null) new Effect.Appear('systemWorking',{ duration: 0.5 });
	},
	onComplete: function() {
		if(Ajax.activeRequestCount == 0){
		//	Element.hide('systemWorking');
		if ($('systemWorking') != null) new Effect.Fade('systemWorking', { duration: 0.5 });
		}
	}
};
Ajax.Responders.register(myGlobalHandlers);	


 
 
 
function request (	url,			// request url
					id,				// id of container where the output is rendered into
					params,			// Ajax.Request parameter hash
					collect,		// ?
					enctype,		// ?
					success_extra,	// extra javascript code that is evaluated on success (string)
					attach,			// ?
					fade,			// ?
					blind,			// ?
					update,			// ?
					show_error_id,	// ?
					show_error_container_id // ?
					) {
	url = (url.search('index') < 0)?'/index.php?action='+url:url;
	id = (id == undefined || id.length <= 0)?'column2_right_main_without_teaser':id;
	if ((show_error_container_id == undefined || show_error_container_id.length <= 0) && (show_error_id != undefined && show_error_id.length > 0)) show_error_container_id = show_error_id+'_container';
	show_error_id = (show_error_id == undefined || show_error_id.length <= 0)?'global_error_stack_output':show_error_id;	
	show_error_container_id = (show_error_container_id == undefined || show_error_container_id.length <= 0)?'global_error_stack_output_container':show_error_container_id;
	show_error_element = (show_error_id == undefined || show_error_id.length <= 0 || !show_error_id || $(show_error_id) == null)?false:$(show_error_id);
	show_error_element_container = (show_error_container_id == undefined || show_error_container_id.length <= 0 || !show_error_container_id || $(show_error_container_id) == null)?false:$(show_error_container_id);
	attach = (attach == undefined || attach.length <= 0 || attach == 0 || attach == false)?false:true;
	fade = (fade == 0 || fade == false)?false:true;
	update = (update == 0 || update == false)?false:true;
	blind = (blind == 0 || blind == false || blind == undefined)?false:true;
	collect = (collect == undefined)?false:collect;
	enctype = (enctype == undefined || enctype.length <= 0)?'multipart/form-data':enctype;
	element = $(id);
	var formParams = (collect)?getFormParams(document,true):'';
	var post = (formParams != '')?formParams:'';
	if (params != '' && params != undefined && params != null){

		if (typeof post == 'object' || typeof params == 'object'){
			if (typeof post != 'object') post = new Object();
			if (typeof params == 'string') params = params.toQueryParams();
			Object.extend(post,params);
		} else {
			post += (post != '')?'&':'';
			post += (params);
		}
	}
	if (url.search('index') < 0){
		Object.extend(post,{'action' : url});
	}
//	var postObj = post.toQueryParams();
	if (typeof post == 'object' ) post = (post.toQueryString)?post.toQueryString():$H(post).toQueryString() ;
	
	
	var opt = {
		// Use POST
		method: 'post',
		// Send this lovely data
		postBody: post,	
		// Encoding
		encoding: 'ISO-8859-1',	
		 // Handle successful response
		onSuccess: function(t) {
			var new_content = unescape(t.responseText);
			// *#*#*#*#*#*#* ersetzen...
			if (new_content.search(/\*#\*#\*#\*#\*#\*#\*/g) >= 0){
				new_content = new_content.replace(/\*#\*#\*#\*#\*#\*#\*/g, '\\');
			} else {
				new_content = new_content;
			}
			
			//alert(new_content);
			
			// Error Handling...
			if (new_content.indexOf('error;') == 0){
				if (show_error_element != false){
					var errormessage = new_content.replace(/error;/,'');					
					Element.update(show_error_element,errormessage);
					new Effect.Appear(show_error_element_container,{queue:'end'});
					new Effect.Fade(show_error_element_container,{queue:'end',delay:10});
				}
			} else {
				
				if (update){
					
					if (new_content != 'kb_error' && (element != null || id == '')){
						if (id != ''){
							new_content = (attach)? element.innerHTML + new_content : new_content;
							Element.update(element,new_content.getInnerHtmlById(id,1));
						}
						if (success_extra != undefined && success_extra.length > 0 && new_content.indexOf('error;') != 0){
							//alert('executing success_extra!');
							eval(success_extra);
						}
						
					} else {
						//alert('an error occurred!');
						if (element == null) alert('Das Element mit der id '+id+' existiert nicht !!!');
						if (new_content == 'kb_error') alert('interner Fehler !!!');
						
					}
					if (blind && element != null && (!element.visible() || element.style.opacity <= 0.5))  new Effect.BlindDown(id,{ duration: 1.0, queue: 'end' });
					if ((!is_ie6) && fade && element != null && (!element.visible() || element.style.opacity <= 0.5))  new Effect.Opacity(id,{ duration: 1.0,transition: Effect.Transitions.linear,from: 0.01, to: 1.0, queue: 'end' });
				} else {
					if (success_extra != undefined && success_extra.length > 0){
						eval(success_extra);
					}
				}
				
			}
		},
		// Handle 404
		on404: function(t) {
			alert('Error 404: location "' + t.statusText + '" was not found.');
		},		

		// Handle other errors
		onFailure: function(t) {
			alert('Error ' + t.status + ' -- ' + t.statusText);
		}
	}

	if (update){
		if (blind && element != null && (element.visible() || element.style.opacity > 0.5))  new Effect.BlindUp(id,{ duration: 1.0});
		if ((!is_ie6) && fade && element != null && (element.visible() || element.style.opacity > 0.5))  new Effect.Opacity(id,{ duration: 0.5,transition: Effect.Transitions.linear,from: 1.0, to: 0.01 });
	}
	new Ajax.Request(url, opt);
}

function kb_request(options){
	var url 	= (options && options.url)?options.url : '/index.php';
	var action 	= (options && options.action)? $H({ action: options.action}) : $H({});
	var id  	= (options && options.id )?options.id : 'column2_right_main_without_teaser';
	var params  = (options && options.params )?options.params : {};
	var collect = (options && options.collect != undefined )?options.collect : false;
	var attach  = (options && options.attach != undefined )?options.attach : false;
	var fade  	= (options && options.fade != undefined )?options.fade : true;
	var blind  	= (options && options.blind != undefined )?options.blind : false;
	var update 	= (options && options.update != undefined )?options.update : true;
	var clean 	= (options && options.clean != undefined )?options.clean : 0;
	var submitted_form_element_ids 	= (options && options.submitted_form_element_ids != undefined )?options.submitted_form_element_ids : [];
	var success_extra = (options && options.onComplete )?options.onComplete : '';
	var show_error_id = (options && options.errorId )?options.errorId : 'global_error_stack_output';
	var show_error_container_id = (options && options.errorContainerId )?options.errorContainerId : 'global_error_stack_output_container';
	var element = $(id);
	
	show_error_element = (show_error_id == undefined || show_error_id.length <= 0 || !show_error_id || $(show_error_id) == null)?false:$(show_error_id);
	show_error_element_container = (show_error_container_id == undefined || show_error_container_id.length <= 0 || !show_error_container_id || $(show_error_container_id) == null)?false:$(show_error_container_id);

	var formParams = (collect)?getFormParams($(collect),true):'';	
	var post = (formParams != '') ? formParams:'';
	
	
	submitted_form_element_ids.each(function(el){
		element = $(el);
		if (element){
			eval('Object.extend(params,element.collectValues());');
		}
		
	});
	
	
	var destId = (formParams && formParams.get && formParams.get('destId') != undefined)?formParams.get('destId'):'';
	destId = (Object.isString(destId))?destId : (destId[0])?destId[0] : '';
	if (!element && destId){
		element =  $(destId);
		id = destId;
	}
	
	if (params != '' && params != undefined && params != null){
		if (typeof post == 'object' || typeof params == 'object'){
			if (typeof post != 'object') post = new Object();
			if (typeof params == 'string') params = params.toQueryParams();
			Object.extend(post,params);
		} else {
			post += (post != '')?'&':'';
			post += (params);
		}
	}

	post = $H(post).merge(action);
	
	if (typeof post == 'object' ) post = (post.toQueryString)?post.toQueryString():$H(post).toQueryString() ;
	
	var opt = {
		// Use POST
		method: 'post',
		// Send this lovely data
		postBody: post,	
		// Encoding
		encoding: 'ISO-8859-1',	
		 // Handle successful response
		onSuccess: function(t) {
			var new_content = unescape(t.responseText);
			// *#*#*#*#*#*#* ersetzen...
			if (new_content.search(/\*#\*#\*#\*#\*#\*#\*/g) >= 0){
				new_content = new_content.replace(/\*#\*#\*#\*#\*#\*#\*/g, '\\');
			} else {
				new_content = new_content;
			}
			
			// Error Handling...
			if (show_error_element != false && new_content.indexOf('error;') == 0){
				var errormessage = new_content.replace(/error;/,'');
				
				Element.update(show_error_element,errormessage);
				new Effect.Appear(show_error_element_container,{queue:'end'});
	//			new Effect.Opacity(show_error_element,{ duration: 0.5,transition: Effect.Transitions.linear,from: 0.001, to: 1.0 ,queue:'end'});
				new Effect.Fade(show_error_element_container,{queue:'end',delay:10});
	//			new Effect.Opacity(show_error_element,{ duration: 0.5,transition: Effect.Transitions.linear,from: 1.0, to: 0.001 ,queue:'end',delay:5});
			} else {
				
				if (update){
					
					if (new_content != 'kb_error' && (element != null || id == '')){
						if (id != ''){
							new_content = (attach)? element.innerHTML + new_content : new_content;
							Element.update(element,new_content.getInnerHtmlById(id));
						}
						if (success_extra != undefined && success_extra.length > 0 && new_content.indexOf('error;') != 0){
							eval(success_extra);
						}
						
					} else {
						if (element == null) alert('Das Element mit der id '+id+' existiert nicht !!!');
						if (new_content == 'kb_error') alert('interner Fehler !!!');
						
					}
					if (blind && element != null && (!element.visible() || element.style.opacity <= 0.5))  new Effect.BlindDown(id,{ duration: 1.0, queue: 'end' });
					if ((!is_ie6) && fade && element != null && (!element.visible() || element.style.opacity <= 0.5))  new Effect.Opacity(id,{ duration: 1.0,transition: Effect.Transitions.linear,from: 0.01, to: 1.0, queue: 'end' });
				} else {
					if (success_extra != undefined && success_extra.length > 0){
						eval(success_extra);
					}
				}
				
			}
		},
		// Handle 404
		on404: function(t) {
			alert('Error 404: location "' + t.statusText + '" was not found.');
		},		

		// Handle other errors
		onFailure: function(t) {
			alert('Error ' + t.status + ' -- ' + t.statusText);
		}
	}

	if (update){
		if (blind && element != null && (element.visible() || element.style.opacity > 0.5))  new Effect.BlindUp(id,{ duration: 1.0});
		if ((!is_ie6) && fade && element != null && (element.visible() || element.style.opacity > 0.5))  new Effect.Opacity(id,{ duration: 0.5,transition: Effect.Transitions.linear,from: 1.0, to: 0.51 });
	}
	
	new Ajax.Request(url, opt);
}


function startCallback(){
	//alert('start');
	
	if ($('systemWorking') != null) new Effect.Appear('systemWorking',{ duration: 0.5 });
	if ((!is_ie6)){
		new Effect.Opacity('album_fotos_id',
	    { duration: 1.0, 
	      transition: Effect.Transitions.linear, 
	      from: 1.0, to: 0.2 });
		 new Effect.Opacity('group_new_pictures_id',
	    { duration: 1.0, 
	      transition: Effect.Transitions.linear, 
	      from: 1.0, to: 0.2 });
	}
	return true;
}

function completeCallback(response,error){
	//alert('complete');
	if ($('systemWorking') != null) new Effect.Fade('systemWorking',{ duration: 0.5 });
	
	response =	unescape(response);
	error = response.indexOf('error;') == 0;
	var errormessage = response.replace(/error;/,'');
				
	if (!error){
		$('album_fotos_id').innerHTML += unescape(errormessage);		
	} else {
		Element.update('global_error_stack_output',unescape(errormessage));

		new Effect.Appear('global_error_stack_output_container',{queue:'end'});
		new Effect.Fade('global_error_stack_output_container',{queue:'end',delay:10});
		
	
	}
	if ((!is_ie6)){
		new Effect.Opacity('album_fotos_id',
	    { duration: 1.0, 
	      transition: Effect.Transitions.linear, 
	      from: 0.2, to: 1.0 });
		new Effect.Opacity('group_new_pictures_id',
	    { duration: 1.0, 
	      transition: Effect.Transitions.linear, 
	      from: 0.2, to: 1.0 })  
	}
	/* 
	  $template_output = '<!-- ERROR: Falsches Format -->';
			$template_output.= '<script>'."\n";
			$template_output.= "\t".'var elem = $(\'photoalbum_file_submit_error\');'."\n";
			$template_output.= "\t".'Element.update(elem,\'blablabla\');'."\n";
			$template_output.= '</script>'."\n";*/
	clearFormParams('group_new_pictures_id');
}

function switchElements(element1,element2,fade){
	fade = (fade == 1 || fade == true)?true:false;
	element1 = $(element1);
	element2 = $(element2);
	hide = ((element2.style.display == 'none' || !element2.visible) || !(element1.style.display == 'none' || !element1.visible))?element1:element2;
	show = ((element2.style.display == 'none' || !element2.visible) || !(element1.style.display == 'none' || !element1.visible))?element2:element1;	
//	new Effect.Opacity(hide,{ duration: 0.5,transition: Effect.Transitions.linear,from: 1.0, to: 0.001 });
//	new Effect.Opacity(show,{ duration: 0.5,transition: Effect.Transitions.linear,from: 0.001, to: 1.0, queue: 'end' });
	if (!is_ie6 && fade && false){
		new Effect.Fade(hide, {duration:0.1});
		new Effect.Appear(show,{ queue: 'end', duration:0.1});	
	} else {
		Element.hide(hide);
		Element.show(show);
	}
}


function numVal(element) {
	var num = element.value.charAt(element.value.length-1);
	var ValidChars = "0123456789";
	if (ValidChars.indexOf(num) == -1) {
		element.value = element.value.substring(0, element.value.length-1);
	}
	//alert(element.value + ' -> '+num);
	
}

// 
function getInnerHtmlById(n) {
	secure = 4000; /* SicherheitsZähler der zur Not die schleife abbricht... */
	
	var errorResult = (this.search(/<html[^>]*>/)  > -1 || this.search(/<head[^>]*>/)  > -1 || this.search(/<body[^>]*>/)  > -1)? '' : this;
	
	typeExpr = new RegExp("<([a-zA-Z]*)[^>]*id=."+n+"[^>]*>");
	if ((n.length == 0) || (this.indexOf(n) == -1) || this.search(typeExpr)  == -1) return (errorResult);
	
	
	type = this.match(typeExpr)[1];	
	
	var front = ''
	var end = ''		
	if (type == null || type == undefined) return false;
	startExpression = new RegExp("<"+type+"[^>]*id=."+n+"[^>]*>");	
	startDivExp = new RegExp("<"+type+"[^>]*>");	
	endDivExp =  new RegExp("</"+type+">");
	
	startTag = new String(this.match(startExpression));
	startIndex = this.search(startTag) + startTag.length;

	var txt = new String(this.substr(startIndex)).replace(/<!--.*-->/,'');
	endMatch = txt.match(endDivExp);
	endIndex = 6 + txt.search(endDivExp);
	
	front = txt.substr(0,endIndex);
	end = txt.substr(endIndex);
	var lastIndex = endIndex;
	startMatch = front.split('<'+type);
	frontCount = 0;
	if (startMatch != null){
			startMatch = startMatch.uniq();
			frontCount += startMatch.length-1;
	}
	
	while (frontCount > 0 && --secure){
		endMatch = end.match(endDivExp);
		endIndex = 6 + end.search(endDivExp);
		lastIndex += endIndex;
		front = end.substr(0,endIndex);
		end = end.substr(endIndex);
	
		startMatch = front.split('<'+type);
		if (startMatch != null){
			startMatch = startMatch.uniq();
			frontCount += startMatch.length-1;
		}		
		frontCount--;
	}
	result = txt.substr(0,lastIndex-6);
	//alert(result);
	return result;
}

String.prototype.getInnerHtmlById = getInnerHtmlById
 

var AjaxQueue = {
	batchSize: 1, //No.of simultaneous AJAX requests allowed, Default : 1
	urlQueue: [], //Request URLs will be pushed into this array
	elementsQueue: [], //Element IDs of elements to be updated on completion of a request ( as in Ajax.Updater )
	optionsQueue: [], //Request options will be pushed into this array
	setBatchSize: function(bSize){ //Method to set a different batch size. Recommended: Set batchSize before making requests
		this.batchSize = bSize;
	},
	push: function(url, options, elementID){ //Push the request in the queue. elementID is optional and required only for Ajax.Updater calls
		this.urlQueue.push(url);
		this.optionsQueue.push(options);
		if(elementID!=null){
			this.elementsQueue.push(elementID);
		} else {
			this.elementsQueue.push("NOTSPECIFIED");
		}

		this._processNext();
	},
	_processNext: function() { // Method for processing the requests in the queue. Private method. Don't call it explicitly
		if(Ajax.activeRequestCount < AjaxQueue.batchSize) // Check if the currently processing request count is less than batch size
		{
			if(AjaxQueue.elementsQueue.first()=="NOTSPECIFIED") { //Check if an elementID was specified
				// Call Ajax.Request if no ElementID specified
				//Call Ajax.Request on the first item in the queue and remove it from the queue
				new Ajax.Request(AjaxQueue.urlQueue.shift(), AjaxQueue.optionsQueue.shift()); 

				var junk = AjaxQueue.elementsQueue.shift();
			} else {
				// Call Ajax.Updater if an ElementID was specified.
				//Call Ajax.Updater on the first item in the queue and remove it from the queue
				new Ajax.Updater(AjaxQueue.elementsQueue.shift(), AjaxQueue.urlQueue.shift(), AjaxQueue.optionsQueue.shift());
			}
		}
	}
};
Ajax.Responders.register({
  //Call AjaxQueue._processNext on completion ( success / failure) of any AJAX call.
  onComplete: AjaxQueue._processNext
});

/************* SYNTAX ***************
AjaxQueue.setBatchSize(size);

AjaxQueue.push(URL , OPTIONS, [ElementID]);

************** USAGE ***************
AjaxQueue.setBatchSize(4);
AjaxQueue.push("blablabla",{onSucess: funcSuccess, onfailure: funcFailure});

*/


// ALT - WAHRSCHEINLICH LÖSCHEN

/*




 function convertVersionString(versionString){
      var r = versionString.split('.');
      return parseInt(r[0])*100000 + parseInt(r[1])*1000 + parseInt(r[2]);}
	  



function toCursorPointer(e){
	e.element().style.cursor='pointer'
};
function toMovePointer(){this.style.cursor='move'};
	  




function toggleElements(elements){
	if (!Object.isArray(elements)) return false;
	
	var options = Object.extend({
		duration: 0.001, 
		afterFinish: function(effect) { }
	}, arguments[1] || {});
	
	var effects = [];	
	elements.each(function(e){
		e = $(e);
		if (e.visible()){
			effects.push(new Effect.Fade(e, { sync: true, duration: 0.001 }));
		} else {
			effects.push(new Effect.Appear(e, { sync: true, duration: 0.001 }));
		}
	});
	
	new Effect.Parallel(effects,options);
	return true
}


function setActive(element){
	var element = $(element);			
	if (!element) return;
	
	var options = Object.extend({
	}, arguments[1] || { });
	
	$(element.parentNode).siblings().each(function(e){
		if (e.hasClassName('active')) e.removeClassName('active');
	});
	
	if (!$(element.parentNode).hasClassName('active')) $(element.parentNode).addClassName('active');	
}



buildCategoryTag = function  (parameters){
	var name = (parameters.name)?parameters.name:'';
	var source = (parameters.source)?parameters.source:'';
	source = $(source);
	if (!source) return '';
	var returnString = '';
	var params = getFormParams(source);		
	var paramsObject = new Object();
	paramsObject = params.toParamObject();
	
	var id = (paramsObject[name])?paramsObject[name]:'';
	var site = (paramsObject[name+'_my_site_id'])?paramsObject[name+'_my_site_id']:'';
	var type = (paramsObject[name+'_my_type'])?paramsObject[name+'_my_type']:'';
	var order = (paramsObject[name+'_my_order'])?paramsObject[name+'_my_order']:'';
	var count = (paramsObject[name+'_my_count'])?paramsObject[name+'_my_count']:'';
	var template = (paramsObject[name+'_my_template'])?paramsObject[name+'_my_template']:'';
	
	returnString = 'CATEGORYPAGE['+site+','+type+','+order+','+count+','+template+']CATEGORYPAGE';
		
	var adv_cat = $(name+'_id');
	if (adv_cat){
		adv_cat.value=returnString;
	} else {
		var hidden_string = document.createElement("input");
		hidden_string.type = 'hidden';
		hidden_string.id = name+'_id';
		hidden_string.value = returnString;
		hidden_string.name = name;
		parent_node = source.parentNode.parentNode;
		parent_node.appendChild(hidden_string);
	}
	return encodeURI(returnString);
}	


function elementNameToArray(element){
	if (typeof element == 'string') element = $(element);	
	if (!element || !element.getElementsByTagName){ return; }
	result = '';
	var inputs = element.getElementsByTagName('input');
	// loop through all input  tags
	var textAreas = element.getElementsByTagName('textarea');
	// loop through all input  tags
	for (var i=0; i<inputs.length; i++){
		var single_element = inputs[i];
		
		if ( single_element.name.substr( single_element.name.length-2,2) != '[]') single_element.name = single_element.name + '[]';
	}
	for (var i=0; i<textAreas.length; i++){
		var single_element = textAreas[i];
		
		if ( single_element.name.substr( single_element.name.length-2,2) != '[]') single_element.name = single_element.name + '[]';
	}
	
 }

 

function myCloneNodeNeu(source){
	if (typeof source == 'string') source = $(source);	
	if (!source) return null;
	if (source.getAttribute && source.getAttribute('name')) alert(source.getAttribute('name'));
	var tmpNode = source.cloneNode(true);	
	
	if (source.hasChildNodes()){
		for (i=0;i<source.childNodes.length;i++){
			test = myCloneNodeNeu(source.childNodes[i]);
			tmpNode.appendChild(test);
		}
	}
	return tmpNode;
}


function myCloneNode(node,index,id,source){
	var i;	
	node = Element.cleanWhitespace(node);
	if (node == null) return;	
	var MyRegExp = new RegExp('_function');	
	if (node.value) node.value = '';
	if (node.getAttribute){
		if (node.getAttribute('onclick') && String(node.getAttribute('onclick')).search(MyRegExp) != -1) 
			node.setAttribute('onClick',String(node.getAttribute('onclick')).replace(MyRegExp, id+'_'+index));
			node.setAttribute('onClick',String(node.getAttribute('onclick')).replace(MyRegExp, id+'_'+index));
		if (node.getAttribute('onclick') && String(node.getAttribute('onClick')).search(MyRegExp) != -1) 
			node.setAttribute('onClick',String(node.getAttribute('onClick')).replace(MyRegExp, id+'_'+index));
			node.setAttribute('onClick',String(node.getAttribute('onclick')).replace(MyRegExp, id+'_'+index));
		if (node.getAttribute('name')) node.setAttribute('name',node.name);
		
		if (node.getAttribute('id')) node.setAttribute('id',node.id+'_'+index);
	}
	if (node.hasChildNodes()){
		for (i=0;i<node.childNodes.length;i++){
			myCloneNode(node.childNodes[i],index,id);
		}
	}
	return node
}

setPrevLink = function(current){
	var link = $('photobox_prev_link');	
	var imgNext = $('photobox_next_img');
	var imgPrev = $('photobox_prev_img');	
	if (current == 1){
		imgPrev.src = '/tmpl/onefamily/img/photobox_prev.gif';
	//	alert(imgPrev.src);
	} else if (current == 2) {
		imgPrev.src = '/tmpl/onefamily/img/photobox_prev_active.gif';
	//	alert(imgPrev.src);
	}

}

setNextLink = function(current){
	var link = $('photobox_next_link');
	var imgNext = $('photobox_next_img');
	var imgPrev = $('photobox_prev_img');	
	if (current == pages){
		imgNext.src = '/tmpl/onefamily/img/photobox_next.gif';
	//	alert(imgNext.src);
	} else if (current == pages-1) {
		imgNext.src = '/tmpl/onefamily/img/photobox_next_active.gif';
	//	alert(imgNext.src);
	}
}

setNaviLinks = function(current){
//	alert(current);
	setPrevLink(current);
	setNextLink(current);
}
*/
function increaseIndexRec(node,options){
	if (!node) return;
	if (!node.getAttribute) return;
	if (!node.getAttribute('id')) return; 
	
	var regexpr = (options && options.regexpr)?options.regexpr:'';
	regexpr = (regexpr.length > 0)?new RegExp(regexpr):'';
	
	node = Element.cleanWhitespace(node);
	
	if (node.hasChildNodes && node.hasChildNodes()){
		for (var i=0;i<node.childNodes.length;i++){
			increaseIndexRec(node.childNodes[i],options);			
		}
	}
	
	if (regexpr.length == 0 || node.id.search(regexpr) != -1 ) {
		var index = new Number(node.id.match(/\d+/));
		new_index = index + 1;
//	if (new_index == id) new_index = ++index;
		new_id = node.id.replace(/\d+/,new_index);
		node.id = new_id;
	} else {
		var index = new Number(node.id.match(regexpr));
		new_index = index + 1;
//	if (new_index == id) new_index = ++index;
		new_id = node.id.replace(/\d+/,new_index);
		node.id = new_id;
	}
}

function increaseNameRec(node,options){
	if (!node) return;


	var regexpr = (options && options.regexpr)?options.regexpr:'';
	var index = (options && options.index)?options.index:new Number(node.id.match(/\d+/));
	
	if (!options){
		options = new Object();
		options.index = index;
	} else {
		options.index = index;
	}
	regexpr = (regexpr.length > 0)?new RegExp(regexpr):'';
	
	node = Element.cleanWhitespace(node);
	
	if (node.hasChildNodes && node.hasChildNodes()){
		for (var i=0;i<node.childNodes.length;i++){
			increaseNameRec(node.childNodes[i],options);			
		}
	}
		
	if (!node.getAttribute) return;
	if (!node.getAttribute('name')) return;
	
		
	//if (regexpr.length == 0 || node.id.search(regexpr) != -1 ) {
		//var index = new Number(node.id.match(/\d+/));
		new_index = index;
		new_name = node.name.replace(/\d+/,new_index);
		node.name = new_name;
//	} else {
//		var index = new Number(node.name.match(regexpr));
//		new_index = index + 1;
//	if (new_index == id) new_index = ++index;
//		new_name = node.name.replace(regexpr,new_index);
//		node.name = new_name;
//	}
}


setFunctionIds = function (node,options){
	if (!node) return;	
	var targetattribute = (options && options.attribute)?options.targetattribute:'onclick';
	var sourceattribute = (options && options.sourceattribute)?options.sourceattribute:'rel';
	var jFunction = (options && options.jFunction)?options.jFunction:'';
	var regexpr = (options && options.regexpr)?options.regexpr:'';
	var replace = (options && options.replace)?options.replace:'';
	var newValue = '';
	var myregexpr = (regexpr.length > 0 && typeof regexpr == 'string' )?new RegExp(regexpr):regexpr;
	
	node = Element.cleanWhitespace(node);
	
	if (node.hasChildNodes && node.hasChildNodes()){
		for (var i=0;i<node.childNodes.length;i++){
			setFunctionIds(node.childNodes[i],options);			
		}
	}
	

	
	if (node.getAttribute && node.getAttribute(sourceattribute)){
		var value = new String(node[sourceattribute]);
	//	alert(value );
		if (jFunction.length > 0){
			var oldFuncRegExp = new RegExp(jFunction+'\([^\)]*\)');
			var oldFunc = value.match(oldFuncRegExp);
			var newFunc = (regexpr.length > 0 && oldFunc.search(regexpr) > -1)?oldFunc.replace(regexpr,replace):oldFunc;
			newValue = value.replace(oldFuncRegExp,newFunc);
		} else {
			newValue = (regexpr.length > 0 && value.search(myregexpr) > -1)?value.replace(myregexpr,replace):value;			
		}
		
		evalString = 'node[\''+targetattribute+'\'] = function(){'+newValue+'return false;}';
		eval(evalString);
	//	if (attribute == 'onclick'){
		//	node.onclick = newValue;
	//	} else {
	//		node.setAttribute(attribute,newValue);
	//	}
	//	alert(node.onclick);
	}
}


params2Object = function(options){
	var cDivider = (options && options.divider)?options.divider:new Array();
	var result = new Array();
	
	tmp = this.split(((cDivider[0])?cDivider[0]:'&'));
	for (i=0;i<tmp.length;++i){		
		value = tmp[i].split(((cDivider[1])?cDivider[1]:'='));
		result[value[0]] = value[1];
	}
	return result;
}

params2Array = function (options){
	var cDivider = (options && options.divider)?options.divider:new Array();
	var value;
	var tmp;
	var tmpIndex;
	var index1;
	var index2;
	var result = new Array();
	tmp = this.split(((cDivider[0])?cDivider[0]:'&'));
	tmpIndex1 = -1;
	tmpIndex2 = -1;
	index2 = 0;
	index1 = -1;
	for (i=0;i<tmp.length;++i){
		value = tmp[i].split("=");
		tmpIndex1 = new Number(value[0].match(/\d+/));
		if (tmpIndex2 > tmpIndex1 || tmpIndex2 < tmpIndex1){
			tmpIndex2 = tmpIndex1;
			index2 = 0;
			++index1;
			result[index1] = new Array();
		} else {
			++index2;
		}
		result[index1][index2] = value[1];
	}
	return result;
}


String.prototype.toParamObject = params2Object;
String.prototype.toParamArray = params2Array;
/*

buildNewsTag = function  (parameters){
	var name = (parameters.name)?parameters.name:'';
	var source = (parameters.source)?parameters.source:'';
	source = $(source);
	var returnString = '';
	var params = getFormParams(source);		
	var paramsObject = new Object();
	paramsObject = params.toParamObject();
	
	var id = (paramsObject[name])?paramsObject[name]:'';
	var group = (paramsObject[name+'_my_group_id'])?paramsObject[name+'_my_group_id']:'';
	var limit = (paramsObject[name+'_my_limit'])?paramsObject[name+'_my_limit']:'';
	var random = (paramsObject[name+'_my_random'])?paramsObject[name+'_my_random']:'';
	var style = (paramsObject[name+'_my_style'])?paramsObject[name+'_my_style']:'';
	

	returnString = 'NEWS['+group+','+style+','+limit+','+random+']NEWS';
			
	var adv_news = $(name+'_id');
	if (adv_news){
		adv_news.value=returnString;
	} else {
		var hidden_string = document.createElement("input");
		hidden_string.type = 'hidden';
		hidden_string.id = name+'_id';
		hidden_string.value = returnString;
		hidden_string.name = name;
		parent_node = source.parentNode.parentNode;
		parent_node.appendChild(hidden_string);
	}
	return encodeURI(returnString);
}	*/
buildListTag = function  (parameters){
	var returnString = '';
	var returnHeader = '';
	var returnElements = '';
	
	header = (parameters.header)?parameters.header:'';
	element = (parameters.values)?parameters.values:'';
	rowCount = (parameters.rows)?parameters.rows:'';
	colCount = (parameters.cols)?parameters.cols:2;
	showHeadline = (parameters.show_headline)?parameters.show_headline:0;
	snippet =  (parameters.snippet)?parameters.snippet:'';
	request_name =  (parameters.name)?parameters.name:'';
	
	returnHeader+= snippet+'|'+colCount+'|'+showHeadline;	
	//LISTEN HEADER
	if (typeof header == 'string') header = $(header);	
	if (header && header.getElementsByTagName){
		var params = getFormParams(header,true);
		params = params.toArray();
		if (params.length > 0){
			//var paramsObject = params.toParamArray();
			var paramsObject = params;

			for (var i=0;i<paramsObject.length;i++){
				if (paramsObject[i]){
					if (i % colCount == 0) {
						returnHeader += '|';
					} else {
						returnHeader += '~';
					}
					var currentValue = paramsObject[i]['value'][0];
					currentValue = currentValue.replace(/,/g,'##KOMMA##');
					currentValue = currentValue.replace(/;/g,'##SEMI##');
					currentValue = currentValue.replace(/~/g,'##TILDE##');
					returnHeader += currentValue;	
				}
			}
		}
	}
	
	// LISTEN VALUES
	if (typeof element == 'string') element = $(element);	
	if (element && element.getElementsByTagName){ 
		var params = getFormParams(element,true);
		params = params.toArray();
		//var paramsObject = params.toParamArray();
		var paramsObject = params;
		
		for (var i=0;i<paramsObject.length;i++){
			if (paramsObject[i]){
				if (i % colCount == 0) {
					returnElements += '|';
				} else {
					returnElements += '~';
				}
				var currentValue = paramsObject[i]['value'][0];
				currentValue = currentValue.replace(/,/g,'##KOMMA##');
				currentValue = currentValue.replace(/;/g,'##SEMI##');
				currentValue = currentValue.replace(/~/g,'##TILDE##');
				returnElements += currentValue;	
			}
		}
		
	
	}
	
	returnString = 'ADV_LIST['+returnHeader+returnElements+']ADV_LIST';
	var adv_list = $(request_name+'_id');
	if (adv_list){
		adv_list.value=returnString;
	} else {
		var hidden_string = document.createElement("input");
		hidden_string.type = 'hidden';
		hidden_string.id = request_name+'_id';
		hidden_string.value = returnString;
		hidden_string.name = request_name;
		parent_node = element.parentNode.parentNode;
		parent_node.appendChild(hidden_string);
	}
	return encodeURI(returnString);
}

moveToList = function(source,element,globalindex,id){						
//	element_id = id;
//	--element_id;
	what = (typeof source == 'string')? $(source):source;	
	if (typeof where == 'string') where = $(where);	
	params = getFormParams(what,true);
	//clonable = $(element+(element_id));
	clonable = $(element);
	var tmpNode = clonable.cloneNode(true);	
	tmpNode.style.display = '';
	tmpNode.id = id.replace(/%d/,globalindex);


	increaseIndexRec(tmpNode);
	increaseNameRec(tmpNode,{regexpr:'\\d+'});
	setFunctionIds(tmpNode,{regexpr: id.replace(/%d/,'\\d+'),replace: tmpNode.id});

	
	//increaseIndexRec(what);
	synchNode(tmpNode,params);
	var p = clonable.parentNode;
	p = Element.cleanWhitespace(p);
	clonable.nextSibling.appendChild(tmpNode);

	
}	



editListNode = function(node,options){
	node = $(node);	
	var p = node.parentNode;
	var params = getFormParams(node,true);
//	var paramsObject = params.toArray();
	var paramsObject = params.toArray();
	//paramsObject = (paramsObject[0])?paramsObject[0]:new Array();
	var editElement = (options && options.editElement)?options.editElement:'';
	var editId = (options && options.editId)?options.editId:'';
	var editName = (options && options.editName)?options.editName:'';
	
	p = Element.cleanWhitespace(p);	
	editElement = $(editElement);
	if (!editElement) return;
	
	var tmpEdit = editElement.cloneNode(true);		
	tmpEdit.id = node.id.replace(/row/,'edit');
	setFunctionIds(tmpEdit,{regexpr: 'asset_list_row_edit',replace: tmpEdit.id});
	
	if (!tmpEdit.getElementsByTagName)  return;
	var inputs = tmpEdit.getElementsByTagName('input');
	for (var i=0; i<inputs.length; i++){
		var input = inputs[i];
		var value = (paramsObject[i] && paramsObject[i]['value'])?paramsObject[i]['value']:'';
		if (input.getAttribute && input.getAttribute('type') != 'hidden'){
			input.value = value;
		}
	}	
	
	tmpEdit.style.display = '';
	p.insertBefore(tmpEdit,node);
	Element.hide(node);	
}


editArrayListNode = function(node,options){
	node = $(node);	
	var p = node.parentNode;
	var params = getFormParams(node,true);
//	var paramsObject = params.toArray();
	var paramsObject = params.toArray();
	//paramsObject = (paramsObject[0])?paramsObject[0]:new Array();
	var editElement = (options && options.editElement)?options.editElement:'';
	var editId = (options && options.editId)?options.editId:'';
	var editName = (options && options.editName)?options.editName:'';
	
	p = Element.cleanWhitespace(p);	
	editElement = $(editElement);
	if (!editElement) return;
	
	var tmpEdit = editElement.cloneNode(true);		
	tmpEdit.id = node.id.replace(/row/,'edit');
	setFunctionIds(tmpEdit,{regexpr: 'asset_list_row_edit',replace: tmpEdit.id});
	
	if (!tmpEdit.getElementsByTagName)  return;
	var inputs = tmpEdit.getElementsByTagName('input');
	for (var i=0; i<inputs.length; i++){
		var input = inputs[i];
		var value = (paramsObject[i] && paramsObject[i]['value'])?paramsObject[i]['value']:'';
		if (input.getAttribute && input.getAttribute('type') != 'hidden'){
			input.value = value;
		}
	}	
	
	tmpEdit.style.display = '';
	p.insertBefore(tmpEdit,node);
	Element.hide(node);	
}


cancelEditRow = function(editNode){
	editNode = $(editNode);
	if (editNode){
		var showId = editNode.id.replace(/edit/,'row');
		var showNode = $(showId);
		editNode.parentNode.removeChild(editNode);
		Element.show(showNode);
	}
}

submitEditRow = function(editNode){
	editNode = $(editNode);
	if (editNode){
		var showId = editNode.id.replace(/edit/,'row');
		var showNode = $(showId);
		
		var params = getFormParams(editNode,true);
		synchNode(showNode,params);
		editNode.parentNode.removeChild(editNode);
		Element.show(showNode);
	}
}

removeListNode = function(element){
	var element = $(element);
	var parent = $(element.parentNode).cleanWhitespace();
	if (!element || !parent) return parent;

	element.remove();
	return parent.reOrder({className:'asset_list_row',attributes:['id','name']});
}		

newLine2br = function (targetStr) {
    var rn, r, n;
    rn = /\r\n/g;
    r = /\r/g;
    n = /\n/g;
	t = /\t/g;
    targetStr = targetStr.replace(rn, "<br />");
    targetStr = targetStr.replace(r, "<br />");
    targetStr = targetStr.replace(n, "<br />");
    targetStr = targetStr.replace(t, "&nbsp;&nbsp;");
    return targetStr;
}

br2newLine = function (targetStr) {

    targetStr = targetStr.replace(/<br \/>/, "\r\n");
    targetStr = targetStr.replace(/<br>/, "\r\n");
    targetStr = targetStr.replace(/<br\/>/, "\r\n");
    targetStr = targetStr.replace(/&nbsp;&nbsp;/, "\t");
    return targetStr;
}
/*
String.prototype.toRegExpString = function() { // nicht fuer netscape 4;
     return this.replace(/([\^\$\.\*\+\?\=\!\:\|\\\/\(\)\[\]\{\}])/g,"\\$1");
   };
   */
/*
**
** File 'domFunctions.js'
**
*/

var cleardiv = document.createElement('div');
cleardiv.setAttribute('class','clear');
cleardiv.appendChild(document.createElement('br'));

function appendAfter(obj,node) {
	if (obj.nextSibling) {
		obj.parentNode.insertBefore(node,obj.nextSibling);
	} else {
		obj.parentNode.appendChild(node);
	}
} 

function appendBefore(obj,node) {
	if (obj.nextSibling) {
		obj.parentNode.insertBefore(node,obj.nextSibling);
	} else {
		obj.parentNode.appendChild(node);
	}
} 

function eval_elements (options) {
	var elements;
	var element = $((options.id)?options.id:'');
	var attrib  = (options.attribute)?options.attribute:'onclick';
	var excludeInvisible  = (options.excludeInvisible)?options.excludeInvisible:true;
	var regex  = (options.regex)?options.regex:'*';
	var precondition  = (options.precondition)?options.precondition:'';
	
	var type  = (options.type)?options.type:'input';
	my_regex = new RegExp(regex);	
	//alert(Element.inspect(element));	
	if (element && element.getElementsByTagName ) {
		element = Element.cleanWhitespace(element);
		elements = element.getElementsByTagName(type);
		if (precondition != ''){ precondition = eval(precondition);}
		else {precondition == true;}
		for (var i=0; i<elements.length; i++){
			var e = $(elements[i]);
			
			// im IE ist getAttribute kein String, daher muss das anders behandelt werden !!!
			if (precondition && is_ie == false && e && e.getAttribute && e.getAttribute(attrib) && (e.getAttribute(attrib).search(regex) >= 0) && (!excludeInvisible || $(e).visible())){
				
				var evaluate = e.getAttribute(attrib);
				evaluate = evaluate.replace(/javascript:/,'');
				eval(evaluate);
			} else if (precondition && is_ie && e && e.getAttribute && e.getAttribute(attrib) && (!excludeInvisible || $(e).visible())){
				var evaluate = e.getAttribute(attrib);
				eval(evaluate);
			}
		}		
	}
}


function synchNode(node,params){
	node = $(node);	
	arrayparams = (params.toArray)? params.toArray():params;	
	if (!node) return;
	if (!node.getAttribute) return;
	if (arrayparams.length == 0) return;
	var index = new Number();
	hidden = node.getElementsByTagName('input');
	show = node.getElementsByTagName('div');
	
	for (i=0;i<hidden.length;i++){	
		element = hidden[i];
		if (element.getAttribute('id') && element.getAttribute('id').search(/value/) != -1 && element.getAttribute('id').search(/\d+/) != -1 ){
			var elem_id = element.getAttribute('id');
			var match = elem_id.match(/(\d+)_(\d+)/);
			var index = new Number(match[2]);
			var value = new String(((arrayparams[index] && arrayparams[index]['value'])?arrayparams[index]['value']:''));
			
			element.value = (value.length > 0)?value:'';
		}
	}
	for (i=0;i<show.length;i++){	
		element = show[i];
		if (element.getAttribute('id') && element.getAttribute('id').search(/value/) != -1 && element.getAttribute('id').search(/\d+/) != -1 ){
			var elem_id = element.getAttribute('id');
			var match = elem_id.match(/(\d+)_(\d+)/);
			//index = new Number(element.getAttribute('id').match(/(\d+)/));
			var index = new Number(match[2]);
			var value = new String((arrayparams[index] && arrayparams[index]['value'])?arrayparams[index]['value']:'');
			element.innerHTML = (value.strip().length > 0)?value:'&nbsp;';
		}
	}
}

nodeUp = function(node){
	node = $(node);	
	
	var p = node.parentNode;
	p = Element.cleanWhitespace(p);
	
	prev_node = node.previousSibling;
	if (prev_node && prev_node.getAttribute && prev_node.getAttribute('id')) {
		node.parentNode.insertBefore(node,prev_node);
	} 
}

nodeDown = function(node){
	node = $(node);		
	var p = node.parentNode;
	p = Element.cleanWhitespace(p);
	next_node = node.nextSibling;
	if (next_node && next_node.getAttribute && next_node.getAttribute('id')) {
		node.parentNode.insertBefore(node,next_node.nextSibling);
	} else if (next_node && next_node.nextSibling && next_node.nextSibling.getAttribute && next_node.nextSibling.getAttribute('id')){
		node.parentNode.insertBefore(node,next_node.nextSibling.nextSibling);
	} else {
		node.parentNode.appendChild(node);
	}		
}

switchParentSelectChild = function(node,options){
	node = $(node);
	var root = $((options && $((options.root))?options.root:''));
	if ( !node && !root) return;	
	if (root && root.cleanWhitespace) root.cleanWhitespace();
	if (node && node.cleanWhitespace) node.cleanWhitespace();	
	
	if (node){
		// Alle Geschwisterknoten ausblenden
		nodeSiblings = node.siblings();
		nodeSiblings.each(function(n){
			if (n.tagName.toLowerCase() == 'div' && n.visible()) n.hide();
		});
		node.show();		
	} else {
		var childnodes = new Array();
		nodes = (root.immediateDescendants)?root.immediateDescendants():new Array();
		
		for (var i=0;i<nodes.length;i++){
			if (nodes[i].tagName.toLowerCase() == 'div' && nodes[i].immediateDescendants) childnodes = childnodes.concat(nodes[i].immediateDescendants());
		}
		childnodes.each(function(n){
			if (n.tagName.toLowerCase() == 'div' && n.visible()) n.hide();
		});
	}
}

parentBackwardSelectChild = function(name){
	var tmpArray = name.split('_');
}

function myCloneNode(node,index,id,source){
	var i;	
	node = Element.cleanWhitespace(node);
	if (node == null) return;	
	var MyRegExp = new RegExp('_function');	
	if (node.value) node.value = '';
	if (node.getAttribute){
		if (node.getAttribute('onclick') && String(node.getAttribute('onclick')).search(MyRegExp) != -1) 
			node.setAttribute('onClick',String(node.getAttribute('onclick')).replace(MyRegExp, id+'_'+index));
			node.setAttribute('onClick',String(node.getAttribute('onclick')).replace(MyRegExp, id+'_'+index));
		if (node.getAttribute('onclick') && String(node.getAttribute('onClick')).search(MyRegExp) != -1) 
			node.setAttribute('onClick',String(node.getAttribute('onClick')).replace(MyRegExp, id+'_'+index));
			node.setAttribute('onClick',String(node.getAttribute('onclick')).replace(MyRegExp, id+'_'+index));
		if (node.getAttribute('name')) node.setAttribute('name',node.name);
		
		if (node.getAttribute('id')) node.setAttribute('id',node.id+'_'+index);
	}
	if (node.hasChildNodes()){
		for (i=0;i<node.childNodes.length;i++){
			myCloneNode(node.childNodes[i],index,id);
		}
	}
	return node
}

function setValueRecursive(element,value){
	element = $(element);	
	if (element == undefined) element = document;
	
	if (!element.getElementsByTagName){ return; }
	var inputs = element.getElementsByTagName('input');	
	if (element.tagName.toLowerCase() == 'input' && !inputs.length) inputs = new Array(element);
	// loop through all input  tags
	for (var i=0; i<inputs.length; i++){
		var input = inputs[i];
		if (input.name != 'action' && input.type != 'button') {
			if (input.type != 'radio' && input.type != 'checkbox') {
				input.value = value;
			} else if ((input.type == 'checkbox' || input.type == 'radio') && input.value == value){
				input.checked = 'checked'
			}
		}
	}	
	
	var textAreas = element.getElementsByTagName('textarea');
	if (element.tagName.toLowerCase() == 'textarea' && !textAreas.length) textAreas = new Array(element);
	// loop through all textarea tags
	for (var i=0; i<textAreas.length; i++){
		textArea.value = value;
	}		
	
	var selects = element.getElementsByTagName('select');
	if (element.tagName.toLowerCase() == 'select' && !selects.length) selects = new Array(element);
	// loop over all select tags
	for (var i = 0; i < selects.length; i ++) {
		var select = selects[i];
		for (var j = 0; j < select.options.length; j ++) {
			var option = select.options[j];
			if (option.value == value) {
				option.selected = "selected";
			} 
		}		
	}
}

function getFormParams(element,returnObj){	
	postObj = new Object();
	element = $(element);	
	if (element == undefined) element = document;	
	if (!element.getElementsByTagName){ return; }
	result = '';
	var inputs = element.getElementsByTagName('input');
	if (element.tagName && element.tagName.toLowerCase() == 'input' && !inputs.length) inputs = new Array(element);
	// loop through all input  tags
	for (var i=0; i<inputs.length; i++){
		var input = inputs[i];
		if (input.name != 'action' && input.type != 'button') {
			if (input.type != 'radio' && input.type != 'checkbox') {
				result += input.name+'='+encodeURI(input.value)+'&';
				if (!(typeof postObj[input.name] == 'object')) postObj[input.name] = new Array();
				postObj[input.name].push(input.value);
			} else if (input.type == 'checkbox'){
				result += input.name+((input.checked)?'=1&':'=&');
				if (!(typeof postObj[input.name] == 'object' || typeof postObj[input.name] == 'object')) postObj[input.name] = new Array();
				postObj[input.name].push(((input.checked)?'1':'0'));
			} else if (input.type == 'radio' && input.checked){
				result += input.name+'='+encodeURI(input.value)+'&';
				if (!(typeof postObj[input.name] == 'object' || typeof postObj[input.name] == 'object')) postObj[input.name] = new Array();
				postObj[input.name].push(input.value);
			}
		}
	}	
	
	var textAreas = element.getElementsByTagName('textarea');
	if (element.tagName && element.tagName.toLowerCase() == 'textarea' && !textAreas.length) textAreas = new Array(element);
	// loop through all textarea tags
	for (var i=0; i<textAreas.length; i++){
		var textArea = textAreas[i];
		result += textArea.name+'='+encodeURI(textArea.value)+'&';
		if (!(typeof postObj[textArea.name] == 'object')) postObj[textArea.name] = new Array();
		postObj[textArea.name].push(textArea.value);
	}		
	
	var selects = element.getElementsByTagName('select');
	if (element.tagName && element.tagName.toLowerCase() == 'select' && !selects.length) selects = new Array(element);

	// loop over all select tags
	for (var i = 0; i < selects.length; i ++) {
		var select = selects[i];
		var twoselect = (select.getAttribute) ? select.getAttribute('rel') == 'twoselect' : false;
		if (twoselect) {
			if (select.options.length <= 0)
				result += select.name + '=&';
		}
		postObj[select.name] = new Array();
		for (var j = 0; j < select.options.length; j ++) {
			var option = select.options[j];
			if (option.selected || twoselect ) {
				result += select.name + '=' + encodeURI(option.value) + '&';
				postObj[select.name].push(option.value);
			} 
		}		
	}
	return (returnObj) ? $H(postObj) : result.substr(0, result.length-1);
}


function clearFormParams(element){
	element = $(element);
	if (element == undefined) element = document;
	if (!element.getElementsByTagName){ return; }
	var inputs = element.getElementsByTagName('input');
	// loop through all input  tags
	for (var i=0; i<inputs.length; i++){
		var input = inputs[i];
		if (input.getAttribute && input.getAttribute('type') != 'hidden' && input.getAttribute('type') != 'button' && input.getAttribute('type') != 'submit' && input.getAttribute('type') != 'image' && input.getAttribute('type') != 'reset'){
			input.value='';
		}
	}	
	var textAreas = element.getElementsByTagName('textarea');
	// loop through all input  tags
	for (var i=0; i<textAreas.length; i++){
		var textArea = textAreas[i];
		textArea.value='';
	}		
	return element;
}

function createClearDiv(){
	return cleardiv.cloneNode(true);
}


var kb_prototypes = {
	/** liefert das erste gefundene eingabe Element zurück 
	 * param Element (nötig für Prototype)
	 */
	findFirstInput: function(element){
		element = $(element);
		return (['input', 'select', 'textarea'].include(element.tagName.toLowerCase())) ? element : element.descendants().find(function(element){
			return element.type != 'hidden' && !element.disabled &&['input','select','textarea'] .include(element.tagName.toLowerCase());
		});
		
	}
}
Element.addMethods(kb_prototypes);
/*
**
** File 'image.js'
**
*/

if(typeof KbImage=='undefined') {
    var KbImage = {};
} 
/********************* IMAGE ZOOMER ***********************/

Object.extend(KbImage,{
	Zoom: Class.create()
})


/**
 * Image zoom control
 * 
 */
KbImage.Zoom.prototype = {
	
	reset: function() {
		
		this.options = Object.extend({
			scalefactor:0,
			imageDim:null
		},arguments[0] || {});
		
		if (this.options.scalefactor){
			this.slider.value = this.options.scalefactor;
			this.scalefactor = this.options.scalefactor;			
		}
	
		var hidden = 0;
		if (this.containerParent && !this.containerParent.visible()) {
			hidden = 1;
			this.containerParent.setStyle({opacity:'0.1'});
			this.containerParent.show();
		}
		
        this.containerDim = Element.getDimensions(this.containerEl);
        this.imageDim = this.options.imageDim? this.options.imageDim : Element.getDimensions(this.imageEl);
        
		
		
		this.imageDim.ratio = this.imageDim.width/this.imageDim.height;

		this.floorZoom = 1;
		this.ceilingZoom = ((this.imageDim.width/this.containerDim.width) > 1) ? (this.imageDim.width/this.containerDim.width) :1;
		
        this.draggable = new Draggable(this.imageEl.id, {
            starteffect:false, 
            reverteffect:false, 
            endeffect:false, 
            snap:this.contain.bind(this)
        });
		
		var sliderValue = this.slider.value;
		this.slider = new Control.Slider(this.handleEl.id, this.trackEl.id, {
            axis:'horizontal', 
            minimum:0, 
            maximum:Element.getDimensions(this.trackEl).width, 
            alignX:0, 
            increment:1, 
            sliderValue:sliderValue, 
            onSlide:this.scale.bind(this), 
            onChange:this.scale.bind(this)
        });
        
		this.scale(this.scalefactor);
		
		if (this.containerParent && hidden) {
			this.containerParent.hide();
			this.containerParent.setStyle({opacity:'1'});
		}
	},


    initialize: function(imageEl, trackEl, handleEl, zoomInEl, zoomOutEl){
        this.containerEl = $(imageEl).parentNode;
        this.imageEl = $(imageEl);
        this.handleEl = $(handleEl);
        this.trackEl = $(trackEl);
        var hidden = 0;
		
		this.containerParent = this.containerEl.parentNode;
		
		if (this.containerParent && !this.containerParent.visible()) {
			hidden = 1;
			this.containerParent.setStyle({opacity:'0.1'});
			this.containerParent.show();
		}
		
        this.containerDim = Element.getDimensions(this.containerEl);
        this.imageDim = Element.getDimensions(this.imageEl);
        
		
		
		this.imageDim.ratio = this.imageDim.width/this.imageDim.height;
        
        this.floorZoom = 1;
        this.ceilingZoom = ((this.imageDim.width/this.containerDim.width) > 1) ? (this.imageDim.width/this.containerDim.width) :1;
        this.imageX = 0;
        this.imageY = 0;
        this.imageZoom = 1;
        
        this.sliderSpeed = 0;
        this.sliderAccel = 0;
        this.zoomBtnPressed = false;
        
        this.showFull = false;
        
        this.selects = document.getElementsByTagName('select');
        
        this.draggable = new Draggable(imageEl, {
            starteffect:false, 
            reverteffect:false, 
            endeffect:false, 
            snap:this.contain.bind(this)
        });
        
        this.slider = new Control.Slider(handleEl, trackEl, {
            axis:'horizontal', 
            minimum:0, 
            maximum:Element.getDimensions(this.trackEl).width, 
            alignX:0, 
            increment:1, 
            sliderValue:0, 
            onSlide:this.scale.bind(this), 
            onChange:this.scale.bind(this)
        });

        this.scale(0.00);
		
		if (this.containerParent && hidden) {
			this.containerParent.hide();
			this.containerParent.setStyle({opacity:'1'});
		}
        
    //    Event.observe(this.imageEl, 'dblclick', this.toggleFull.bind(this));
        
        Event.observe($(zoomInEl), 'mousedown', this.startZoomIn.bind(this));
        Event.observe($(zoomInEl), 'mouseup', this.stopZooming.bind(this));
        Event.observe($(zoomInEl), 'mouseout', this.stopZooming.bind(this));
        
        Event.observe($(zoomOutEl), 'mousedown', this.startZoomOut.bind(this));
        Event.observe($(zoomOutEl), 'mouseup', this.stopZooming.bind(this));    
        Event.observe($(zoomOutEl), 'mouseout', this.stopZooming.bind(this));   
    },
        
    toggleFull: function () {
        this.showFull = !this.showFull;
        //TODO: hide selects for IE only
        for (i=0; i<this.selects.length; i++) {
            this.selects[i].style.visibility = this.showFull ? 'hidden' : 'visible';
        }
        this.trackEl.style.visibility = this.showFull ? 'hidden' : 'visible';
        this.containerEl.style.overflow = this.showFull ? 'visible' : 'hidden';
        this.containerEl.style.zIndex = this.showFull ? '100' : '1';
        
        return this;
    },
    
    scale: function (v) {
		this.scalefactor = v;
        var centerX = (this.containerDim.width*(1-this.imageZoom)/2-this.imageX)/this.imageZoom;
        var centerY = (this.containerDim.height*(1-this.imageZoom)/2-this.imageY)/this.imageZoom;
        
        this.imageZoom = this.floorZoom+(v*(this.ceilingZoom-this.floorZoom));
        
        this.imageEl.style.width = (this.imageZoom*this.containerDim.width)+'px';
        if(this.containerDim.ratio){
          this.imageEl.style.height = (this.imageZoom*this.containerDim.width*this.containerDim.ratio)+'px'; // for safari
        }
        
        

		if (this.options && this.options.imageDim) {
			this.contain(this.options.imageDim.left, this.options.imageDim.top, this.draggable);
			this.options.imageDim = null;
		} else {
			this.imageX = this.containerDim.width*(1-this.imageZoom)/2-centerX*this.imageZoom;
			this.imageY = this.containerDim.height*(1-this.imageZoom)/2-centerY*this.imageZoom;
			this.contain(this.imageX, this.imageY, this.draggable);
		}
        
        return true;
    },
    
    startZoomIn: function()
    {
        this.zoomBtnPressed = true;
        this.sliderAccel = .004;
        this.periodicalZoom();
        this.zoomer = new PeriodicalExecuter(this.periodicalZoom.bind(this), .05);
        return this;
    },
    
    startZoomOut: function()
    {
        this.zoomBtnPressed = true;
        this.sliderAccel = -.004;
        this.periodicalZoom();
        this.zoomer = new PeriodicalExecuter(this.periodicalZoom.bind(this), .05);
        return this;
    },
    
    stopZooming: function()
    {
        if (!this.zoomer || this.sliderSpeed==0) {
            return;
        }
        this.zoomBtnPressed = false;
        this.sliderAccel = 0;
    },
    
    periodicalZoom: function()
    {
        if (!this.zoomer) {
            return this;
        }
        
        if (this.zoomBtnPressed) {
            this.sliderSpeed += this.sliderAccel;
        } else {
            this.sliderSpeed /= 1.5;
            if (Math.abs(this.sliderSpeed)<.001) {
                this.sliderSpeed = 0;
                this.zoomer.stop();
                this.zoomer = null;
            }
        }
        this.slider.value += this.sliderSpeed;
        
        this.slider.setValue(this.slider.value);
        this.scale(this.slider.value);
        
        return this;
    },
    
    contain: function (x,y,draggable) {
		if (x == undefined) x = 0;
		if (y == undefined) y = 0;
		
        var dim = Element.getDimensions(draggable.element);
        
        var xMin = 0, xMax = this.containerDim.width-dim.width;
        var yMin = 0, yMax = this.containerDim.height-dim.height;
        
        x = x>xMin ? xMin : x;
        x = x<xMax ? xMax : x;
        y = y>yMin ? yMin : y;
        y = y<yMax ? yMax : y;
        
        this.imageX = x;
        this.imageY = (y>0)?0:y;
        
        this.imageEl.style.left = this.imageX+'px';
        this.imageEl.style.top = this.imageY+'px';
        
        return [x,y];
    }
}

/*
**
** File 'dragdrop.js'
**
*/
// script.aculo.us dragdrop.js v1.8.2, Tue Nov 18 18:30:58 +0100 2008

// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
//           (c) 2005-2008 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz)
//
// script.aculo.us is freely distributable under the terms of an MIT-style license.
// For details, see the script.aculo.us web site: http://script.aculo.us/

if(Object.isUndefined(Effect))
  throw("dragdrop.js requires including script.aculo.us' effects.js library");

var Droppables = {
  drops: [],

  remove: function(element) {
    this.drops = this.drops.reject(function(d) { return d.element==$(element) });
  },

  add: function(element) {
    element = $(element);
    var options = Object.extend({
      greedy:     true,
      hoverclass: null,
      tree:       false
    }, arguments[1] || { });

    // cache containers
    if(options.containment) {
      options._containers = [];
      var containment = options.containment;
      if(Object.isArray(containment)) {
        containment.each( function(c) { options._containers.push($(c)) });
      } else {
        options._containers.push($(containment));
      }
    }

    if(options.accept) options.accept = [options.accept].flatten();

    Element.makePositioned(element); // fix IE
    options.element = element;

    this.drops.push(options);
  },

  findDeepestChild: function(drops) {
    deepest = drops[0];

    for (i = 1; i < drops.length; ++i)
      if (Element.isParent(drops[i].element, deepest.element))
        deepest = drops[i];

    return deepest;
  },

  isContained: function(element, drop) {
    var containmentNode;
    if(drop.tree) {
      containmentNode = element.treeNode;
    } else {
      containmentNode = element.parentNode;
    }
    return drop._containers.detect(function(c) { return containmentNode == c });
  },

  isAffected: function(point, element, drop) {
    return (
      (drop.element!=element) &&
      ((!drop._containers) ||
        this.isContained(element, drop)) &&
      ((!drop.accept) ||
        (Element.classNames(element).detect(
          function(v) { return drop.accept.include(v) } ) )) &&
      Position.within(drop.element, point[0], point[1]) );
  },

  deactivate: function(drop) {
    if(drop.hoverclass)
      Element.removeClassName(drop.element, drop.hoverclass);
    this.last_active = null;
  },

  activate: function(drop) {
    if(drop.hoverclass)
      Element.addClassName(drop.element, drop.hoverclass);
    this.last_active = drop;
  },

  show: function(point, element) {
    if(!this.drops.length) return;
    var drop, affected = [];

    this.drops.each( function(drop) {
      if(Droppables.isAffected(point, element, drop))
        affected.push(drop);
    });

    if(affected.length>0)
      drop = Droppables.findDeepestChild(affected);

    if(this.last_active && this.last_active != drop) this.deactivate(this.last_active);
    if (drop) {
      Position.within(drop.element, point[0], point[1]);
      if(drop.onHover)
        drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));

      if (drop != this.last_active) Droppables.activate(drop);
    }
  },

  fire: function(event, element) {
    if(!this.last_active) return;
    Position.prepare();

    if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active))
      if (this.last_active.onDrop) {
        this.last_active.onDrop(element, this.last_active.element, event);
        return true;
      }
  },

  reset: function() {
    if(this.last_active)
      this.deactivate(this.last_active);
  }
};

var Draggables = {
  drags: [],
  observers: [],

  register: function(draggable) {
    if(this.drags.length == 0) {
      this.eventMouseUp   = this.endDrag.bindAsEventListener(this);
      this.eventMouseMove = this.updateDrag.bindAsEventListener(this);
      this.eventKeypress  = this.keyPress.bindAsEventListener(this);

      Event.observe(document, "mouseup", this.eventMouseUp);
      Event.observe(document, "mousemove", this.eventMouseMove);
      Event.observe(document, "keypress", this.eventKeypress);
    }
    this.drags.push(draggable);
  },

  unregister: function(draggable) {
    this.drags = this.drags.reject(function(d) { return d==draggable });
    if(this.drags.length == 0) {
      Event.stopObserving(document, "mouseup", this.eventMouseUp);
      Event.stopObserving(document, "mousemove", this.eventMouseMove);
      Event.stopObserving(document, "keypress", this.eventKeypress);
    }
  },

  activate: function(draggable) {
    if(draggable.options.delay) {
      this._timeout = setTimeout(function() {
        Draggables._timeout = null;
        window.focus();
        Draggables.activeDraggable = draggable;
      }.bind(this), draggable.options.delay);
    } else {
      window.focus(); // allows keypress events if window isn't currently focused, fails for Safari
      this.activeDraggable = draggable;
    }
  },

  deactivate: function() {
    this.activeDraggable = null;
  },

  updateDrag: function(event) {
    if(!this.activeDraggable) return;
    var pointer = [Event.pointerX(event), Event.pointerY(event)];
    // Mozilla-based browsers fire successive mousemove events with
    // the same coordinates, prevent needless redrawing (moz bug?)
    if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return;
    this._lastPointer = pointer;

    this.activeDraggable.updateDrag(event, pointer);
  },

  endDrag: function(event) {
    if(this._timeout) {
      clearTimeout(this._timeout);
      this._timeout = null;
    }
    if(!this.activeDraggable) return;
    this._lastPointer = null;
    this.activeDraggable.endDrag(event);
    this.activeDraggable = null;
  },

  keyPress: function(event) {
    if(this.activeDraggable)
      this.activeDraggable.keyPress(event);
  },

  addObserver: function(observer) {
    this.observers.push(observer);
    this._cacheObserverCallbacks();
  },

  removeObserver: function(element) {  // element instead of observer fixes mem leaks
    this.observers = this.observers.reject( function(o) { return o.element==element });
    this._cacheObserverCallbacks();
  },

  notify: function(eventName, draggable, event) {  // 'onStart', 'onEnd', 'onDrag'
    if(this[eventName+'Count'] > 0)
      this.observers.each( function(o) {
        if(o[eventName]) o[eventName](eventName, draggable, event);
      });
    if(draggable.options[eventName]) draggable.options[eventName](draggable, event);
  },

  _cacheObserverCallbacks: function() {
    ['onStart','onEnd','onDrag'].each( function(eventName) {
      Draggables[eventName+'Count'] = Draggables.observers.select(
        function(o) { return o[eventName]; }
      ).length;
    });
  }
};

/*--------------------------------------------------------------------------*/

var Draggable = Class.create({
  initialize: function(element) {
    var defaults = {
      handle: false,
      reverteffect: function(element, top_offset, left_offset) {
        var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02;
        new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur,
          queue: {scope:'_draggable', position:'end'}
        });
      },
      endeffect: function(element) {
        var toOpacity = Object.isNumber(element._opacity) ? element._opacity : 1.0;
        new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity,
          queue: {scope:'_draggable', position:'end'},
          afterFinish: function(){
            Draggable._dragging[element] = false
          }
        });
      },
      zindex: 1000,
      revert: false,
      quiet: false,
      scroll: false,
      scrollSensitivity: 20,
      scrollSpeed: 15,
      snap: false,  // false, or xy or [x,y] or function(x,y){ return [x,y] }
      delay: 0
    };

    if(!arguments[1] || Object.isUndefined(arguments[1].endeffect))
      Object.extend(defaults, {
        starteffect: function(element) {
          element._opacity = Element.getOpacity(element);
          Draggable._dragging[element] = true;
          new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7});
        }
      });

    var options = Object.extend(defaults, arguments[1] || { });

    this.element = $(element);

    if(options.handle && Object.isString(options.handle))
      this.handle = this.element.down('.'+options.handle, 0);

    if(!this.handle) this.handle = $(options.handle);
    if(!this.handle) this.handle = this.element;

    if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) {
      options.scroll = $(options.scroll);
      this._isScrollChild = Element.childOf(this.element, options.scroll);
    }

    Element.makePositioned(this.element); // fix IE

    this.options  = options;
    this.dragging = false;

    this.eventMouseDown = this.initDrag.bindAsEventListener(this);
    Event.observe(this.handle, "mousedown", this.eventMouseDown);

    Draggables.register(this);
  },

  destroy: function() {
    Event.stopObserving(this.handle, "mousedown", this.eventMouseDown);
    Draggables.unregister(this);
  },

  currentDelta: function() {
    return([
      parseInt(Element.getStyle(this.element,'left') || '0'),
      parseInt(Element.getStyle(this.element,'top') || '0')]);
  },

  initDrag: function(event) {
    if(!Object.isUndefined(Draggable._dragging[this.element]) &&
      Draggable._dragging[this.element]) return;
    if(Event.isLeftClick(event)) {
      // abort on form elements, fixes a Firefox issue
      var src = Event.element(event);
      if((tag_name = src.tagName.toUpperCase()) && (
        tag_name=='INPUT' ||
        tag_name=='SELECT' ||
        tag_name=='OPTION' ||
        tag_name=='BUTTON' ||
        tag_name=='TEXTAREA')) return;

      var pointer = [Event.pointerX(event), Event.pointerY(event)];
      var pos     = Position.cumulativeOffset(this.element);
      this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) });

      Draggables.activate(this);
      Event.stop(event);
    }
  },

  startDrag: function(event) {
    this.dragging = true;
    if(!this.delta)
      this.delta = this.currentDelta();

    if(this.options.zindex) {
      this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0);
      this.element.style.zIndex = this.options.zindex;
    }

    if(this.options.ghosting) {
      this._clone = this.element.cloneNode(true);
      this._originallyAbsolute = (this.element.getStyle('position') == 'absolute');
      if (!this._originallyAbsolute)
        Position.absolutize(this.element);
      this.element.parentNode.insertBefore(this._clone, this.element);
    }

    if(this.options.scroll) {
      if (this.options.scroll == window) {
        var where = this._getWindowScroll(this.options.scroll);
        this.originalScrollLeft = where.left;
        this.originalScrollTop = where.top;
      } else {
        this.originalScrollLeft = this.options.scroll.scrollLeft;
        this.originalScrollTop = this.options.scroll.scrollTop;
      }
    }

    Draggables.notify('onStart', this, event);

    if(this.options.starteffect) this.options.starteffect(this.element);
  },

  updateDrag: function(event, pointer) {
    if(!this.dragging) this.startDrag(event);

    if(!this.options.quiet){
      Position.prepare();
      Droppables.show(pointer, this.element);
    }

    Draggables.notify('onDrag', this, event);

    this.draw(pointer);
    if(this.options.change) this.options.change(this);

    if(this.options.scroll) {
      this.stopScrolling();

      var p;
      if (this.options.scroll == window) {
        with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; }
      } else {
        p = Position.page(this.options.scroll);
        p[0] += this.options.scroll.scrollLeft + Position.deltaX;
        p[1] += this.options.scroll.scrollTop + Position.deltaY;
        p.push(p[0]+this.options.scroll.offsetWidth);
        p.push(p[1]+this.options.scroll.offsetHeight);
      }
      var speed = [0,0];
      if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity);
      if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity);
      if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity);
      if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity);
      this.startScrolling(speed);
    }

    // fix AppleWebKit rendering
    if(Prototype.Browser.WebKit) window.scrollBy(0,0);

    Event.stop(event);
  },

  finishDrag: function(event, success) {
    this.dragging = false;

    if(this.options.quiet){
      Position.prepare();
      var pointer = [Event.pointerX(event), Event.pointerY(event)];
      Droppables.show(pointer, this.element);
    }

    if(this.options.ghosting) {
      if (!this._originallyAbsolute)
        Position.relativize(this.element);
      delete this._originallyAbsolute;
      Element.remove(this._clone);
      this._clone = null;
    }

    var dropped = false;
    if(success) {
      dropped = Droppables.fire(event, this.element);
      if (!dropped) dropped = false;
    }
    if(dropped && this.options.onDropped) this.options.onDropped(this.element);
    Draggables.notify('onEnd', this, event);

    var revert = this.options.revert;
    if(revert && Object.isFunction(revert)) revert = revert(this.element);

    var d = this.currentDelta();
    if(revert && this.options.reverteffect) {
      if (dropped == 0 || revert != 'failure')
        this.options.reverteffect(this.element,
          d[1]-this.delta[1], d[0]-this.delta[0]);
    } else {
      this.delta = d;
    }

    if(this.options.zindex)
      this.element.style.zIndex = this.originalZ;

    if(this.options.endeffect)
      this.options.endeffect(this.element);

    Draggables.deactivate(this);
    Droppables.reset();
  },

  keyPress: function(event) {
    if(event.keyCode!=Event.KEY_ESC) return;
    this.finishDrag(event, false);
    Event.stop(event);
  },

  endDrag: function(event) {
    if(!this.dragging) return;
    this.stopScrolling();
    this.finishDrag(event, true);
    Event.stop(event);
  },

  draw: function(point) {
    var pos = Position.cumulativeOffset(this.element);
    if(this.options.ghosting) {
      var r   = Position.realOffset(this.element);
      pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY;
    }

    var d = this.currentDelta();
    pos[0] -= d[0]; pos[1] -= d[1];

    if(this.options.scroll && (this.options.scroll != window && this._isScrollChild)) {
      pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft;
      pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop;
    }

    var p = [0,1].map(function(i){
      return (point[i]-pos[i]-this.offset[i])
    }.bind(this));

    if(this.options.snap) {
      if(Object.isFunction(this.options.snap)) {
        p = this.options.snap(p[0],p[1],this);
      } else {
      if(Object.isArray(this.options.snap)) {
        p = p.map( function(v, i) {
          return (v/this.options.snap[i]).round()*this.options.snap[i] }.bind(this));
      } else {
        p = p.map( function(v) {
          return (v/this.options.snap).round()*this.options.snap }.bind(this));
      }
    }}

    var style = this.element.style;
    if((!this.options.constraint) || (this.options.constraint=='horizontal'))
      style.left = p[0] + "px";
    if((!this.options.constraint) || (this.options.constraint=='vertical'))
      style.top  = p[1] + "px";

    if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering
  },

  stopScrolling: function() {
    if(this.scrollInterval) {
      clearInterval(this.scrollInterval);
      this.scrollInterval = null;
      Draggables._lastScrollPointer = null;
    }
  },

  startScrolling: function(speed) {
    if(!(speed[0] || speed[1])) return;
    this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed];
    this.lastScrolled = new Date();
    this.scrollInterval = setInterval(this.scroll.bind(this), 10);
  },

  scroll: function() {
    var current = new Date();
    var delta = current - this.lastScrolled;
    this.lastScrolled = current;
    if(this.options.scroll == window) {
      with (this._getWindowScroll(this.options.scroll)) {
        if (this.scrollSpeed[0] || this.scrollSpeed[1]) {
          var d = delta / 1000;
          this.options.scroll.scrollTo( left + d*this.scrollSpeed[0], top + d*this.scrollSpeed[1] );
        }
      }
    } else {
      this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000;
      this.options.scroll.scrollTop  += this.scrollSpeed[1] * delta / 1000;
    }

    Position.prepare();
    Droppables.show(Draggables._lastPointer, this.element);
    Draggables.notify('onDrag', this);
    if (this._isScrollChild) {
      Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer);
      Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000;
      Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000;
      if (Draggables._lastScrollPointer[0] < 0)
        Draggables._lastScrollPointer[0] = 0;
      if (Draggables._lastScrollPointer[1] < 0)
        Draggables._lastScrollPointer[1] = 0;
      this.draw(Draggables._lastScrollPointer);
    }

    if(this.options.change) this.options.change(this);
  },

  _getWindowScroll: function(w) {
    var T, L, W, H;
    with (w.document) {
      if (w.document.documentElement && documentElement.scrollTop) {
        T = documentElement.scrollTop;
        L = documentElement.scrollLeft;
      } else if (w.document.body) {
        T = body.scrollTop;
        L = body.scrollLeft;
      }
      if (w.innerWidth) {
        W = w.innerWidth;
        H = w.innerHeight;
      } else if (w.document.documentElement && documentElement.clientWidth) {
        W = documentElement.clientWidth;
        H = documentElement.clientHeight;
      } else {
        W = body.offsetWidth;
        H = body.offsetHeight;
      }
    }
    return { top: T, left: L, width: W, height: H };
  }
});

Draggable._dragging = { };

/*--------------------------------------------------------------------------*/

var SortableObserver = Class.create({
  initialize: function(element, observer) {
    this.element   = $(element);
    this.observer  = observer;
    this.lastValue = Sortable.serialize(this.element);
  },

  onStart: function() {
    this.lastValue = Sortable.serialize(this.element);
  },

  onEnd: function() {
    Sortable.unmark();
    if(this.lastValue != Sortable.serialize(this.element))
      this.observer(this.element)
  }
});

var Sortable = {
  SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/,

  sortables: { },

  _findRootElement: function(element) {
    while (element.tagName.toUpperCase() != "BODY") {
      if(element.id && Sortable.sortables[element.id]) return element;
      element = element.parentNode;
    }
  },

  options: function(element) {
    element = Sortable._findRootElement($(element));
    if(!element) return;
    return Sortable.sortables[element.id];
  },

  destroy: function(element){
    element = $(element);
    var s = Sortable.sortables[element.id];

    if(s) {
      Draggables.removeObserver(s.element);
      s.droppables.each(function(d){ Droppables.remove(d) });
      s.draggables.invoke('destroy');

      delete Sortable.sortables[s.element.id];
    }
  },

  create: function(element) {
    element = $(element);
    var options = Object.extend({
      element:     element,
      tag:         'li',       // assumes li children, override with tag: 'tagname'
      dropOnEmpty: false,
      tree:        false,
      treeTag:     'ul',
      overlap:     'vertical', // one of 'vertical', 'horizontal'
      constraint:  'vertical', // one of 'vertical', 'horizontal', false
      containment: element,    // also takes array of elements (or id's); or false
      handle:      false,      // or a CSS class
      only:        false,
      delay:       0,
      hoverclass:  null,
      ghosting:    false,
      quiet:       false,
      scroll:      false,
      scrollSensitivity: 20,
      scrollSpeed: 15,
      format:      this.SERIALIZE_RULE,

      // these take arrays of elements or ids and can be
      // used for better initialization performance
      elements:    false,
      handles:     false,

      onChange:    Prototype.emptyFunction,
      onUpdate:    Prototype.emptyFunction,
      onStart:     Prototype.emptyFunction,   //  prepare an onStart function
      onEnd:       Prototype.emptyFunction   //  prepare an onEnd function 
    }, arguments[1] || { });

    // clear any old sortable with same element
    this.destroy(element);

    // build options for the draggables
    var options_for_draggable = {
      revert:      true,
      quiet:       options.quiet,
      scroll:      options.scroll,
      scrollSpeed: options.scrollSpeed,
      scrollSensitivity: options.scrollSensitivity,
      delay:       options.delay,
      ghosting:    options.ghosting,
      constraint:  options.constraint,
      handle:      options.handle,
	  onStart:     options.onStart,   // apply the onStart function to the draggable istance
      onEnd:       options.onEnd };

    if(options.starteffect)
      options_for_draggable.starteffect = options.starteffect;

    if(options.reverteffect)
      options_for_draggable.reverteffect = options.reverteffect;
    else
      if(options.ghosting) options_for_draggable.reverteffect = function(element) {
        element.style.top  = 0;
        element.style.left = 0;
      };

    if(options.endeffect)
      options_for_draggable.endeffect = options.endeffect;

    if(options.zindex)
      options_for_draggable.zindex = options.zindex;

    // build options for the droppables
    var options_for_droppable = {
      overlap:     options.overlap,
      containment: options.containment,
      tree:        options.tree,
      hoverclass:  options.hoverclass,
      onHover:     Sortable.onHover
    };

    var options_for_tree = {
      onHover:      Sortable.onEmptyHover,
      overlap:      options.overlap,
      containment:  options.containment,
      hoverclass:   options.hoverclass
    };

    // fix for gecko engine
    Element.cleanWhitespace(element);

    options.draggables = [];
    options.droppables = [];

    // drop on empty handling
    if(options.dropOnEmpty || options.tree) {
      Droppables.add(element, options_for_tree);
      options.droppables.push(element);
    }

    (options.elements || this.findElements(element, options) || []).each( function(e,i) {
      var handle = options.handles ? $(options.handles[i]) :
        (options.handle ? $(e).select('.' + options.handle)[0] : e);
      options.draggables.push(
        new Draggable(e, Object.extend(options_for_draggable, { handle: handle })));
      Droppables.add(e, options_for_droppable);
      if(options.tree) e.treeNode = element;
      options.droppables.push(e);
    });

    if(options.tree) {
      (Sortable.findTreeElements(element, options) || []).each( function(e) {
        Droppables.add(e, options_for_tree);
        e.treeNode = element;
        options.droppables.push(e);
      });
    }

    // keep reference
    this.sortables[element.id] = options;

    // for onupdate
    Draggables.addObserver(new SortableObserver(element, options.onUpdate));

  },

  // return all suitable-for-sortable elements in a guaranteed order
  findElements: function(element, options) {
    return Element.findChildren(
      element, options.only, options.tree ? true : false, options.tag);
  },

  findTreeElements: function(element, options) {
    return Element.findChildren(
      element, options.only, options.tree ? true : false, options.treeTag);
  },

  onHover: function(element, dropon, overlap) {
    if(Element.isParent(dropon, element)) return;

    if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) {
      return;
    } else if(overlap>0.5) {
      Sortable.mark(dropon, 'before');
      if(dropon.previousSibling != element) {
        var oldParentNode = element.parentNode;
        element.style.visibility = "hidden"; // fix gecko rendering
        dropon.parentNode.insertBefore(element, dropon);
        if(dropon.parentNode!=oldParentNode)
          Sortable.options(oldParentNode).onChange(element);
        Sortable.options(dropon.parentNode).onChange(element);
      }
    } else {
      Sortable.mark(dropon, 'after');
      var nextElement = dropon.nextSibling || null;
      if(nextElement != element) {
        var oldParentNode = element.parentNode;
        element.style.visibility = "hidden"; // fix gecko rendering
        dropon.parentNode.insertBefore(element, nextElement);
        if(dropon.parentNode!=oldParentNode)
          Sortable.options(oldParentNode).onChange(element);
        Sortable.options(dropon.parentNode).onChange(element);
      }
    }
  },

  onEmptyHover: function(element, dropon, overlap) {
    var oldParentNode = element.parentNode;
    var droponOptions = Sortable.options(dropon);

    if(!Element.isParent(dropon, element)) {
      var index;

      var children = Sortable.findElements(dropon, {tag: droponOptions.tag, only: droponOptions.only});
      var child = null;

      if(children) {
        var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap);

        for (index = 0; index < children.length; index += 1) {
          if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) {
            offset -= Element.offsetSize (children[index], droponOptions.overlap);
          } else if (offset - (Element.offsetSize (children[index], droponOptions.overlap) / 2) >= 0) {
            child = index + 1 < children.length ? children[index + 1] : null;
            break;
          } else {
            child = children[index];
            break;
          }
        }
      }

      dropon.insertBefore(element, child);

      Sortable.options(oldParentNode).onChange(element);
      droponOptions.onChange(element);
    }
  },

  unmark: function() {
    if(Sortable._marker) Sortable._marker.hide();
  },

  mark: function(dropon, position) {
    // mark on ghosting only
    var sortable = Sortable.options(dropon.parentNode);
    if(sortable && !sortable.ghosting) return;

    if(!Sortable._marker) {
      Sortable._marker =
        ($('dropmarker') || Element.extend(document.createElement('DIV'))).
          hide().addClassName('dropmarker').setStyle({position:'absolute'});
      document.getElementsByTagName("body").item(0).appendChild(Sortable._marker);
    }
    var offsets = Position.cumulativeOffset(dropon);
    Sortable._marker.setStyle({left: offsets[0]+'px', top: offsets[1] + 'px'});

    if(position=='after')
      if(sortable.overlap == 'horizontal')
        Sortable._marker.setStyle({left: (offsets[0]+dropon.clientWidth) + 'px'});
      else
        Sortable._marker.setStyle({top: (offsets[1]+dropon.clientHeight) + 'px'});

    Sortable._marker.show();
  },

  _tree: function(element, options, parent) {
    var children = Sortable.findElements(element, options) || [];

    for (var i = 0; i < children.length; ++i) {
      var match = children[i].id.match(options.format);

      if (!match) continue;

      var child = {
        id: encodeURIComponent(match ? match[1] : null),
        element: element,
        parent: parent,
        children: [],
        position: parent.children.length,
        container: $(children[i]).down(options.treeTag)
      };

      /* Get the element containing the children and recurse over it */
      if (child.container)
        this._tree(child.container, options, child);

      parent.children.push (child);
    }

    return parent;
  },

  tree: function(element) {
    element = $(element);
    var sortableOptions = this.options(element);
    var options = Object.extend({
      tag: sortableOptions.tag,
      treeTag: sortableOptions.treeTag,
      only: sortableOptions.only,
      name: element.id,
      format: sortableOptions.format
    }, arguments[1] || { });

    var root = {
      id: null,
      parent: null,
      children: [],
      container: element,
      position: 0
    };

    return Sortable._tree(element, options, root);
  },

  /* Construct a [i] index for a particular node */
  _constructIndex: function(node) {
    var index = '';
    do {
      if (node.id) index = '[' + node.position + ']' + index;
    } while ((node = node.parent) != null);
    return index;
  },

  sequence: function(element) {
    element = $(element);
    var options = Object.extend(this.options(element), arguments[1] || { });

    return $(this.findElements(element, options) || []).map( function(item) {
      return item.id.match(options.format) ? item.id.match(options.format)[1] : '';
    });
  },

  setSequence: function(element, new_sequence) {
    element = $(element);
    var options = Object.extend(this.options(element), arguments[2] || { });

    var nodeMap = { };
    this.findElements(element, options).each( function(n) {
        if (n.id.match(options.format))
            nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode];
        n.parentNode.removeChild(n);
    });

    new_sequence.each(function(ident) {
      var n = nodeMap[ident];
      if (n) {
        n[1].appendChild(n[0]);
        delete nodeMap[ident];
      }
    });
  },

  serialize: function(element) {
    element = $(element);
    var options = Object.extend(Sortable.options(element), arguments[1] || { });
    var name = encodeURIComponent(
      (arguments[1] && arguments[1].name) ? arguments[1].name : element.id);

    if (options.tree) {
      return Sortable.tree(element, arguments[1]).children.map( function (item) {
        return [name + Sortable._constructIndex(item) + "[id]=" +
                encodeURIComponent(item.id)].concat(item.children.map(arguments.callee));
      }).flatten().join('&');
    } else {
      return Sortable.sequence(element, arguments[1]).map( function(item) {
        return name + "[]=" + encodeURIComponent(item);
      }).join('&');
    }
  }
};

// Returns true if child is contained within element
Element.isParent = function(child, element) {
  if (!child.parentNode || child == element) return false;
  if (child.parentNode == element) return true;
  return Element.isParent(child.parentNode, element);
};

Element.findChildren = function(element, only, recursive, tagName) {
  if(!element.hasChildNodes()) return null;
  tagName = tagName.toUpperCase();
  if(only) only = [only].flatten();
  var elements = [];
  $A(element.childNodes).each( function(e) {
    if(e.tagName && e.tagName.toUpperCase()==tagName &&
      (!only || (Element.classNames(e).detect(function(v) { return only.include(v) }))))
        elements.push(e);
    if(recursive) {
      var grandchildren = Element.findChildren(e, only, recursive, tagName);
      if(grandchildren) elements.push(grandchildren);
    }
  });

  return (elements.length>0 ? elements.flatten() : []);
};

Element.offsetSize = function (element, type) {
  return element['offset' + ((type=='vertical' || type=='height') ? 'Height' : 'Width')];
};
/*
**
** File 'builder.js'
**
*/
// script.aculo.us builder.js v1.8.2, Tue Nov 18 18:30:58 +0100 2008

// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
//
// script.aculo.us is freely distributable under the terms of an MIT-style license.
// For details, see the script.aculo.us web site: http://script.aculo.us/

var Builder = {
  NODEMAP: {
    AREA: 'map',
    CAPTION: 'table',
    COL: 'table',
    COLGROUP: 'table',
    LEGEND: 'fieldset',
    OPTGROUP: 'select',
    OPTION: 'select',
    PARAM: 'object',
    TBODY: 'table',
    TD: 'table',
    TFOOT: 'table',
    TH: 'table',
    THEAD: 'table',
    TR: 'table'
  },
  // note: For Firefox < 1.5, OPTION and OPTGROUP tags are currently broken,
  //       due to a Firefox bug
  node: function(elementName) {
    elementName = elementName.toUpperCase();

    // try innerHTML approach
    var parentTag = this.NODEMAP[elementName] || 'div';
    var parentElement = document.createElement(parentTag);
    try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
      parentElement.innerHTML = "<" + elementName + "></" + elementName + ">";
    } catch(e) {}
    var element = parentElement.firstChild || null;

    // see if browser added wrapping tags
    if(element && (element.tagName.toUpperCase() != elementName))
      element = element.getElementsByTagName(elementName)[0];

    // fallback to createElement approach
    if(!element) element = document.createElement(elementName);

    // abort if nothing could be created
    if(!element) return;

    // attributes (or text)
    if(arguments[1])
      if(this._isStringOrNumber(arguments[1]) ||
        (arguments[1] instanceof Array) ||
        arguments[1].tagName) {
          this._children(element, arguments[1]);
        } else {
          var attrs = this._attributes(arguments[1]);
          if(attrs.length) {
            try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
              parentElement.innerHTML = "<" +elementName + " " +
                attrs + "></" + elementName + ">";
            } catch(e) {}
            element = parentElement.firstChild || null;
            // workaround firefox 1.0.X bug
            if(!element) {
              element = document.createElement(elementName);
              for(attr in arguments[1])
                element[attr == 'class' ? 'className' : attr] = arguments[1][attr];
            }
            if(element.tagName.toUpperCase() != elementName)
              element = parentElement.getElementsByTagName(elementName)[0];
          }
        }

    // text, or array of children
    if(arguments[2])
      this._children(element, arguments[2]);

     return $(element);
  },
  _text: function(text) {
     return document.createTextNode(text);
  },

  ATTR_MAP: {
    'className': 'class',
    'htmlFor': 'for'
  },

  _attributes: function(attributes) {
    var attrs = [];
    for(attribute in attributes)
      attrs.push((attribute in this.ATTR_MAP ? this.ATTR_MAP[attribute] : attribute) +
          '="' + attributes[attribute].toString().escapeHTML().gsub(/"/,'&quot;') + '"');
    return attrs.join(" ");
  },
  _children: function(element, children) {
    if(children.tagName) {
      element.appendChild(children);
      return;
    }
    if(typeof children=='object') { // array can hold nodes and text
      children.flatten().each( function(e) {
        if(typeof e=='object')
          element.appendChild(e);
        else
          if(Builder._isStringOrNumber(e))
            element.appendChild(Builder._text(e));
      });
    } else
      if(Builder._isStringOrNumber(children))
        element.appendChild(Builder._text(children));
  },
  _isStringOrNumber: function(param) {
    return(typeof param=='string' || typeof param=='number');
  },
  build: function(html) {
    var element = this.node('div');
    $(element).update(html.strip());
    return element.down();
  },
  dump: function(scope) {
    if(typeof scope != 'object' && typeof scope != 'function') scope = window; //global scope

    var tags = ("A ABBR ACRONYM ADDRESS APPLET AREA B BASE BASEFONT BDO BIG BLOCKQUOTE BODY " +
      "BR BUTTON CAPTION CENTER CITE CODE COL COLGROUP DD DEL DFN DIR DIV DL DT EM FIELDSET " +
      "FONT FORM FRAME FRAMESET H1 H2 H3 H4 H5 H6 HEAD HR HTML I IFRAME IMG INPUT INS ISINDEX "+
      "KBD LABEL LEGEND LI LINK MAP MENU META NOFRAMES NOSCRIPT OBJECT OL OPTGROUP OPTION P "+
      "PARAM PRE Q S SAMP SCRIPT SELECT SMALL SPAN STRIKE STRONG STYLE SUB SUP TABLE TBODY TD "+
      "TEXTAREA TFOOT TH THEAD TITLE TR TT U UL VAR").split(/\s+/);

    tags.each( function(tag){
      scope[tag] = function() {
        return Builder.node.apply(Builder, [tag].concat($A(arguments)));
      };
    });
  }
};
/*
**
** File 'cropper.uncompressed.js'
**
*/
/**
 * Image Cropper (v. 1.2.0 - 2006-10-30 )
 * Copyright (c) 2006 David Spurr (http://www.defusion.org.uk/)
 * 
 * The image cropper provides a way to draw a crop area on an image and capture
 * the coordinates of the drawn crop area.
 * 
 * Features include:
 * 		- Based on Prototype and Scriptaculous
 * 		- Image editing package styling, the crop area functions and looks 
 * 		  like those found in popular image editing software
 * 		- Dynamic inclusion of required styles
 * 		- Drag to draw areas
 * 		- Shift drag to draw/resize areas as squares
 * 		- Selection area can be moved 
 * 		- Seleciton area can be resized using resize handles
 * 		- Allows dimension ratio limited crop areas
 * 		- Allows minimum dimension crop areas
 * 		- Allows maximum dimesion crop areas
 * 		- If both min & max dimension options set to the same value for a single axis,then the cropper will not 
 * 		  display the resize handles as appropriate (when min & max dimensions are passed for both axes this
 * 		  results in a 'fixed size' crop area)
 * 		- Allows dynamic preview of resultant crop ( if minimum width & height are provided ), this is
 * 		  implemented as a subclass so can be excluded when not required
 * 		- Movement of selection area by arrow keys ( shift + arrow key will move selection area by
 * 		  10 pixels )
 *		- All operations stay within bounds of image
 * 		- All functionality & display compatible with most popular browsers supported by Prototype:
 * 			PC:	IE 7, 6 & 5.5, Firefox 1.5, Opera 8.5 (see known issues) & 9.0b
 * 			MAC: Camino 1.0, Firefox 1.5, Safari 2.0
 * 
 * Requires:
 * 		- Prototype v. 1.5.0_rc0 > (as packaged with Scriptaculous 1.6.1)
 * 		- Scriptaculous v. 1.6.1 > modules: builder, dragdrop 
 * 		
 * Known issues:
 * 		- Safari animated gifs, only one of each will animate, this seems to be a known Safari issue
 * 
 * 		- After drawing an area and then clicking to start a new drag in IE 5.5 the rendered height 
 *        appears as the last height until the user drags, this appears to be the related to the error 
 *        that the forceReRender() method fixes for IE 6, i.e. IE 5.5 is not redrawing the box properly.
 * 
 * 		- Lack of CSS opacity support in Opera before version 9 mean we disable those style rules, these 
 * 		  could be fixed by using PNGs with transparency if Opera 8.5 support is high priority for you
 * 
 * 		- Marching ants keep reloading in IE <6 (not tested in IE7), it is a known issue in IE and I have 
 *        found no viable workarounds that can be included in the release. If this really is an issue for you
 *        either try this post: http://mir.aculo.us/articles/2005/08/28/internet-explorer-and-ajax-image-caching-woes
 *        or uncomment the 'FIX MARCHING ANTS IN IE' rules in the CSS file
 *		
 *		- Styling & borders on image, any CSS styling applied directly to the image itself (floats, borders, padding, margin, etc.) will 
 *		  cause problems with the cropper. The use of a wrapper element to apply these styles to is recommended.
 * 
 * 		- overflow: auto or overflow: scroll on parent will cause cropper to burst out of parent in IE and Opera (maybe Mac browsers too)
 *		  I'm not sure why yet.
 * 
 * Usage:
 * 		See Cropper.Img & Cropper.ImgWithPreview for usage details
 * 
 * Changelog:
 * v1.2.0 - 2006-10-30
 * 		+ Added id to the preview image element using 'imgCrop_[originalImageID]'
 *      * #00001 - Fixed bug: Doesn't account for scroll offsets
 *      * #00009 - Fixed bug: Placing the cropper inside differently positioned elements causes incorrect co-ordinates and display
 *      * #00013 - Fixed bug: I-bar cursor appears on drag plane
 *      * #00014 - Fixed bug: If ID for image tag is not found in document script throws error
 *      * Fixed bug with drag start co-ordinates if wrapper element has moved in browser (e.g. dragged to a new position)
 *      * Fixed bug with drag start co-ordinates if image contained in a wrapper with scrolling - this may be buggy if image 
 * 		  has other ancestors with scrolling applied (except the body)
 *      * #00015 - Fixed bug: When cropper removed and then reapplied onEndCrop callback gets called multiple times, solution suggestion from Bill Smith
 *      * Various speed increases & code cleanup which meant improved performance in Mac - which allowed removal of different overlay methods for
 *        IE and all other browsers, which led to a fix for:
 * 		* #00010 - Fixed bug: Select area doesn't adhere to image size when image resized using img attributes
 *      - #00006 - Removed default behaviour of automatically setting a ratio when both min width & height passed, the ratioDimensions must be passed in
 * 		+ #00005 - Added ability to set maximum crop dimensions, if both min & max set as the same value then we'll get a fixed cropper size on the axes as appropriate
 *        and the resize handles will not be displayed as appropriate
 * 		* Switched keydown for keypress for moving select area with cursor keys (makes for nicer action) - doesn't appear to work in Safari
 * 
 * v1.1.3 - 2006-08-21
 * 		* Fixed wrong cursor on western handle in CSS
 * 		+ #00008 & #00003 - Added feature: Allow to set dimensions & position for cropper on load
 *      * #00002 - Fixed bug: Pressing 'remove cropper' twice removes image in IE
 * 
 * v1.1.2 - 2006-06-09
 * 		* Fixed bugs with ratios when GCD is low (patch submitted by Andy Skelton)
 * 
 * v1.1.1 - 2006-06-03
 * 		* Fixed bug with rendering issues fix in IE 5.5
 * 		* Fixed bug with endCrop callback issues once cropper had been removed & reset in IE
 * 
 * v1.1.0 - 2006-06-02
 * 		* Fixed bug with IE constantly trying to reload select area background image
 * 		* Applied more robust fix to Safari & IE rendering issues
 * 		+ Added method to reset parameters - useful for when dynamically changing img cropper attached to
 * 		+ Added method to remove cropper from image
 * 
 * v1.0.0 - 2006-05-18 
 * 		+ Initial verison
 * 
 * 
 * Copyright (c) 2006, David Spurr (http://www.defusion.org.uk/)
 * All rights reserved.
 * 
 * 
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 * 
 *     * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
 *     * Neither the name of the David Spurr nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * http://www.opensource.org/licenses/bsd-license.php
 * 
 * See scriptaculous.js for full scriptaculous licence
 */
 
/**
 * Extend the Draggable class to allow us to pass the rendering
 * down to the Cropper object.
 */
var CropDraggable = Class.create();

Object.extend( Object.extend( CropDraggable.prototype, Draggable.prototype), {
	
	initialize: function(element) {
		this.options = Object.extend(
			{
				/**
				 * The draw method to defer drawing to
				 */
				drawMethod: function() {}
			}, 
			arguments[1] || {}
		);

		this.element = $(element);

		this.handle = this.element;

		this.delta    = this.currentDelta();
		this.dragging = false;   

		this.eventMouseDown = this.initDrag.bindAsEventListener(this);
		Event.observe(this.handle, "mousedown", this.eventMouseDown);

		Draggables.register(this);
	},
	
	/**
	 * Defers the drawing of the draggable to the supplied method
	 */
	draw: function(point) {
		var pos = Position.cumulativeOffset(this.element);
		var d = this.currentDelta();
		pos[0] -= d[0]; 
		pos[1] -= d[1];
				
		var p = [0,1].map(function(i) { 
			return (point[i]-pos[i]-this.offset[i]) 
		}.bind(this));
				
		this.options.drawMethod( p );
	}
	
});


/**
 * The Cropper object, this will attach itself to the provided image by wrapping it with 
 * the generated xHTML structure required by the cropper.
 * 
 * Usage:
 * 	@param obj Image element to attach to
 * 	@param obj Optional options:
 * 		- ratioDim obj 
 * 			The pixel dimensions to apply as a restrictive ratio, with properties x & y
 * 
 * 		- minWidth int 
 * 			The minimum width for the select area in pixels
 * 
 * 		- minHeight	int 
 * 			The mimimum height for the select area in pixels
 * 
 * 		- maxWidth int
 * 			The maximum width for the select areas in pixels (if both minWidth & maxWidth set to same the width of the cropper will be fixed)
 * 
 * 		- maxHeight int
 *			The maximum height for the select areas in pixels (if both minHeight & maxHeight set to same the height of the cropper will be fixed)
 * 
 * 		- displayOnInit int 
 * 			Whether to display the select area on initialisation, only used when providing minimum width & height or ratio
 * 
 * 		- onEndCrop func
 * 			The callback function to provide the crop details to on end of a crop (see below)
 * 
 * 		- captureKeys boolean
 * 			Whether to capture the keys for moving the select area, as these can cause some problems at the moment
 * 
 * 		- onloadCoords obj
 * 			A coordinates object with properties x1, y1, x2 & y2; for the coordinates of the select area to display onload
 * 	
 *----------------------------------------------
 * 
 * The callback function provided via the onEndCrop option should accept the following parameters:
 * 		- coords obj
 * 			The coordinates object with properties x1, y1, x2 & y2; for the coordinates of the select area
 * 
 * 		- dimensions obj
 * 			The dimensions object with properites width & height; for the dimensions of the select area
 * 		
 *
 * 		Example:
 * 			function onEndCrop( coords, dimensions ) {
 *				$( 'x1' ).value 	= coords.x1;
 *				$( 'y1' ).value 	= coords.y1;
 *				$( 'x2' ).value 	= coords.x2;
 *				$( 'y2' ).value 	= coords.y2;
 *				$( 'width' ).value 	= dimensions.width;
 *				$( 'height' ).value	= dimensions.height;
 *			}
 * 
 */
var Cropper = {};
Cropper.Img = Class.create();
Cropper.Img.prototype = {
	
	/**
	 * Initialises the class
	 * 
	 * @access public
	 * @param obj Image element to attach to
	 * @param obj Options
	 * @return void
	 */
	initialize: function(element, options) {
		this.options = Object.extend(
			{
				/**
				 * @var obj
				 * The pixel dimensions to apply as a restrictive ratio
				 */
				ratioDim: { x: 0, y: 0 },
				/**
				 * @var int
				 * The minimum pixel width, also used as restrictive ratio if min height passed too
				 */
				minWidth:		0,
				/**
				 * @var int
				 * The minimum pixel height, also used as restrictive ratio if min width passed too
				 */
				minHeight:		0,
				/**
				 * @var boolean
				 * Whether to display the select area on initialisation, only used when providing minimum width & height or ratio
				 */
				displayOnInit:	false,
				/**
				 * @var function
				 * The call back function to pass the final values to
				 */
				onEndCrop: Prototype.emptyFunction,
				/**
				 * @var boolean
				 * Whether to capture key presses or not
				 */
				captureKeys: true,
				/**
				 * @var obj Coordinate object x1, y1, x2, y2
				 * The coordinates to optionally display the select area at onload
				 */
				onloadCoords: null,
				/**
				 * @var int
				 * The maximum width for the select areas in pixels (if both minWidth & maxWidth set to same the width of the cropper will be fixed)
				 */
				maxWidth: 0,
				/**
				 * @var int
				 * The maximum height for the select areas in pixels (if both minHeight & maxHeight set to same the height of the cropper will be fixed)
				 */
				maxHeight: 0
			}, 
			options || {}
		);				
		/**
		 * @var obj
		 * The img node to attach to
		 */
		this.img			= $( element );
		/**
		 * @var obj
		 * The x & y coordinates of the click point
		 */
		this.clickCoords	= { x: 0, y: 0 };
		/**
		 * @var boolean
		 * Whether the user is dragging
		 */
		this.dragging		= false;
		/**
		 * @var boolean
		 * Whether the user is resizing
		 */
		this.resizing		= false;
		/**
		 * @var boolean
		 * Whether the user is on a webKit browser
		 */
		this.isWebKit 		= /Konqueror|Safari|KHTML/.test( navigator.userAgent );
		/**
		 * @var boolean
		 * Whether the user is on IE
		 */
		this.isIE 			= /MSIE/.test( navigator.userAgent );
		/**
		 * @var boolean
		 * Whether the user is on Opera below version 9
		 */
		this.isOpera8		= /Opera\s[1-8]/.test( navigator.userAgent );
		/**
		 * @var int
		 * The x ratio 
		 */
		this.ratioX			= 0;
		/**
		 * @var int
		 * The y ratio
		 */
		this.ratioY			= 0;
		/**
		 * @var boolean
		 * Whether we've attached sucessfully
		 */
		this.attached		= false;
		/**
		 * @var boolean
		 * Whether we've got a fixed width (if minWidth EQ or GT maxWidth then we have a fixed width
		 * in the case of minWidth > maxWidth maxWidth wins as the fixed width)
		 */
		this.fixedWidth		= ( this.options.maxWidth > 0 && ( this.options.minWidth >= this.options.maxWidth ) );
		/**
		 * @var boolean
		 * Whether we've got a fixed height (if minHeight EQ or GT maxHeight then we have a fixed height
		 * in the case of minHeight > maxHeight maxHeight wins as the fixed height)
		 */
		this.fixedHeight	= ( this.options.maxHeight > 0 && ( this.options.minHeight >= this.options.maxHeight ) );
		
		// quit if the image element doesn't exist
		if( typeof this.img == 'undefined' ) return;
				
		// include the stylesheet		
		$A( document.getElementsByTagName( 'script' ) ).each( 
			function(s) {
				if( s.src.match( /cropper\.js/ ) ) {
					var path 	= s.src.replace( /cropper\.js(.*)?/, '' );
					// '<link rel="stylesheet" type="text/css" href="' + path + 'cropper.css" media="screen" />';
					var style 		= document.createElement( 'link' );
					style.rel 		= 'stylesheet';
					style.type 		= 'text/css';
					style.href 		= path + 'cropper.css';
					style.media 	= 'screen';
					document.getElementsByTagName( 'head' )[0].appendChild( style );
				}
	    	}
	    );   
	
		// calculate the ratio when neccessary
		if( this.options.ratioDim.x > 0 && this.options.ratioDim.y > 0 ) {
			var gcd = this.getGCD( this.options.ratioDim.x, this.options.ratioDim.y );
			this.ratioX = this.options.ratioDim.x / gcd;
			this.ratioY = this.options.ratioDim.y / gcd;
			// dump( 'RATIO : ' + this.ratioX + ':' + this.ratioY + '\n' );
		}
							
		// initialise sub classes
		this.subInitialize();

		// only load the event observers etc. once the image is loaded
		// this is done after the subInitialize() call just in case the sub class does anything
		// that will affect the result of the call to onLoad()
		if( this.img.complete || this.isWebKit ) this.onLoad(); // for some reason Safari seems to support img.complete but returns 'undefined' on the this.img object
		else Event.observe( this.img, 'load', this.onLoad.bindAsEventListener( this) );		
	},
	
	/**
	 * The Euclidean algorithm used to find the greatest common divisor
	 * 
	 * @acces private
	 * @param int Value 1
	 * @param int Value 2
	 * @return int
	 */
	getGCD : function( a , b ) {
		if( b == 0 ) return a;
		return this.getGCD(b, a % b );
	},
	
	/**
	 * Attaches the cropper to the image once it has loaded
	 * 
	 * @access private
	 * @return void
	 */
	onLoad: function( ) {
		/*
		 * Build the container and all related elements, will result in the following
		 *
		 * <div class="imgCrop_wrap">
		 * 		<img ... this.img ... />
		 * 		<div class="imgCrop_dragArea">
		 * 			<!-- the inner spans are only required for IE to stop it making the divs 1px high/wide -->
		 * 			<div class="imgCrop_overlay imageCrop_north"><span></span></div>
		 * 			<div class="imgCrop_overlay imageCrop_east"><span></span></div>
		 * 			<div class="imgCrop_overlay imageCrop_south"><span></span></div>
		 * 			<div class="imgCrop_overlay imageCrop_west"><span></span></div>
		 * 			<div class="imgCrop_selArea">
		 * 				<!-- marquees -->
		 * 				<!-- the inner spans are only required for IE to stop it making the divs 1px high/wide -->
		 * 				<div class="imgCrop_marqueeHoriz imgCrop_marqueeNorth"><span></span></div>
		 * 				<div class="imgCrop_marqueeVert imgCrop_marqueeEast"><span></span></div>
		 * 				<div class="imgCrop_marqueeHoriz imgCrop_marqueeSouth"><span></span></div>
		 * 				<div class="imgCrop_marqueeVert imgCrop_marqueeWest"><span></span></div>			
		 * 				<!-- handles -->
		 * 				<div class="imgCrop_handle imgCrop_handleN"></div>
		 * 				<div class="imgCrop_handle imgCrop_handleNE"></div>
		 * 				<div class="imgCrop_handle imgCrop_handleE"></div>
		 * 				<div class="imgCrop_handle imgCrop_handleSE"></div>
		 * 				<div class="imgCrop_handle imgCrop_handleS"></div>
		 * 				<div class="imgCrop_handle imgCrop_handleSW"></div>
		 * 				<div class="imgCrop_handle imgCrop_handleW"></div>
		 * 				<div class="imgCrop_handle imgCrop_handleNW"></div>
		 * 				<div class="imgCrop_clickArea"></div>
		 * 			</div>	
		 * 			<div class="imgCrop_clickArea"></div>
		 * 		</div>	
		 * </div>
		 */
		var cNamePrefix = 'imgCrop_';
		
		// get the point to insert the container
		var insertPoint = this.img.parentNode;
		
		// apply an extra class to the wrapper to fix Opera below version 9
		var fixOperaClass = '';
		if( this.isOpera8 ) fixOperaClass = ' opera8';
		this.imgWrap = Builder.node( 'div', { 'class': cNamePrefix + 'wrap' + fixOperaClass } );
		
		this.north		= Builder.node( 'div', { 'class': cNamePrefix + 'overlay ' + cNamePrefix + 'north' }, [Builder.node( 'span' )] );
		this.east		= Builder.node( 'div', { 'class': cNamePrefix + 'overlay ' + cNamePrefix + 'east' } , [Builder.node( 'span' )] );
		this.south		= Builder.node( 'div', { 'class': cNamePrefix + 'overlay ' + cNamePrefix + 'south' }, [Builder.node( 'span' )] );
		this.west		= Builder.node( 'div', { 'class': cNamePrefix + 'overlay ' + cNamePrefix + 'west' } , [Builder.node( 'span' )] );
		
		var overlays	= [ this.north, this.east, this.south, this.west ];

		this.dragArea	= Builder.node( 'div', { 'class': cNamePrefix + 'dragArea' }, overlays );
						
		this.handleN	= Builder.node( 'div', { 'class': cNamePrefix + 'handle ' + cNamePrefix + 'handleN' } );
		this.handleNE	= Builder.node( 'div', { 'class': cNamePrefix + 'handle ' + cNamePrefix + 'handleNE' } );
		this.handleE	= Builder.node( 'div', { 'class': cNamePrefix + 'handle ' + cNamePrefix + 'handleE' } );
		this.handleSE	= Builder.node( 'div', { 'class': cNamePrefix + 'handle ' + cNamePrefix + 'handleSE' } );
		this.handleS	= Builder.node( 'div', { 'class': cNamePrefix + 'handle ' + cNamePrefix + 'handleS' } );
		this.handleSW	= Builder.node( 'div', { 'class': cNamePrefix + 'handle ' + cNamePrefix + 'handleSW' } );
		this.handleW	= Builder.node( 'div', { 'class': cNamePrefix + 'handle ' + cNamePrefix + 'handleW' } );
		this.handleNW	= Builder.node( 'div', { 'class': cNamePrefix + 'handle ' + cNamePrefix + 'handleNW' } );
				
		this.selArea	= Builder.node( 'div', { 'class': cNamePrefix + 'selArea' },
			[
				Builder.node( 'div', { 'class': cNamePrefix + 'marqueeHoriz ' + cNamePrefix + 'marqueeNorth' }, [Builder.node( 'span' )] ),
				Builder.node( 'div', { 'class': cNamePrefix + 'marqueeVert ' + cNamePrefix + 'marqueeEast' }  , [Builder.node( 'span' )] ),
				Builder.node( 'div', { 'class': cNamePrefix + 'marqueeHoriz ' + cNamePrefix + 'marqueeSouth' }, [Builder.node( 'span' )] ),
				Builder.node( 'div', { 'class': cNamePrefix + 'marqueeVert ' + cNamePrefix + 'marqueeWest' }  , [Builder.node( 'span' )] ),
				this.handleN,
				this.handleNE,
				this.handleE,
				this.handleSE,
				this.handleS,
				this.handleSW,
				this.handleW,
				this.handleNW,
				Builder.node( 'div', { 'class': cNamePrefix + 'clickArea' } )
			]
		);
				
		this.imgWrap.appendChild( this.img );
		this.imgWrap.appendChild( this.dragArea );
		this.dragArea.appendChild( this.selArea );
		this.dragArea.appendChild( Builder.node( 'div', { 'class': cNamePrefix + 'clickArea' } ) );

		insertPoint.appendChild( this.imgWrap );

		// add event observers
		this.startDragBind 	= this.startDrag.bindAsEventListener( this );
		Event.observe( this.dragArea, 'mousedown', this.startDragBind );
		
		this.onDragBind 	= this.onDrag.bindAsEventListener( this );
		Event.observe( document, 'mousemove', this.onDragBind );
		
		this.endCropBind 	= this.endCrop.bindAsEventListener( this );
		Event.observe( document, 'mouseup', this.endCropBind );
		
		this.resizeBind		= this.startResize.bindAsEventListener( this );
		this.handles = [ this.handleN, this.handleNE, this.handleE, this.handleSE, this.handleS, this.handleSW, this.handleW, this.handleNW ];
		this.registerHandles( true );
		
		if( this.options.captureKeys ) {
			this.keysBind = this.handleKeys.bindAsEventListener( this );
			Event.observe( document, 'keypress', this.keysBind );
		}

		// attach the dragable to the select area
		new CropDraggable( this.selArea, { drawMethod: this.moveArea.bindAsEventListener( this ) } );
		
		this.setParams();
	},
	
	/**
	 * Manages adding or removing the handle event handler and hiding or displaying them as appropriate
	 * 
	 * @access private
	 * @param boolean registration true = add, false = remove
	 * @return void
	 */
	registerHandles: function( registration ) {	
		for( var i = 0; i < this.handles.length; i++ ) {
			var handle = $( this.handles[i] );
			
			if( registration ) {
				var hideHandle	= false;	// whether to hide the handle
				
				// disable handles asappropriate if we've got fixed dimensions
				// if both dimensions are fixed we don't need to do much
				if( this.fixedWidth && this.fixedHeight ) hideHandle = true;
				else if( this.fixedWidth || this.fixedHeight ) {
					// if one of the dimensions is fixed then just hide those handles
					var isCornerHandle	= handle.className.match( /([S|N][E|W])$/ )
					var isWidthHandle 	= handle.className.match( /(E|W)$/ );
					var isHeightHandle 	= handle.className.match( /(N|S)$/ );
					if( isCornerHandle ) hideHandle = true;
					else if( this.fixedWidth && isWidthHandle ) hideHandle = true;
					else if( this.fixedHeight && isHeightHandle ) hideHandle = true;
				}
				if( hideHandle ) handle.hide();
				else Event.observe( handle, 'mousedown', this.resizeBind );
			} else {
				handle.show();
				Event.stopObserving( handle, 'mousedown', this.resizeBind );
			}
		}
	},
		
	/**
	 * Sets up all the cropper parameters, this can be used to reset the cropper when dynamically
	 * changing the images
	 * 
	 * @access private
	 * @return void
	 */
	setParams: function() {
		/**
		 * @var int
		 * The image width
		 */
		this.imgW = this.img.width;
		/**
		 * @var int
		 * The image height
		 */
		this.imgH = this.img.height;			

		$( this.north ).setStyle( { height: 0 } );
		$( this.east ).setStyle( { width: 0, height: 0 } );
		$( this.south ).setStyle( { height: 0 } );
		$( this.west ).setStyle( { width: 0, height: 0 } );
		
		// resize the container to fit the image
		$( this.imgWrap ).setStyle( { 'width': this.imgW + 'px', 'height': this.imgH + 'px' } );
		
		// hide the select area
		$( this.selArea ).hide();
						
		// setup the starting position of the select area
		var startCoords = { x1: 0, y1: 0, x2: 0, y2: 0 };
		var validCoordsSet = false;
		
		// display the select area 
		if( this.options.onloadCoords != null ) {
			// if we've being given some coordinates to 
			startCoords = this.cloneCoords( this.options.onloadCoords );
			validCoordsSet = true;
		} else if( this.options.ratioDim.x > 0 && this.options.ratioDim.y > 0 ) {
			// if there is a ratio limit applied and the then set it to initial ratio
			startCoords.x1 = Math.ceil( ( this.imgW - this.options.ratioDim.x ) / 2 );
			startCoords.y1 = Math.ceil( ( this.imgH - this.options.ratioDim.y ) / 2 );
			startCoords.x2 = startCoords.x1 + this.options.ratioDim.x;
			startCoords.y2 = startCoords.y1 + this.options.ratioDim.y;
			validCoordsSet = true;
		}
		
		this.setAreaCoords( startCoords, false, false, 1 );
		
		if( this.options.displayOnInit && validCoordsSet ) {
			this.selArea.show();
			this.drawArea();
			this.endCrop();
		}
		
		this.attached = true;
	},
	
	/**
	 * Removes the cropper
	 * 
	 * @access public
	 * @return void
	 */
	remove: function() {
		if( this.attached ) {
			this.attached = false;
			
			// remove the elements we inserted
			this.imgWrap.parentNode.insertBefore( this.img, this.imgWrap );
			this.imgWrap.parentNode.removeChild( this.imgWrap );
			
			// remove the event observers
			Event.stopObserving( this.dragArea, 'mousedown', this.startDragBind );
			Event.stopObserving( document, 'mousemove', this.onDragBind );		
			Event.stopObserving( document, 'mouseup', this.endCropBind );
			this.registerHandles( false );
			if( this.options.captureKeys ) Event.stopObserving( document, 'keypress', this.keysBind );
		}
	},
	
	/**
	 * Resets the cropper, can be used either after being removed or any time you wish
	 * 
	 * @access public
	 * @return void
	 */
	reset: function() {
		if( !this.attached ) this.onLoad();
		else this.setParams();
		this.endCrop();
	},
	
	/**
	 * Handles the key functionality, currently just using arrow keys to move, if the user
	 * presses shift then the area will move by 10 pixels
	 */
	handleKeys: function( e ) {
		var dir = { x: 0, y: 0 }; // direction to move it in & the amount in pixels
		if( !this.dragging ) {
			
			// catch the arrow keys
			switch( e.keyCode ) {
				case( 37 ) : // left
					dir.x = -1;
					break;
				case( 38 ) : // up
					dir.y = -1;
					break;
				case( 39 ) : // right
					dir.x = 1;
					break
				case( 40 ) : // down
					dir.y = 1;
					break;
			}
			
			if( dir.x != 0 || dir.y != 0 ) {
				// if shift is pressed then move by 10 pixels
				if( e.shiftKey ) {
					dir.x *= 10;
					dir.y *= 10;
				}
				
				this.moveArea( [ this.areaCoords.x1 + dir.x, this.areaCoords.y1 + dir.y ] );
				Event.stop( e ); 
			}
		}
	},
	
	/**
	 * Calculates the width from the areaCoords
	 * 
	 * @access private
	 * @return int
	 */
	calcW: function() {
		return (this.areaCoords.x2 - this.areaCoords.x1)
	},
	
	/**
	 * Calculates the height from the areaCoords
	 * 
	 * @access private
	 * @return int
	 */
	calcH: function() {
		return (this.areaCoords.y2 - this.areaCoords.y1)
	},
	
	/**
	 * Moves the select area to the supplied point (assumes the point is x1 & y1 of the select area)
	 * 
	 * @access public
	 * @param array Point for x1 & y1 to move select area to
	 * @return void
	 */
	moveArea: function( point ) {
		// dump( 'moveArea        : ' + point[0] + ',' + point[1] + ',' + ( point[0] + ( this.areaCoords.x2 - this.areaCoords.x1 ) ) + ',' + ( point[1] + ( this.areaCoords.y2 - this.areaCoords.y1 ) ) + '\n' );
		this.setAreaCoords( 
			{
				x1: point[0], 
				y1: point[1],
				x2: point[0] + this.calcW(),
				y2: point[1] + this.calcH()
			},
			true,
			false
		);
		this.drawArea();
	},

	/**
	 * Clones a co-ordinates object, stops problems with handling them by reference
	 * 
	 * @access private
	 * @param obj Coordinate object x1, y1, x2, y2
	 * @return obj Coordinate object x1, y1, x2, y2
	 */
	cloneCoords: function( coords ) {
		return { x1: coords.x1, y1: coords.y1, x2: coords.x2, y2: coords.y2 };
	},

	/**
	 * Sets the select coords to those provided but ensures they don't go
	 * outside the bounding box
	 * 
	 * @access private
	 * @param obj Coordinates x1, y1, x2, y2
	 * @param boolean Whether this is a move
	 * @param boolean Whether to apply squaring
	 * @param obj Direction of mouse along both axis x, y ( -1 = negative, 1 = positive ) only required when moving etc.
	 * @param string The current resize handle || null
	 * @return void
	 */
	setAreaCoords: function( coords, moving, square, direction, resizeHandle ) {
		// dump( 'setAreaCoords (in) : ' + coords.x1 + ',' + coords.y1 + ',' + coords.x2 + ',' + coords.y2 );
		if( moving ) {
			// if moving
			var targW = coords.x2 - coords.x1;
			var targH = coords.y2 - coords.y1;
			
			// ensure we're within the bounds
			if( coords.x1 < 0 ) {
				coords.x1 = 0;
				coords.x2 = targW;
			}
			if( coords.y1 < 0 ) {
				coords.y1 = 0;
				coords.y2 = targH;
			}
			if( coords.x2 > this.imgW ) {
				coords.x2 = this.imgW;
				coords.x1 = this.imgW - targW;
			}
			if( coords.y2 > this.imgH ) {
				coords.y2 = this.imgH;
				coords.y1 = this.imgH - targH;
			}			
		} else {
			// ensure we're within the bounds
			if( coords.x1 < 0 ) coords.x1 = 0;
			if( coords.y1 < 0 ) coords.y1 = 0;
			if( coords.x2 > this.imgW ) coords.x2 = this.imgW;
			if( coords.y2 > this.imgH ) coords.y2 = this.imgH;
			
			// This is passed as null in onload
			if( direction != null ) {
								
				// apply the ratio or squaring where appropriate
				if( this.ratioX > 0 ) this.applyRatio( coords, { x: this.ratioX, y: this.ratioY }, direction, resizeHandle );
				else if( square ) this.applyRatio( coords, { x: 1, y: 1 }, direction, resizeHandle );
										
				var mins = [ this.options.minWidth, this.options.minHeight ]; // minimum dimensions [x,y]			
				var maxs = [ this.options.maxWidth, this.options.maxHeight ]; // maximum dimensions [x,y]
		
				// apply dimensions where appropriate
				if( mins[0] > 0 || mins[1] > 0 || maxs[0] > 0 || maxs[1] > 0) {
				
					var coordsTransX 	= { a1: coords.x1, a2: coords.x2 };
					var coordsTransY 	= { a1: coords.y1, a2: coords.y2 };
					var boundsX			= { min: 0, max: this.imgW };
					var boundsY			= { min: 0, max: this.imgH };
					
					// handle squaring properly on single axis minimum dimensions
					if( (mins[0] != 0 || mins[1] != 0) && square ) {
						if( mins[0] > 0 ) mins[1] = mins[0];
						else if( mins[1] > 0 ) mins[0] = mins[1];
					}
					
					if( (maxs[0] != 0 || maxs[0] != 0) && square ) {
						// if we have a max x value & it is less than the max y value then we set the y max to the max x (so we don't go over the minimum maximum of one of the axes - if that makes sense)
						if( maxs[0] > 0 && maxs[0] <= maxs[1] ) maxs[1] = maxs[0];
						else if( maxs[1] > 0 && maxs[1] <= maxs[0] ) maxs[0] = maxs[1];
					}
					
					if( mins[0] > 0 ) this.applyDimRestriction( coordsTransX, mins[0], direction.x, boundsX, 'min' );
					if( mins[1] > 1 ) this.applyDimRestriction( coordsTransY, mins[1], direction.y, boundsY, 'min' );
					
					if( maxs[0] > 0 ) this.applyDimRestriction( coordsTransX, maxs[0], direction.x, boundsX, 'max' );
					if( maxs[1] > 1 ) this.applyDimRestriction( coordsTransY, maxs[1], direction.y, boundsY, 'max' );
					
					coords = { x1: coordsTransX.a1, y1: coordsTransY.a1, x2: coordsTransX.a2, y2: coordsTransY.a2 };
				}
				
			}
		}
		
		// dump( 'setAreaCoords (out) : ' + coords.x1 + ',' + coords.y1 + ',' + coords.x2 + ',' + coords.y2 + '\n' );
		this.areaCoords = coords;
	},
	
	/**
	 * Applies the supplied dimension restriction to the supplied coordinates along a single axis
	 * 
	 * @access private
	 * @param obj Single axis coordinates, a1, a2 (e.g. for the x axis a1 = x1 & a2 = x2)
	 * @param int The restriction value
	 * @param int The direction ( -1 = negative, 1 = positive )
	 * @param obj The bounds of the image ( for this axis )
	 * @param string The dimension restriction type ( 'min' | 'max' )
	 * @return void
	 */
	applyDimRestriction: function( coords, val, direction, bounds, type ) {
		var check;
		if( type == 'min' ) check = ( ( coords.a2 - coords.a1 ) < val );
		else check = ( ( coords.a2 - coords.a1 ) > val );
		if( check ) {
			if( direction == 1 ) coords.a2 = coords.a1 + val;
			else coords.a1 = coords.a2 - val;
			
			// make sure we're still in the bounds (not too pretty for the user, but needed)
			if( coords.a1 < bounds.min ) {
				coords.a1 = bounds.min;
				coords.a2 = val;
			} else if( coords.a2 > bounds.max ) {
				coords.a1 = bounds.max - val;
				coords.a2 = bounds.max;
			}
		}
	},
		
	/**
	 * Applies the supplied ratio to the supplied coordinates
	 * 
	 * @access private
	 * @param obj Coordinates, x1, y1, x2, y2
	 * @param obj Ratio, x, y
	 * @param obj Direction of mouse, x & y : -1 == negative 1 == positive
	 * @param string The current resize handle || null
	 * @return void
	 */
	applyRatio : function( coords, ratio, direction, resizeHandle ) {
		// dump( 'direction.y : ' + direction.y + '\n');
		var newCoords;
		if( resizeHandle == 'N' || resizeHandle == 'S' ) {
			// dump( 'north south \n');
			// if moving on either the lone north & south handles apply the ratio on the y axis
			newCoords = this.applyRatioToAxis( 
				{ a1: coords.y1, b1: coords.x1, a2: coords.y2, b2: coords.x2 },
				{ a: ratio.y, b: ratio.x },
				{ a: direction.y, b: direction.x },
				{ min: 0, max: this.imgW }
			);
			coords.x1 = newCoords.b1;
			coords.y1 = newCoords.a1;
			coords.x2 = newCoords.b2;
			coords.y2 = newCoords.a2;
		} else {
			// otherwise deal with it as if we're applying the ratio on the x axis
			newCoords = this.applyRatioToAxis( 
				{ a1: coords.x1, b1: coords.y1, a2: coords.x2, b2: coords.y2 },
				{ a: ratio.x, b: ratio.y },
				{ a: direction.x, b: direction.y },
				{ min: 0, max: this.imgH }
			);
			coords.x1 = newCoords.a1;
			coords.y1 = newCoords.b1;
			coords.x2 = newCoords.a2;
			coords.y2 = newCoords.b2;
		}
		
	},
	
	/**
	 * Applies the provided ratio to the provided coordinates based on provided direction & bounds,
	 * use to encapsulate functionality to make it easy to apply to either axis. This is probably
	 * quite hard to visualise so see the x axis example within applyRatio()
	 * 
	 * Example in parameter details & comments is for requesting applying ratio to x axis.
	 * 
	 * @access private
	 * @param obj Coords object (a1, b1, a2, b2) where a = x & b = y in example
	 * @param obj Ratio object (a, b) where a = x & b = y in example
	 * @param obj Direction object (a, b) where a = x & b = y in example
	 * @param obj Bounds (min, max)
	 * @return obj Coords object (a1, b1, a2, b2) where a = x & b = y in example
	 */
	applyRatioToAxis: function( coords, ratio, direction, bounds ) {
		var newCoords = Object.extend( coords, {} );
		var calcDimA = newCoords.a2 - newCoords.a1;			// calculate dimension a (e.g. width)
		var targDimB = Math.floor( calcDimA * ratio.b / ratio.a );	// the target dimension b (e.g. height)
		var targB;											// to hold target b (e.g. y value)
		var targDimA;                                		// to hold target dimension a (e.g. width)
		var calcDimB = null;								// to hold calculated dimension b (e.g. height)
		
		// dump( 'newCoords[0]: ' + newCoords.a1 + ',' + newCoords.b1 + ','+ newCoords.a2 + ',' + newCoords.b2 + '\n');
				
		if( direction.b == 1 ) {							// if travelling in a positive direction
			// make sure we're not going out of bounds
			targB = newCoords.b1 + targDimB;
			if( targB > bounds.max ) {
				targB = bounds.max;
				calcDimB = targB - newCoords.b1;			// calcuate dimension b (e.g. height)
			}
			
			newCoords.b2 = targB;
		} else {											// if travelling in a negative direction
			// make sure we're not going out of bounds
			targB = newCoords.b2 - targDimB;
			if( targB < bounds.min ) {
				targB = bounds.min;
				calcDimB = targB + newCoords.b2;			// calcuate dimension b (e.g. height)
			}
			newCoords.b1 = targB;
		}
		
		// dump( 'newCoords[1]: ' + newCoords.a1 + ',' + newCoords.b1 + ','+ newCoords.a2 + ',' + newCoords.b2 + '\n');
			
		// apply the calculated dimensions
		if( calcDimB != null ) {
			targDimA = Math.floor( calcDimB * ratio.a / ratio.b );
			
			if( direction.a == 1 ) newCoords.a2 = newCoords.a1 + targDimA;
			else newCoords.a1 = newCoords.a1 = newCoords.a2 - targDimA;
		}
		
		// dump( 'newCoords[2]: ' + newCoords.a1 + ',' + newCoords.b1 + ','+ newCoords.a2 + ',' + newCoords.b2 + '\n');
			
		return newCoords;
	},
	
	/**
	 * Draws the select area
	 * 
	 * @access private
	 * @return void
	 */
	drawArea: function( ) {	
		/*
		 * NOTE: I'm not using the Element.setStyle() shortcut as they make it 
		 * quite sluggish on Mac based browsers
		 */
		// dump( 'drawArea        : ' + this.areaCoords.x1 + ',' + this.areaCoords.y1 + ',' + this.areaCoords.x2 + ',' + this.areaCoords.y2 + '\n' );
		var areaWidth     = this.calcW();
		var areaHeight    = this.calcH();
		
		/*
		 * Calculate all the style strings before we use them, allows reuse & produces quicker
		 * rendering (especially noticable in Mac based browsers)
		 */
		var px = 'px';
		var params = [
			this.areaCoords.x1 + px, 	// the left of the selArea
			this.areaCoords.y1 + px,		// the top of the selArea
			areaWidth + px,					// width of the selArea
			areaHeight + px,					// height of the selArea
			this.areaCoords.x2 + px,		// bottom of the selArea
			this.areaCoords.y2 + px,		// right of the selArea
			(this.img.width - this.areaCoords.x2) + px,	// right edge of selArea
			(this.img.height - this.areaCoords.y2) + px	// bottom edge of selArea
		];
				
		// do the select area
		var areaStyle				= this.selArea.style;
		areaStyle.left				= params[0];
		areaStyle.top				= params[1];
		areaStyle.width				= params[2];
		areaStyle.height			= params[3];
			  	
		// position the north, east, south & west handles
		var horizHandlePos = Math.ceil( (areaWidth - 6) / 2 ) + px;
		var vertHandlePos = Math.ceil( (areaHeight - 6) / 2 ) + px;
		
		this.handleN.style.left 	= horizHandlePos;
		this.handleE.style.top 		= vertHandlePos;
		this.handleS.style.left 	= horizHandlePos;
		this.handleW.style.top		= vertHandlePos;
		
		// draw the four overlays
		this.north.style.height 	= params[1];
		
		var eastStyle 				= this.east.style;
		eastStyle.top				= params[1];
		eastStyle.height			= params[3];
		eastStyle.left				= params[4];
	    eastStyle.width				= params[6];
	   
	   	var southStyle 				= this.south.style;
	   	southStyle.top				= params[5];
	   	southStyle.height			= params[7];
	   
	    var westStyle       		= this.west.style;
	    westStyle.top				= params[1];
	    westStyle.height			= params[3];
	   	westStyle.width				= params[0];
	   	
		// call the draw method on sub classes
		this.subDrawArea();
		
		this.forceReRender();
	},
	
	/**
	 * Force the re-rendering of the selArea element which fixes rendering issues in Safari 
	 * & IE PC, especially evident when re-sizing perfectly vertical using any of the south handles
	 * 
	 * @access private
	 * @return void
	 */
	forceReRender: function() {
		if( this.isIE || this.isWebKit) {
			var n = document.createTextNode(' ');
			var d,el,fixEL,i;
		
			if( this.isIE ) fixEl = this.selArea;
			else if( this.isWebKit ) {
				fixEl = document.getElementsByClassName( 'imgCrop_marqueeSouth', this.imgWrap )[0];
				/* we have to be a bit more forceful for Safari, otherwise the the marquee &
				 * the south handles still don't move
				 */ 
				d = Builder.node( 'div', '' );
				d.style.visibility = 'hidden';
				
				var classList = ['SE','S','SW'];
				for( i = 0; i < classList.length; i++ ) {
					el = document.getElementsByClassName( 'imgCrop_handle' + classList[i], this.selArea )[0];
					if( el.childNodes.length ) el.removeChild( el.childNodes[0] );
					el.appendChild(d);
				}
			}
			fixEl.appendChild(n);
			fixEl.removeChild(n);
		}
	},
	
	/**
	 * Starts the resize
	 * 
	 * @access private
	 * @param obj Event
	 * @return void
	 */
	startResize: function( e ) {
		this.startCoords = this.cloneCoords( this.areaCoords );
		
		this.resizing = true;
		this.resizeHandle = Event.element( e ).classNames().toString().replace(/([^N|NE|E|SE|S|SW|W|NW])+/, '');
		// dump( 'this.resizeHandle : ' + this.resizeHandle + '\n' );
		Event.stop( e );
	},
	
	/**
	 * Starts the drag
	 * 
	 * @access private
	 * @param obj Event
	 * @return void
	 */
	startDrag: function( e ) {	
		this.selArea.show();
		this.clickCoords = this.getCurPos( e );
     	
    	this.setAreaCoords( { x1: this.clickCoords.x, y1: this.clickCoords.y, x2: this.clickCoords.x, y2: this.clickCoords.y }, false, false, null );
    	
    	this.dragging = true;
    	this.onDrag( e ); // incase the user just clicks once after already making a selection
    	Event.stop( e );
	},
	
	/**
	 * Gets the current cursor position relative to the image
	 * 
	 * @access private
	 * @param obj Event
	 * @return obj x,y pixels of the cursor
	 */
	getCurPos: function( e ) {
		// get the offsets for the wrapper within the document
		var el = this.imgWrap, wrapOffsets = Position.cumulativeOffset( el );
		// remove any scrolling that is applied to the wrapper (this may be buggy) - don't count the scroll on the body as that won't affect us
		while( el.nodeName != 'BODY' ) {
			wrapOffsets[1] -= el.scrollTop  || 0;
			wrapOffsets[0] -= el.scrollLeft || 0;
			el = el.parentNode;
	    }		
		return curPos = { 
			x: Event.pointerX(e) - wrapOffsets[0],
			y: Event.pointerY(e) - wrapOffsets[1]
		}
	},
  	
  	/**
  	 * Performs the drag for both resize & inital draw dragging
  	 * 
  	 * @access private
	 * @param obj Event
	 * @return void
	 */
  	onDrag: function( e ) {
  		if( this.dragging || this.resizing ) {	
  		
  			var resizeHandle = null;
  			var curPos = this.getCurPos( e );			
			var newCoords = this.cloneCoords( this.areaCoords );
  			var direction = { x: 1, y: 1 };
  	  					
		    if( this.dragging ) {
		    	if( curPos.x < this.clickCoords.x ) direction.x = -1;
		    	if( curPos.y < this.clickCoords.y ) direction.y = -1;
		    	
				this.transformCoords( curPos.x, this.clickCoords.x, newCoords, 'x' );
				this.transformCoords( curPos.y, this.clickCoords.y, newCoords, 'y' );
			} else if( this.resizing ) {
				resizeHandle = this.resizeHandle;			
				// do x movements first
				if( resizeHandle.match(/E/) ) {
					// if we're moving an east handle
					this.transformCoords( curPos.x, this.startCoords.x1, newCoords, 'x' );	
					if( curPos.x < this.startCoords.x1 ) direction.x = -1;
				} else if( resizeHandle.match(/W/) ) {
					// if we're moving an west handle
					this.transformCoords( curPos.x, this.startCoords.x2, newCoords, 'x' );
					if( curPos.x < this.startCoords.x2 ) direction.x = -1;
				}
									
				// do y movements second
				if( resizeHandle.match(/N/) ) {
					// if we're moving an north handle	
					this.transformCoords( curPos.y, this.startCoords.y2, newCoords, 'y' );
					if( curPos.y < this.startCoords.y2 ) direction.y = -1;
				} else if( resizeHandle.match(/S/) ) {
					// if we're moving an south handle
					this.transformCoords( curPos.y, this.startCoords.y1, newCoords, 'y' );	
					if( curPos.y < this.startCoords.y1 ) direction.y = -1;
				}	
							
			}
		
			this.setAreaCoords( newCoords, false, e.shiftKey, direction, resizeHandle );
			this.drawArea();
			Event.stop( e ); // stop the default event (selecting images & text) in Safari & IE PC
		}
	},
	
	/**
	 * Applies the appropriate transform to supplied co-ordinates, on the
	 * defined axis, depending on the relationship of the supplied values
	 * 
	 * @access private
	 * @param int Current value of pointer
	 * @param int Base value to compare current pointer val to
	 * @param obj Coordinates to apply transformation on x1, x2, y1, y2
	 * @param string Axis to apply transformation on 'x' || 'y'
	 * @return void
	 */
	transformCoords : function( curVal, baseVal, coords, axis ) {
		var newVals = [ curVal, baseVal ];
		if( curVal > baseVal ) newVals.reverse();
		coords[ axis + '1' ] = newVals[0];
		coords[ axis + '2' ] = newVals[1];		
	},
	
	/**
	 * Ends the crop & passes the values of the select area on to the appropriate 
	 * callback function on completion of a crop
	 * 
	 * @access private
	 * @return void
	 */
	endCrop : function() {
		this.dragging = false;
		this.resizing = false;
		
	/*	this.options.onEndCrop(
			this.areaCoords,
			{
				width: this.calcW(), 
				height: this.calcH() 
			}
		);*/
	},
	
	/**
	 * Abstract method called on the end of initialization
	 * 
	 * @access private
	 * @abstract
	 * @return void
	 */
	subInitialize: function() {},
	
	/**
	 * Abstract method called on the end of drawArea()
	 * 
	 * @access private
	 * @abstract
	 * @return void
	 */
	subDrawArea: function() {}
};




/**
 * Extend the Cropper.Img class to allow for presentation of a preview image of the resulting crop,
 * the option for displayOnInit is always overridden to true when displaying a preview image
 * 
 * Usage:
 * 	@param obj Image element to attach to
 * 	@param obj Optional options:
 * 		- see Cropper.Img for base options
 * 		
 * 		- previewWrap obj
 * 			HTML element that will be used as a container for the preview image		
 */
Cropper.ImgWithPreview = Class.create();

Object.extend( Object.extend( Cropper.ImgWithPreview.prototype, Cropper.Img.prototype ), {
	
	/**
	 * Implements the abstract method from Cropper.Img to initialize preview image settings.
	 * Will only attach a preview image is the previewWrap element is defined and the minWidth
	 * & minHeight options are set.
	 * 
	 * @see Croper.Img.subInitialize
	 */
	subInitialize: function() {
		/**
		 * Whether or not we've attached a preview image
		 * @var boolean
		 */
		this.hasPreviewImg = false;
		if( typeof(this.options.previewWrap) != 'undefined' 
			&& this.options.minWidth > 0 
			&& this.options.minHeight > 0
		) {
			/**
			 * The preview image wrapper element
			 * @var obj HTML element
			 */
			this.previewWrap 	= $( this.options.previewWrap );
			/**
			 * The preview image element
			 * @var obj HTML IMG element
			 */
			this.previewImg 	= this.img.cloneNode( false );
			// set the ID of the preview image to be unique
			this.previewImg.id	= 'imgCrop_' + this.previewImg.id;
			
						
			// set the displayOnInit option to true so we display the select area at the same time as the thumbnail
			this.options.displayOnInit = true;

			this.hasPreviewImg 	= true;
			
			this.previewWrap.addClassName( 'imgCrop_previewWrap' );
			
			this.previewWrap.setStyle(
			 { 
			 	width: this.options.minWidth + 'px',
			 	height: this.options.minHeight + 'px'
			 }
			);
			
			this.previewWrap.appendChild( this.previewImg );
		}
	},
	
	/**
	 * Implements the abstract method from Cropper.Img to draw the preview image
	 * 
	 * @see Croper.Img.subDrawArea
	 */
	subDrawArea: function() {
		if( this.hasPreviewImg ) {
			// get the ratio of the select area to the src image
			var calcWidth = this.calcW();
			var calcHeight = this.calcH();
			// ratios for the dimensions of the preview image
			var dimRatio = { 
				x: this.imgW / calcWidth, 
				y: this.imgH / calcHeight 
			}; 
			//ratios for the positions within the preview
			var posRatio = { 
				x: calcWidth / this.options.minWidth, 
				y: calcHeight / this.options.minHeight 
			};
			
			// setting the positions in an obj before apply styles for rendering speed increase
			var calcPos	= {
				w: Math.ceil( this.options.minWidth * dimRatio.x ) + 'px',
				h: Math.ceil( this.options.minHeight * dimRatio.y ) + 'px',
				x: '-' + Math.ceil( this.areaCoords.x1 / posRatio.x )  + 'px',
				y: '-' + Math.ceil( this.areaCoords.y1 / posRatio.y ) + 'px'
			}
			
			var previewStyle 	= this.previewImg.style;
			previewStyle.width 	= calcPos.w;
			previewStyle.height	= calcPos.h;
			previewStyle.left	= calcPos.x;
			previewStyle.top	= calcPos.y;
		}
	}
	
});


/**
 * Extend the Cropper.Img class to allow for presentation of a preview image of the resulting crop,
 * the option for displayOnInit is always overridden to true when displaying a preview image
 * 
 * Usage:
 * 	@param obj Image element to attach to
 * 	@param obj Optional options:
 * 		- see Cropper.Img for base options
 * 		
 * 		- previewWrap obj
 * 			HTML element that will be used as a container for the preview image		
 */
Cropper.KbImage = Class.create();

Object.extend( Object.extend( Cropper.KbImage.prototype, Cropper.Img.prototype ), {
	
	/**
	 * Implements the abstract method from Cropper.Img to initialize preview image settings.
	 * Will only attach a preview image is the previewWrap element is defined and the minWidth
	 * & minHeight options are set.
	 * 
	 * @see Croper.Img.subInitialize
	 */
	subInitialize: function() {
		/**
		 * Whether or not we've attached a preview image
		 * @var boolean
		 */
		this.hasPreviewImg = false;
		if( typeof(this.options.previewWrap) != 'undefined' 
			&& this.options.minWidth > 0 
			&& this.options.minHeight > 0
		) {
			/**
			 * The preview image wrapper element
			 * @var obj HTML element
			 */
			this.previewWrap 	= $( this.options.previewWrap );
			/**
			 * The preview image element
			 * @var obj HTML IMG element
			 */
			this.previewImg 	= this.img.cloneNode( false );
			// set the ID of the preview image to be unique
			this.previewImg.id	= 'imgCrop_' + this.previewImg.id;
			this.previewImg.writeAttribute({width: this.img.width / this.options.kbOptions.zoom});
			this.previewImg.setStyle({width: (this.img.width / this.options.kbOptions.zoom) + 'px' });
						
			// set the displayOnInit option to true so we display the select area at the same time as the thumbnail
			this.options.displayOnInit = true;

			this.hasPreviewImg 	= true;
			var previewDim = this.options.kbOptions.preview_size;
			this.previewWrap.addClassName( 'imgCrop_previewWrap' );
			
			this.previewWrap.setStyle({ 
			 	width: previewDim.width + 'px',
			 	height: previewDim.height + 'px',
				overflow: 'hidden'
			});
			
			this.previewWrap.appendChild( this.previewImg );
			
		}
	},
	
	/**
	 * Implements the abstract method from Cropper.Img to draw the preview image
	 * 
	 * @see Croper.Img.subDrawArea
	 */
	subDrawArea: function() {
		if( this.hasPreviewImg ) {
			var previewDim = this.options.kbOptions.preview_size;
			this.previewWrap.setStyle({ 
			 	width: previewDim.width + 'px',
			 	height: previewDim.height + 'px',
				overflow: 'hidden'
			});
			// get the ratio of the select area to the src image
			var calcWidth = this.calcW();
			var calcHeight = this.calcH();
			// ratios for the dimensions of the preview image
			var dimRatio = { 
				x: this.imgW / calcWidth, 
				y: this.imgH / calcHeight 
			}; 
			//ratios for the positions within the preview
			var posRatio = { 
				x: calcWidth / this.options.minWidth, 
				y: calcHeight / this.options.minHeight 
			};
			
			// setting the positions in an obj before apply styles for rendering speed increase
			var calcPos	= {
				w: Math.ceil(( (this.options.minWidth * dimRatio.x) / this.options.kbOptions.zoom ) * (this.options.kbOptions.ratio)),
				h: Math.ceil(( (this.options.minHeight * dimRatio.y) / this.options.kbOptions.zoom ) * (this.options.kbOptions.ratio)) ,
				x: '-' + Math.ceil(( (this.areaCoords.x1 / posRatio.x) / this.options.kbOptions.zoom ) * (this.options.kbOptions.ratio)),
				y: '-' + Math.ceil(( (this.areaCoords.y1 / posRatio.y) / this.options.kbOptions.zoom ) * (this.options.kbOptions.ratio))
			};
						
			var previewStyle 	= this.previewImg.style;
			previewStyle.width 	= calcPos.w + 'px';
			previewStyle.height	= calcPos.h + 'px';
			previewStyle.left	= calcPos.x + 'px';
			previewStyle.top	= calcPos.y + 'px';
		}
	},
	
	/**
	 * Ends the crop & passes the values of the select area on to the appropriate 
	 * callback function on completion of a crop
	 * 
	 * @access private
	 * @return void
	 */
	endCrop : function() {
		this.dragging = false;
		this.resizing = false;
		
		
		if( this.hasPreviewImg ) {
			var ratio = this.options.kbOptions.ratio;
			var calcWidth = this.calcW();
			var calcHeight = this.calcH();
			// ratios for the dimensions of the preview image
			var dimRatio = { 
				x: this.imgW / calcWidth, 
				y: this.imgH / calcHeight 
			}; 
			//ratios for the positions within the preview
			var posRatio = { 
				x: calcWidth / this.options.minWidth, 
				y: calcHeight / this.options.minHeight 
			};
			
			// setting the positions in an obj before apply styles for rendering speed increase
			var dimensions = this.previewImg.getDimensions();
			dimensions.width /= ratio;
			dimensions.height /= ratio;
			
			var coords = {
				x1: Math.abs((this.previewImg.getStyle('left').match(/\d{1,4}/).first() / ratio)),
				y1: Math.abs((this.previewImg.getStyle('top').match(/\d{1,4}/).first() / ratio))
			};
			
			Object.extend(coords,{
				x2: (coords.x1 + (this.previewWrap.getDimensions().width / ratio)),
				y2: (coords.y1 + (this.previewWrap.getDimensions().height / ratio))
			});
			this.options.onEndCrop(
				coords,
				dimensions,
				this.options.kbOptions
			);
		}	
	}
	
});

/*
**
** File 'imageResize.class.js'
**
*/

if (parseFloat(Prototype.Version) < 1.6)  throw("Image Resize requires the Prototype JavaScript framework >= 1.6.0");

if (!IMAGERESIZE16_INCLUDED){	

	var IMAGERESIZE16_INCLUDED = true;

	var ZoomButton = Class.create();
	/**
	  * Class Zoombutton
	  * author: ben
	  * Slider für Image Resize
	  */
	ZoomButton.prototype = {	
		
		_uniqueId: 1,
		_slider: null,
		_image:null,
		
		// Bilder für den Slider
		//_plusButtonImg: "/img/icons/silk_icons/add.png",
		_plusButtonImg: "/img/slider/slider_btn_zoom_in.gif",
		_plusButtonClass: "gif",
		//_minusButtonImg: "/img/icons/silk_icons/delete.png",
		_minusButtonImg: "/img/slider/slider_btn_zoom_out.gif",
		_minusButtonClass: "gif",
		_sliderImg: "/img/slider/slider_bg_sml.gif",
		//_sliderImg: "/img/imgResize/zoom_bg2.png",
		_sliderClass: "gif",	
		_zbImg: "/img/slider/magnifier_handle.gif",
		_zbClass: "gif",
		_crop: null,
		
		_sizePreset:null,
		
		// irgendwelche Konstanten wo ich denn sinn noch nicht kene :)
		zoom_100: 328,
		percent: 100,
		buttonStep: 10,
		
		initialize: function (options){
			// Übergebene Parameter (options) Parsen
			this._uniqueId = (options && options.id)?options.id:this._uniqueId;
			this.zoom_100 = (options && options.zoom_100)?options.zoom_100:this.zoom_100;
			var target = $((options && options.target)?options.target:null);
			this._slider = document.createElement('div');
			this._sizePreset = $((options && options.size_preset)?options.size_preset:null).cloneNode(true); 
			if ($((options && options.size_preset)?options.size_preset:null))
				$((options && options.size_preset)?options.size_preset:null).remove();
			
			this._image = (options && options.image)?options.image:null;
			this._crop = (options && options.crop != null )?options.crop:1;
			
			options = Object.extend({
				crop_resizeable:true
			}, options || { });
		
			// Formularelemente Bauen
			this._slider.id = 'size'+this._uniqueId;
			var plusButton = $(document.createElement('div'));		
			var minusButton = $(document.createElement('div'));
			plusButton.setStyle({float:'left'});
			minusButton.setStyle({float:'left'});	
			plusButton.obj = this;
			minusButton.obj = this;
			plusButton.onmouseover = plusButton.style.cursor='pointer';
			minusButton.onmouseover = minusButton.style.cursor='pointer';	
			plusButton.onclick = function(){
				this.obj.setPercent(this.obj.buttonStep)
			};
			minusButton.onclick = function(){
				this.obj.setPercent((this.obj.buttonStep)*(-1))
			};
			var slideLine = $(document.createElement('div'));		
			slideLine.setStyle({float:'left',width:'328px',height:'2px',margin:'8px 2px 3px 2px',backgroundImage: 'url('+this._sliderImg+')'});
			var zoomButton = $(document.createElement('div'));		
			zoomButton.setStyle({width:'10px',height:'22px',margin:'0 0 0 0 ',backgroundImage: 'url('+this._zbImg+')',backgroundRepeat: 'no-repeat',position:'relative',top:'-10px'});		
			slideLine.id = 'zoom_'+this._uniqueId;
			zoomButton.id = 'zoom_button_'+this._uniqueId;		
			slideLine.appendChild(zoomButton);		
			plusButton.appendChild(document.createElement('img'));
			plusButton.firstChild.src = this._plusButtonImg;
			plusButton.firstChild.className = this._plusButtonClass;		
			minusButton.appendChild(document.createElement('img'));
			minusButton.firstChild.src = this._minusButtonImg;
			minusButton.firstChild.className = this._minusButtonClass;		
			
			var input_x = $(document.createElement('div'));
			input_x.setStyle({float:'left', margin:'-5px  0 0 0'});
			input_x.appendChild(document.createElement('input'))
			input_x.firstChild.type = 'text';
			input_x.firstChild.size = '5';
			input_x.firstChild.id = "ig_w_" + this._uniqueId;
			input_x.firstChild._image = this._image;
			input_x.firstChild.onkeyup = (this._crop)?function(){this._image.igBoxChange('x')}:function(){this._image.igImageChange('x')};
			input_x.firstChild.onchange = (this._crop)?function(){this._image.igBoxChange('x')}:function(){this._image.igImageChange('x')};
			
			var input_text_1 = $(document.createElement('div'));
			input_text_1.setStyle({float:'left',margin:'0 15px 0 15px'});
			input_text_1.appendChild(document.createTextNode(unescape('Gr%F6%DFe%3A')));
			var input_text_2 = $(document.createElement('div'));
			input_text_2.setStyle({float:'left',margin:'0 5px 0 5px'});
			input_text_2.appendChild(document.createTextNode(' X '));
			var input_text_3 = $(document.createElement('div'));
			input_text_3.setStyle({float:'left',margin:'0 5px 0 5px'});
			input_text_3.appendChild(document.createTextNode('px'));
			
			var input_y = $(document.createElement('div'));
			input_y.setStyle({float:'left', margin:'-5px  0 0 0'});
			input_y.appendChild(document.createElement('input'))
			input_y.firstChild.type = 'text';
			input_y.firstChild.size = '5';
			input_y.firstChild.id = "ig_h_" + this._uniqueId;
			input_y.firstChild._image = this._image;
			input_y.firstChild.onkeyup = (this._crop)?function(){this._image.igBoxChange('y')}:function(){this._image.igImageChange('y')};
			input_y.firstChild.onchange = (this._crop)?function(){this._image.igBoxChange('y')}:function(){this._image.igImageChange('y')};
			
			this._sizePreset = $(this._sizePreset);
			if (this._sizePreset){
				this._sizePreset.cleanWhitespace();			
				this._sizePreset.setStyle({display:'block',float:'left',margin:'-3px 0 0 7px'});
				this._sizePreset._image = this._image;
				
				this._sizePreset.onchange = (this._crop)?function(){this._image.boxChange()}:function(){this._image.boxChange()};
			}
			
			var slideWrapper = new Element('div',{className:'slide-wrapper', style:'float:left;position:relative;top:-2px;'});
			var inputWrapper = new Element('div',{className:'input-wrapper'});
			slideWrapper.appendChild(minusButton);
			slideWrapper.appendChild(slideLine);
			slideWrapper.appendChild(plusButton);
			slideWrapper.appendChild(createClearDiv());
			this._slider.appendChild(slideWrapper);
			inputWrapper.appendChild(input_text_1);
			inputWrapper.appendChild(input_x);
			inputWrapper.appendChild(input_text_2);		
			inputWrapper.appendChild(input_y);
			inputWrapper.appendChild(input_text_3);
			if (this._sizePreset) inputWrapper.appendChild(this._sizePreset);
			this._slider.appendChild(inputWrapper);
			
			if (this._sizePreset){
				new Insertion.After(this._sizePreset, '<div class="clear"></div>')
			} else {
				new Insertion.After(input_text_3, '<div class="clear"></div>')
			}
			//this._slider.appendChild(createClearDiv());
			this._slider.appendChild(createClearDiv());
			if (!options.crop_resizeable) {
				$(input_text_1).hide();
				$(input_x).hide();
				$(input_text_2).hide();
				$(input_y).hide();
				$(input_text_3).hide();
			}
			if (target) target.appendChild(this._slider);
		},
		
		// verweis auf das zugehörige Objekt der Image Klasse
		setImage: function(image){
			this._image = image;
		},
		
		// setzt den slider abhängig des übergebenen wertes
		set:function(x) {
	        if (x == 0) x=1;
	        a = ( ( zoom_100 / 100 ) * x );
	        dd.elements['zoom_button_'+this._uniqueId].moveTo( dd.elements['zoom_button_'+this._uniqueId].defx + a,dd.elements['zoom_button_'+this._uniqueId].defy );
	        this.move();
		},
		
		// setzt den slider abhängig des übergebenen wertes in prozent
		setAbsPercent: function (x) {
	        a = parseInt(x);
	        if(a > 100) a = 100;
	        if(a < 0) a = 0;
	        this.set(a);
		},
		

		setAbsPercentButton: function (x) {
	        a = parseInt(x);
	        if(a > 100) a = 100;
	        if(a < 0) a = 0;
	         if (x == 0) x=1;
	        a = ( ( zoom_100 / 100 ) * x );
	        dd.elements['zoom_button_'+this._uniqueId].moveTo( dd.elements['zoom_button_'+this._uniqueId].defx + a,dd.elements['zoom_button_'+this._uniqueId].defy );
		},
		
		setPercent: function (x) {
	        x = parseInt(x);
	        a = this.percent + x;
	        if(a > 100) a = 100;
	        if(a < 0) a = 0;
	        this.set(a);
		},


		move:function(){
	        x = dd.elements['zoom_button_'+this._uniqueId].x - dd.elements['zoom_button_'+this._uniqueId].defx;
			x = zoom_100 - x;
	        this.percent = 100 -  (( x /  zoom_100  ) * 100 );
	        if (this.percent == 0) this.percent = 2;
			
	        this._image.percent((this.percent));
			
		},
		
		getPercent: function(){
			return this.percent;
		}

	}


	var IR = Class.create();

	IR.prototype = {
		_uniqueId: 1,
		_zoom:null,
		_iR:null,
		_width:640,
		_height:480,	
		_width2:640,
		_height2:480,
		
		_boxWidth:140,
		_boxHeight:185,
		
		_boxX: 328,
		_boxY: 5,
		_parentDiv: null,
		_ratio: 1,
		/* ab welcher Diskrepanz zwischen original Seitenverhältnis & aktuellem Seitenverhältnis ist es nicht mehr proportional*/
		_proportionalSensitive: 0.034,
		
		maxDimensions:null,
		_dimensions:null,
		
		_picture:null,
		_lightOverlap:null,
		_darkOverlap:null,
		
		_crop:null,
		delta:{x:0,y:0},
		_maxZoomPercent: 1600,
		maxWidth:0,
		maxHeight:0,


		initialize: function(options){
			this._uniqueId = (options && options.id)?options.id:this._uniqueId;
			target = $((options && options.target)?options.target:null);
			this._picture = $((options && options.picture)?options.picture:null);
			this._parentDiv = $((options && options.parentDiv)?options.parentDiv:null);
			this._dimensions = (options && options.dimensions)?options.dimensions:{width:this._width,height:this._height};
			this._crop = (options && options.crop != null )?options.crop:1;
			this._boxWidth = (options && options.crop_x != null )?options.crop_x:this._boxWidth;
			this._boxHeight = (options && options.crop_y != null )?options.crop_y:this._boxHeight;
			this._iR = (options && options.iResize != null )?options.iResize:null;
			this.imageRatio = 1.333;//this._dimensions.width / this._dimensions.height;
			
			
			options = Object.extend({
				box_overlay:null
			}, options || { });
			
			
			
			this._width = this._width2 = this._dimensions.width;
			this._height = this._height2 = this._dimensions.height;
			
			
			this.containerDim = this._parentDiv.getDimensions(); 
			this._parentDiv.setStyle({height:(this.containerDim.width/this.imageRatio)+'px',overflow:'hidden'});
			this.containerDim = this._parentDiv.getDimensions(); 
			
			this.maxWidth = (this._width2 * this._maxZoomPercent) / 100;
			this.maxHeight = (this._height2 * this._maxZoomPercent) / 100;
			
			this._picture.setStyle({position: 'absolute', galleryimg:"no"});	
			 
			var box = $(document.createElement('div'));
			box.id = 'box_' + this._uniqueId;
			box.setStyle({"zIndex":3,width:"10px",height:"10px",border:'1px solid #E8FD59',position:'relative',overflow:'hidden'});	
			if (options.box_overlay){
				boxOverlay = new Element('img',{src:options.box_overlay,width:this._boxWidth,height:this._boxHeight});
				box.appendChild(boxOverlay);
				boxOverlay.setOpacity(0.5);
				box.setStyle({"zIndex":3,width:"11px",height:"11px",border:'0px'});	
			}
			

			this._lightOverlap = $(document.createElement('img'));
			this._lightOverlap.id = 'lightOverlap_'.uniqueId;
			this._lightOverlap.src = (this._picture) ? this._picture.src : '';
			this._lightOverlap.setStyle({position: 'absolute', galleryimg:"no",zIndex:'2' });
			
			
			
			this._darkOverlap = $(document.createElement('div'));
			this._darkOverlap.setStyle({zIndex:1,backgroundColor: 'black',FILTER:'alpha(opacity=50)',MozOpacity: '0.5',opacity: '0.5',position:'absolute'});		
			
			if (target && this._darkOverlap) target.appendChild(this._darkOverlap);	
			if (target) target.appendChild(this._lightOverlap);	
			if (target) target.appendChild(box);	
			
			if (this._crop) {
				if( this._boxWidth > this._width ){
					this._boxWidth = this._width - 5;
					this._boxX = 2;
				}
				if( this._boxHeight > this._height ){
					this._boxHeight = this._height - 5;
					this._boxY = 2;
				}
				
			} else {
				this._boxWidth = this._width-1;
				this._boxX = 0;
				this._boxHeight = this._height-1;
				this._boxY = 0;
			}
			this._ratio = (this._crop)?this._boxWidth/this._boxHeight:this._width/this._height;
			this.maxDimensions = {right:(this._width - this._boxWidth), bottom:(this._height - this._boxHeight)} ;
			this.dragImage = new Draggable(this._picture,{
				handle:this._darkOverlap,
				snap:this.contain.bind(this),
				zindex: 1
			});
			Event.observe(this._darkOverlap, "mouseover", this.cursorHand.bindAsEventListener(this));
			
		},
		
		cursorHand: function(e){
			e.element().style.cursor='pointer';
		},
	
		
		contain: function (x,y,draggable) {
			if (x == undefined) x = 0;
			if (y == undefined) y = 0;
			
	        var dim = Element.getDimensions(draggable.element);
	        
	        var xMin = 0, xMax = (this.containerDim.width-dim.width >= 0)?0:this.containerDim.width-dim.width;
	        var yMin = 0, yMax = (this.containerDim.height-dim.height >= 0)?0:this.containerDim.height-dim.height;
	        
	        x = x>xMin ? xMin : x;
	        x = x<xMax ? xMax : x;
	        y = y>yMin ? yMin : y;
	        y = y<yMax ? yMax : y;
			
			Element.clonePosition(this._lightOverlap, this._picture);
			
			this.delta = {x:x,y:y};
			if (this._iR) this._iR.delta = {x:x,y:y};
			
			_upper	= dd.elements['box_'+this._uniqueId].y - dd.elements['box_'+this._uniqueId].defy  - y;
			_right  = dd.elements['box_'+this._uniqueId].x - dd.elements['box_'+this._uniqueId].defx  - x;
			_bottom = dd.elements['box_'+this._uniqueId].y - dd.elements['box_'+this._uniqueId].defy + parseInt(this._boxHeight) - y;
			_left   = dd.elements['box_'+this._uniqueId].x - dd.elements['box_'+this._uniqueId].defx + parseInt(this._boxWidth) - x;
			
			if( !isIE ) _clip = "rect( " + _upper + "px " + _right + "px " + _bottom + "px " + _left + "px )";
			else _clip = "rect( " + _upper + "px " + _left + "px " + _bottom + "px " + _right + "px )";

			this._lightOverlap.style.clip = _clip;
	        
	      /*   this.imageX = x;
	        this.imageY = (y>0)?0:y;
	       
	        this.imageEl.style.left = this.imageX+'px';
	        this.imageEl.style.top = this.imageY+'px';*/
	        
	        return [x,y];
	    },
		
		init: function (options){
			
			
	        if( !_step ) var _step = 1;
	        this.setBox();
			this.setPicture();
	        dd.elements['zoom_button_'+this._uniqueId].moveTo( dd.elements['zoom_button_'+this._uniqueId].defx, dd.elements['zoom_button_'+this._uniqueId].defy );
	        dd.elements['box_'+this._uniqueId].moveBy( this._boxX, this._boxY );
			this._zoom.move();
			this.checkBoxPosition();
		},
		
		standard: function(){
		    this._width = 600;
			this._height = 400;
			this.setPicture();
		},
		
		getMaxDimensions: function(){
			return this.maxDimensions;
		},
		
		percent: function(x){
			min_prozent_hoehe = (this._crop)?(this._boxHeight / this._height2) * 100:1;
	        min_prozent_breite = (this._crop)?(this._boxWidth / this._width2) * 100:1;
			
			
			
			
	        if(min_prozent_hoehe > min_prozent_breite) {
	                min_prozent = min_prozent_hoehe;
	        } else {
	                min_prozent = min_prozent_breite;
	        }
	        a = 100 - min_prozent;

	        b = (a / 100 ) * x;

	        var x_neu = b + min_prozent;
	     //   zoom_prozent = this._zoom.getPercent();
	        neue_breite = ( this._width2 / 100 ) *  x_neu;
	     //   neue_breite = ( this._width2 / 100 ) *  zoom_prozent;

	        skalierungsfaktor = this._width/neue_breite;
	        neue_hoehe = this._height/skalierungsfaktor;

			if (this._crop){
		         if((neue_breite >= this._boxWidth && neue_hoehe >= this._boxHeight)) {
		            this._width = neue_breite;
		            this._height = neue_hoehe;
		         } else {
					this._zoom.setAbsPercentButton(min_prozent);
				 }
			} else {
				this._width = neue_breite;
		        this._height = neue_hoehe;
				this.setBox();
			}
			if (Math.abs(((this._crop)?(this._boxWidth/this._boxHeight):(this._width/this._height)) - this._ratio) > this._proportionalSensitive && this._boxWidth > 10){
				setValueRecursive(this._zoom._sizePreset,'');
			} else {
				setValueRecursive(this._zoom._sizePreset,'1');
			}
				
	        this.setPicture();
		},
		
		checkBoxPosition: function(){
			a = dd.elements['box_'+this._uniqueId].x - dd.elements['box_'+this._uniqueId].defx + parseInt(this._boxWidth) - this.delta.x;
	        b = dd.elements['box_'+this._uniqueId].y - dd.elements['box_'+this._uniqueId].defy + parseInt(this._boxHeight) - this.delta.y;
		
			if (this._crop){
			
				_upper         = dd.elements['box_'+this._uniqueId].y - dd.elements['box_'+this._uniqueId].defy  - this.delta.y;
				_right         = dd.elements['box_'+this._uniqueId].x - dd.elements['box_'+this._uniqueId].defx  - this.delta.x;
				_bottom = b;
				_left        = a;

				if( !isIE ) _clip = "rect( " + _upper + "px " + _right + "px " + _bottom + "px " + _left + "px )";
				else _clip = "rect( " + _upper + "px " + _left + "px " + _bottom + "px " + _right + "px )";

			   this._lightOverlap.style.clip = _clip;

				if( a > this._width ){
						c = this._width - a;
						dd.elements['box_'+this._uniqueId].moveBy(c,0);
				}

				if( b > this._height ){
						c = this._height - b;
						dd.elements['box_'+this._uniqueId].moveBy(0,c);
				}

				if(dd.elements['box_'+this._uniqueId].x < 0) {
						dd.elements['box_'+this._uniqueId].moveTo(0,dd.elements['box_'+this._uniqueId].y);
				}

				if(dd.elements['box_'+this._uniqueId].y < 0) {
						dd.elements['box_'+this._uniqueId].moveTo(dd.elements['box_'+this._uniqueId].x,0);
				}
			} else {
				_upper	= 0;
				_right  = 0;
				_bottom = parseInt(this._boxHeight);
				_left   = parseInt(this._boxWidth);
			}
		},
		
		setMax: function(){
	        max_right = this._width-this._boxWidth;
	        max_bottom = this._height-this._boxHeight;
	        dd.elements['box_'+this._uniqueId].maxoffr = max_right;
	        dd.elements['box_'+this._uniqueId].maxoffb = max_bottom;
		},
		
		setBox: function(){
			if (this._crop) dd.elements['box_'+this._uniqueId].resizeTo( this._boxWidth,this._boxHeight );
			else  dd.elements['box_'+this._uniqueId].resizeTo( this._width,this._height );
	        document.getElementById("ig_w_" + this._uniqueId).value = (this._crop)?this._boxWidth:Math.round(this._width);
	        document.getElementById("ig_h_" + this._uniqueId).value = (this._crop)?this._boxHeight:Math.round(this._height);
		},

		setPicture: function(){
			
			var obj = (!this.checkBoxPosition)?this.obj:this;

			obj._picture.setStyle({width:obj._width + "px",height:obj._height + "px"});

	        /* Light overlap */this._lightOverlap
			obj._lightOverlap.setStyle({width:obj._width + "px",height:obj._height + "px"});

	        /* Dark overlap */
			obj._darkOverlap.setStyle({width:obj._width + "px",height:obj._height + "px"});

	        //document.getElementById("bild").style.backgroundImage = "url(bild.php?breite=" + bild_breite + "&bild=" + bild +")";
		//	if($(this._parentDiv)) $(this._parentDiv).style.height = obj._height + "px"; 
	        obj.checkBoxPosition();
	        obj.setMax();	
		},
		
		igBoxChange: function(axis){
			var value = getFormParams(this._zoom._sizePreset,true)
			if (value && value.values){ 
				value = value.values();
				value = (value.length && value[0])?value[0]:'';
			} else {
				value = ''
			}
			
			if (axis == 'x' && value == '1'){
				neue_breite = document.getElementById( "ig_w_"+this._uniqueId ).value;
				neue_hoehe = neue_breite/this._ratio;
		        document.getElementById( "ig_h_"+this._uniqueId ).value = neue_hoehe;
			} else if (axis == 'y' && value == '1') {
				neue_hoehe = document.getElementById( "ig_h_"+this._uniqueId ).value;
				neue_breite = neue_hoehe * this._ratio;
				document.getElementById( "ig_w_"+this._uniqueId ).value = neue_breite;	        
			} else {
				neue_breite = document.getElementById( "ig_w_"+this._uniqueId ).value;
		        neue_hoehe = document.getElementById( "ig_h_"+this._uniqueId ).value;
				setValueRecursive(this._zoom._sizePreset,'');
			}
			
			
	        if ( parseInt( neue_breite ) && neue_breite <= this._width ){
				 this._boxWidth = parseInt(neue_breite);
				 document.getElementById("ig_w_"+this._uniqueId).value = this._boxWidth;
	        } else {
				if (neue_breite >= this._width){
					 document.getElementById("ig_w_"+this._uniqueId).value = parseInt( this._width );
					 this._boxWidth =parseInt( this._width );
				} else {
					 document.getElementById("ig_w_"+this._uniqueId).value = parseInt( this._boxWidth );
				}
	        }

	        if ( parseInt( neue_hoehe ) && neue_hoehe <= this._height ){
				 this._boxHeight = parseInt( neue_hoehe );
				 document.getElementById( "ig_h_"+this._uniqueId ).value = this._boxHeight;
	        } else {
				if( neue_hoehe >= this._height ) {
					document.getElementById( "ig_h_"+this._uniqueId ).value = parseInt( this._height );
					this._boxHeight =  parseInt( this._height );
				} else {
					document.getElementById("ig_h_"+this._uniqueId).value = parseInt( this._boxHeight );
				}
	        }
	        _changed = 1;
	        this.setMax();
	        this.setBox();
	        this.checkBoxPosition();
			
			var sp = getFormParams(this._zoom._sizePreset.id,true).get('sizepreset');
			if (sp && sp[0]) sp = sp[0];
			
			if ((!sp || sp == '') || Math.abs(((this._crop)?(this._boxWidth/this._boxHeight):(this._width/this._height)) - this._ratio) > this._proportionalSensitive && this._boxWidth > 10){
				setValueRecursive(this._zoom._sizePreset,'');
			} else {
				setValueRecursive(this._zoom._sizePreset,'1');
			}
		},
		
		igImageChange: function(axis){
			var value = getFormParams(this._zoom._sizePreset,true)
			if (value && value.values){ 
				value = value.values();
				value = (value.length && value[0])?value[0]:'';
			} else {
				value = ''
			}
			
			
			if (axis == 'x' && value == '1'){
				neue_breite = document.getElementById( "ig_w_"+this._uniqueId ).value;
				neue_hoehe = neue_breite/this._ratio;
		        document.getElementById( "ig_h_"+this._uniqueId ).value = neue_hoehe;
			} else if (axis == 'y' && value == '1') {
				neue_hoehe = document.getElementById( "ig_h_"+this._uniqueId ).value;
				neue_breite = neue_hoehe * this._ratio;
				document.getElementById( "ig_w_"+this._uniqueId ).value = neue_breite;	        
			} else {
				neue_breite = document.getElementById( "ig_w_"+this._uniqueId ).value;
		        neue_hoehe = document.getElementById( "ig_h_"+this._uniqueId ).value;
				setValueRecursive(this._zoom._sizePreset,'');
			}
			
					
			var newpercentX = parseInt(neue_breite / this._width2 *100);
			var newpercentY = parseInt(neue_hoehe / this._height2 *100);
			var np = (newpercentX > newpercentY)?newpercentX:newpercentY;

	        if ( parseInt( neue_breite ) && neue_breite <= this.maxWidth ){
				 if (neue_breite > this._width2) this._width2 = neue_breite; 
				 else this._zoom.setAbsPercentButton(np);
				 this._width = parseInt(Math.round(neue_breite));
				 document.getElementById("ig_w_"+this._uniqueId).value = neue_breite;
	        } else {
				if (neue_breite >= this.maxWidth){
					if (neue_breite > this._width2) this._width2 = this.maxWidth;
					 document.getElementById("ig_w_"+this._uniqueId).value = parseInt(Math.round( this.maxWidth ));
					 this._boxWidth =parseInt(Math.round( this.maxWidth ));
				} else {
					 document.getElementById("ig_w_"+this._uniqueId).value = parseInt(Math.round( this._width ));
				}
	        }

	        if ( parseInt( neue_hoehe ) && neue_hoehe <= this.maxHeight ){
				  if (neue_hoehe > this._height2) this._height2 = neue_hoehe; 
				 else this._zoom.setAbsPercentButton(np);
				 this._height = parseInt(Math.round( neue_hoehe ));
				 document.getElementById( "ig_h_"+this._uniqueId ).value = neue_hoehe;
	        } else {
				if( neue_hoehe >= this.maxHeight ) {
					 if (neue_hoehe > this._height) this._height2 = this.maxHeight; 
					document.getElementById( "ig_h_"+this._uniqueId ).value = parseInt(Math.round( this.maxHeight ));
					this._height =  parseInt(Math.round( this.maxHeight ));
				} else {
					document.getElementById("ig_h_"+this._uniqueId).value = parseInt(Math.round( this._height ));
				}
	        }
	        _changed = 1;
			
			
	        this.setMax();
			
	        this.setPicture();
			this.setBox();
			
			if (Math.abs(((this._crop)?(this._boxWidth/this._boxHeight):(this._width/this._height)) - this._ratio) > this._proportionalSensitive  && this._boxWidth > 10){
				setValueRecursive(this._zoom._sizePreset,'');
			} else {
				setValueRecursive(this._zoom._sizePreset,'1');
			}
		},
		
		boxChange: function(){
			this._changed = 0;
			var value = getFormParams(this._zoom._sizePreset,true)
			if (value && value.values){ 
				value = value.values();
				value = (value.length && value[0])?value[0]:'';
			} else {
				value = ''
			}

			if (value != '1'){
				value = new String(value);
		        var arten = value.split('x');

				var new_width = (arten && arten[0])?arten[0]:(this._crop)?this._boxWidth:this._width;
				var new_height = (arten && arten[1])?arten[1]:(this._crop)?this._boxHeight:this._height;
				
				if (arten && arten.length == 1){
					new_height = Math.round(this._height * (new_width / this._width));
				}
			} else {
				var new_width = (this._crop)?this._boxWidth:this._width;
				var new_height = (this._crop)?this._boxHeight:this._height;
			}
			
			if (this._crop){		
		        if(new_width > this._width || new_height > this._height )
		        {
		                alert( 'Your picture is too small for this network' );
		                setValueRecursive(this._zoom._sizePreset,'1');
		                return false;
		        }

		        this._boxWidth = new_width;
		        this._boxHeight = new_height;
				
		        this.setMax();
		        this.setBox();

		       // this._zoom.move();
		        this.checkBoxPosition();
			} else {
				var newpercentX = parseInt(new_width / this._width2 *100);
				var newpercentY = parseInt(new_height / this._height2 *100);
				var np = (newpercentX > newpercentY)?newpercentX:newpercentY;
				
				if (new_height > this._height2) this._height2 = new_height; 
				else if (new_width > this._width2) this._width2 = new_width; 
				else this._zoom.setAbsPercentButton(np);
				
				this._width = new_width;
				this._height = new_height;
				document.getElementById("ig_w_"+this._uniqueId).value = parseInt(Math.round( this._width ));
				document.getElementById( "ig_h_"+this._uniqueId ).value = parseInt(Math.round( this._height ));
				this.setMax();
				
				this.setPicture();
				this.setBox();
			}
		},
		
		setZoomButton: function(zoom){
			this._zoom = zoom;
		}
	}

	var ImageResize = Class.create();

	ImageResize.prototype = {
		image:null,
		zoom:null,
		id:0,
		crop:null,
		delta:{x:0,y:0},
		
		initialize: function (options){
			this.id = (options && options.id)?options.id:this._uniqueId;
			var zoom_100 = (options && options.zoom_100)?options.zoom_100:328;
			var buttonTarget = $((options && options.buttonTarget)?options.buttonTarget:null );
			var imageTarget = $((options && options.imageTarget)?options.imageTarget:null );
			var picture = $((options && options.picture)?options.picture:null); 
			var parentDiv = $((options && options.parentDiv)?options.parentDiv:null); 
			var scale = (options && options.scale)?options.scale:1; 
			var size_preset = $((options && options.size_preset)?options.size_preset:null); 
			var dimensions = (options && options.dimensions)?options.dimensions:null;
			this.crop = (options && options.crop != null )?options.crop:1;

			options = Object.extend({
				crop_resizeable:true,
				crop_x:140,
				crop_y:185,
				box_overlay:''
			}, options || { });
			
			if (!parentDiv && imageTarget) parentDiv = $(imageTarget);
			
			var imageOptions = Object.extend(options || { },{
				iResize:this,
				id:this.id,
				target:imageTarget,
				picture:picture,
				dimensions:dimensions,
				crop:this.crop,
				parentDiv:parentDiv
			} );
			
			
			this.image = new IR(imageOptions);
			this.zoom = new ZoomButton({id:this.id,zoom_100:zoom_100,target:buttonTarget,image:this.image,crop:this.crop,size_preset:size_preset,crop_resizeable:options.crop_resizeable});
			
			this.image.setZoomButton(this.zoom);
		},
		
		initPicture: function(){
			this.image.init();
		},
		
		boxDimensions: function(){
			return (this.crop)?this.image.getMaxDimensions():{right:0,bottom:0};
		},
		
		getZoom: function(){
			return this.zoom;
		},
		
		getImage: function(){
			return this.image;
		},
		
		setPictureParams: function(){
			hidden_x = $('x_'+this.id);
			hidden_y = $('y_'+this.id);
			hidden_width = $('width_'+this.id);
			hidden_height = $('height_'+this.id);
			hidden_scale = $('scale_'+this.id);
			hidden_custom_width = $('custom_width_'+this.id);
			hidden_custom_height = $('custom_height_'+this.id);
		
			var _x = Math.round(dd.elements['box_'+this.id].x-dd.elements['box_'+this.id].defx - this.delta.x);
	        var _y = Math.round(dd.elements['box_'+this.id].y-dd.elements['box_'+this.id].defy - this.delta.y);
	        var _w = Math.round(dd.elements['box_'+this.id].w);
	        var _h = Math.round(dd.elements['box_'+this.id].h );
			var _cw = Math.round($( "ig_w_"+this.id ).value);
	        var _ch = Math.round($( "ig_h_"+this.id ).value );
			var _scale = (Math.round(((this.image._width / this.image._width2) *10000)))/100 ;
			
			if (hidden_x) hidden_x.value = _x;
			if (hidden_y) hidden_y.value = _y;
			if (hidden_width) hidden_width.value = _w;
			if (hidden_height) hidden_height.value = _h;
			if (hidden_custom_width) hidden_custom_width.value = _cw;
			if (hidden_custom_height) hidden_custom_height.value = _ch;
			if (hidden_scale) hidden_scale.value = _scale;
		}
	}
}

/*
**
** File 'validate.js'
**
*/
/* Validate.js, version 1.0.2
*  (c) 2006 achraf bouyakhsass <mutation[at]mutationevent.com>
* 
*  This software is licensed under the CC-GNU GPL
*  http://creativecommons.org/licenses/GPL/2.0/
*
*  For more details
*  http://www.mutationevent.com/project/validate.js
*
*  Package to validate various data :
*  isEqual
*  hasValidChars
*  isSimpleIP
*  isAlphaLatin
*  isNotEmpty
*  isIntegerInRange
*  isNum
*  isEMailAddr
*  isZipCode
*  isDate
*  isMD5
*  isURL
*  isGuid
*  isISBN
*  isSSN
*  isDecimal
*  isplatform
*  addRules
*  Apply
/*--------------------------------------------------------------------------*/


var Validate = Class.create();

Object.extend(Validate.prototype,{
	/*--------------------------------------------------------------------------*/
	initialize:function(){
		this.error_array = []
		this.rules_array = [];
		this.e = true;
	},
	/*--------------------------------------------------------------------------*/
	isEqual:function(string1, string2){
		if(string1 == string2) return true;
		else return false;
	},
	/*--------------------------------------------------------------------------*/
	hasValidChars:function(s, characters, caseSensitive){
		function escapeSpecials(s){
			return s.replace(new RegExp("([\\\\-])", "g"), "\\$1");
		}
		return new RegExp("^[" + escapeSpecials(characters) + "]+$",(!caseSensitive ? "i" : "")).test(s);
	},
	/*--------------------------------------------------------------------------*/
	isSimpleIP:function(ip){
		ipRegExp = /^(([0-2]*[0-9]+[0-9]+)\.([0-2]*[0-9]+[0-9]+)\.([0-2]*[0-9]+[0-9]+)\.([0-2]*[0-9]+[0-9]+))$/
		return ipRegExp.test(ip);
	},
	/*--------------------------------------------------------------------------*/
	isAlphaLatin:function(string){
		alphaRegExp = /^[0-9a-z]+$/i
		return alphaRegExp.test(string);
	},
	/*--------------------------------------------------------------------------*/
	isNotEmpty:function (string){
		return /\S/.test(string);
	},
	/*--------------------------------------------------------------------------*/
	isEmpty:function(s){
		return !/\S/.test(s);
	},
	/*--------------------------------------------------------------------------*/
	isIntegerInRange:function(n,Nmin,Nmax){
		var num = Number(n);
		if(isNaN(num)){
			return false;
		}
		if(num != Math.round(num)){
			return false;
		}
		return (num >= Nmin && num <= Nmax);
	},
	/*--------------------------------------------------------------------------*/
	isNum:function(number){
		numRegExp = /^[0-9]+$/
		return numRegExp.test(number);
	},
	/*--------------------------------------------------------------------------*/
	isEMailAddr:function(string){
		emailRegExp = /^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.([a-z]){2,4})$/
		return emailRegExp.test(string);
	},
	/*--------------------------------------------------------------------------*/
	isZipCode:function(zipcode,country){
		if(!zipcode) return false;
		if(!country) format = 'US';
		switch(country){
			case'US': zpcRegExp = /^\d{5}$|^\d{5}-\d{4}$/; break;
			case'MA': zpcRegExp = /^\d{5}$/; break;
			case'CA': zpcRegExp = /^[A-Z]\d[A-Z] \d[A-Z]\d$/; break;
			case'DU': zpcRegExp = /^[1-9][0-9]{3}\s?[a-zA-Z]{2}$/; break;
			case'FR': zpcRegExp = /^\d{5}$/; break;
			case'Monaco':zpcRegExp = /^(MC-)\d{5}$/; break;
		}
		return zpcRegExp.test(zipcode);
	},
	/*--------------------------------------------------------------------------*/
	isDate:function(date,format){
		if(!date) return false;
		if(!format) format = 'FR';
		
		switch(format){
			case'FR': RegExpformat = /^(([0-2]\d|[3][0-1])\/([0]\d|[1][0-2])\/([2][0]|[1][9])\d{2})$/; break;
			case'US': RegExpformat = /^([2][0]|[1][9])\d{2}\-([0]\d|[1][0-2])\-([0-2]\d|[3][0-1])$/; break;
			case'SHORTFR': RegExpformat = /^([0-2]\d|[3][0-1])\/([0]\d|[1][0-2])\/\d{2}$/; break;
			case'SHORTUS': RegExpformat = /^\d{2}\-([0]\d|[1][0-2])\-([0-2]\d|[3][0-1])$/; break;
			case'dd MMM yyyy':RegExpformat = /^([0-2]\d|[3][0-1])\s(Jan(vier)?|FâˆšÂ©v(rier)?|Mars|Avr(il)?|Mai|Juin|Juil(let)?|Aout|Sep(tembre)?|Oct(obre)?|Nov(ember)?|Dec(embre)?)\s([2][0]|[1][19])\d{2}$/; break;
			case'MMM dd, yyyy':RegExpformat = /^(J(anuary|u(ne|ly))|February|Ma(rch|y)|A(pril|ugust)|(((Sept|Nov|Dec)em)|Octo)ber)\s([0-2]\d|[3][0-1])\,\s([2][0]|[1][9])\d{2}$/; break;
		}
		
		return RegExpformat.test(date);
	},
	/*--------------------------------------------------------------------------*/
	isMD5:function(string){
		if(!string) return false;
		md5RegExp = /^[a-f0-9]{32}$/;
		return md5RegExp.test(string);
	},
	/*--------------------------------------------------------------------------*/
	isURL:function(string){
		if(!string) return false;
		string = string.toLowerCase();
		//urlRegExp = /^((((ht|f)tp(s?))\:\/\/)([0-9a-zA-Z\-]+\.)+[a-zA-Z]{2,6}(\:[0-9]+)?\/?)?(\S*)?$/
		urlRegExp = /^(((ht|f)tp(s?))|\/)/
		return urlRegExp.test(string);
	},
	/*--------------------------------------------------------------------------*/
	isGuid:function(guid){//guid format : xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx or xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
		if(!guid) return false;
		GuidRegExp = /^[{|\(]?[0-9a-fA-F]{8}[-]?([0-9a-fA-F]{4}[-]?){3}[0-9a-fA-F]{12}[\)|}]?$/
		return GuidRegExp.test(guid);
	},
	/*--------------------------------------------------------------------------*/
	isISBN:function(number){
		if(!number) return false;
		ISBNRegExp = /ISBN\x20(?=.{13}$)\d{1,5}([- ])\d{1,7}\1\d{1,6}\1(\d|X)$/
		return ISBNRegExp.test(number);
	},
	/*--------------------------------------------------------------------------*/
	isSSN:function(number){//Social Security Number format : NNN-NN-NNNN
		if(!number) return false;
		ssnRegExp = /^\d{3}-\d{2}-\d{4}$/
		return ssnRegExp.test(number);
	},
	/*--------------------------------------------------------------------------*/
	isDecimal:function(number){// positive or negative decimal
		if(!number) return false;
		decimalRegExp = /^-?(0|[1-9]{1}\d{0,})(\.(\d{1}\d{0,}))?$/
		return decimalRegExp.test(number);
	},
	/*--------------------------------------------------------------------------*/
	isplatform:function(platform){
		//win, mac, nix
		if(!platform) return false;
		var os;
		winRegExp = /\win/i
		if(winRegExp.test(window.navigator.platform)) os = 'win';
		
		macRegExp = /\mac/i
		if(macRegExp.test(window.navigator.platform)) os = 'mac';
		
		nixRegExp = /\unix|\linux|\sun/i
		if(nixRegExp.test(window.navigator.platform)) os = 'nix';
		
		if(platform == os) return true;
		else return false;
	},
	/*--------------------------------------------------------------------------*/
	getValue:function(id){
		document.getElementById(id).value;
	},
	/*--------------------------------------------------------------------------*/
	addRules:function(rules){
		this.rules_array.push(rules);
	},
	/*--------------------------------------------------------------------------*/
	check:function(){
		this.error_array = [];
		this.e = true;
		for(var i=0;i<this.rules_array.length;i++){
			switch(this.rules_array[i].option){
				/*--------------------------------------------------------------------------*/
				case'ValidChars':
					if(!this.hasValidChars(getValue(this.rules_array[i].id),this.rules_array[i].chars,false)){
						this.error_array.push(this.rules_array[i].error);
						this.e = false;
					}
				break;
				/*--------------------------------------------------------------------------*/
				case'AlphaLatin':
					if (this.isAlphaLatin(getValue(this.rules_array[i].id))){
						this.error_array.push(this.rules_array[i].error);
						this.e = false;
					}
				break;
				/*--------------------------------------------------------------------------*/
				case'required':
					if (this.isEmpty(getValue(this.rules_array[i].id))){
						this.error_array.push(this.rules_array[i].error);
						this.e = false;
					}
				break;
				/*--------------------------------------------------------------------------*/
				case'integerRange':
					if (!this.isIntegerInRange(getValue(this.rules_array[i].id),this.rules_array[i].Min,this.rules_array[i].Max)){
						this.error_array.push(this.rules_array[i].error);
						this.e = false;
					}
				break;
				/*--------------------------------------------------------------------------*/
				case'Number':
					if (!this.isNum(getValue(this.rules_array[i].id))){
						this.error_array.push(this.rules_array[i].error);
						this.e = false;
					}
				break;
				/*--------------------------------------------------------------------------*/
				case'email':
					if (!this.isEMailAddr(getValue(this.rules_array[i].id))){
						this.error_array.push(this.rules_array[i].error);
						this.e = false;
					}
				break;
				/*--------------------------------------------------------------------------*/
				case'zipCode':
					if (!this.isZipCode(getValue(this.rules_array[i].id),this.rules_array[i].country)){
						this.error_array.push(this.rules_array[i].error);
						this.e = false;
					}
				break;
				/*--------------------------------------------------------------------------*/
				case'date':
					if(!this.isDate(getValue(this.rules_array[i].id),this.rules_array[i].format)){
						this.error_array.push(this.rules_array[i].error);
						this.e = false;
					}
				break;
				/*--------------------------------------------------------------------------*/
				case'url':
					if(!this.isURL(getValue(this.rules_array[i].id))){
						this.error_array.push(this.rules_array[i].error);
						this.e = false;
					}
				break;
				/*--------------------------------------------------------------------------*/
				case'Decimal':
					if(!this.isDecimal(getValue(this.rules_array[i].id))){
						this.error_array.push(this.rules_array[i].error);
						this.e = false;
					}
				break;
				/*--------------------------------------------------------------------------*/
				case'isEqual':
					if(!this.isEqual(getValue(this.rules_array[i].id),getValue(this.rules_array[i].to))){
						this.error_array.push(this.rules_array[i].error);
						this.e = false;
					}
				break;
				/*--------------------------------------------------------------------------*/
			}
		}
	},
	/*--------------------------------------------------------------------------*/
	Apply:function(el){
		this.check();
		if(this.e){
			return true;
		}else{
			var endMsg = this.error_array;
			if(!el){
				alert(this.error_array.toString().replace(/\,/gi,"\n"));
			}else{
				document.getElementById(el).innerHTML = this.error_array.toString().replace(/\,/gi,"<br/>");
			}
			return false;
		}
	}
	/*--------------------------------------------------------------------------*/
});

/*
**
** File 'livepipe.js'
**
*/
/**
 * @author Ryan Johnson <http://syntacticx.com/>
 * @copyright 2008 PersonalGrid Corporation <http://personalgrid.com/>
 * @package LivePipe UI
 * @license MIT
 * @url http://livepipe.net/core
 * @require prototype.js
 */

if(typeof(Control) == 'undefined')
	Control = {};
	
var $proc = function(proc){
	return typeof(proc) == 'function' ? proc : function(){return proc};
};

var $value = function(value){
	return typeof(value) == 'function' ? value() : value;
};

Object.Event = {
	extend: function(object){
		object._objectEventSetup = function(event_name){
			this._observers = this._observers || {};
			this._observers[event_name] = this._observers[event_name] || [];
		};
		object.observe = function(event_name,observer){
			if(typeof(event_name) == 'string' && typeof(observer) != 'undefined'){
				this._objectEventSetup(event_name);
				if(!this._observers[event_name].include(observer))
					this._observers[event_name].push(observer);
			}else
				for(var e in event_name)
					this.observe(e,event_name[e]);
		};
		object.stopObserving = function(event_name,observer){
			this._objectEventSetup(event_name);
			if(event_name && observer)
				this._observers[event_name] = this._observers[event_name].without(observer);
			else if(event_name)
				this._observers[event_name] = [];
			else
				this._observers = {};
		};
		object.observeOnce = function(event_name,outer_observer){
			var inner_observer = function(){
				outer_observer.apply(this,arguments);
				this.stopObserving(event_name,inner_observer);
			}.bind(this);
			this._objectEventSetup(event_name);
			this._observers[event_name].push(inner_observer);
		};
		object.notify = function(event_name){
			this._objectEventSetup(event_name);
			var collected_return_values = [];
			var args = $A(arguments).slice(1);
			try{
				for(var i = 0; i < this._observers[event_name].length; ++i)
					collected_return_values.push(this._observers[event_name][i].apply(this._observers[event_name][i],args) || null);
			}catch(e){
				if(e == $break)
					return false;
				else
					throw e;
			}
			return collected_return_values;
		};
		if(object.prototype){
			object.prototype._objectEventSetup = object._objectEventSetup;
			object.prototype.observe = object.observe;
			object.prototype.stopObserving = object.stopObserving;
			object.prototype.observeOnce = object.observeOnce;
			object.prototype.notify = function(event_name){
				if(object.notify){
					var args = $A(arguments).slice(1);
					args.unshift(this);
					args.unshift(event_name);
					object.notify.apply(object,args);
				}
				this._objectEventSetup(event_name);
				var args = $A(arguments).slice(1);
				var collected_return_values = [];
				try{
					if(this.options && this.options[event_name] && typeof(this.options[event_name]) == 'function')
						collected_return_values.push(this.options[event_name].apply(this,args) || null);
					for(var i = 0; i < this._observers[event_name].length; ++i)
						collected_return_values.push(this._observers[event_name][i].apply(this._observers[event_name][i],args) || null);
				}catch(e){
					if(e == $break)
						return false;
					else
						throw e;
				}
				return collected_return_values;
			};
		}
	}
};

/* Begin Core Extensions */

//Element.observeOnce
Element.addMethods({
	observeOnce: function(element,event_name,outer_callback){
		var inner_callback = function(){
			outer_callback.apply(this,arguments);
			Element.stopObserving(element,event_name,inner_callback);
		};
		Element.observe(element,event_name,inner_callback);
	}
});

//mouseenter, mouseleave
//from http://dev.rubyonrails.org/attachment/ticket/8354/event_mouseenter_106rc1.patch
Object.extend(Event, (function() {
	var cache = Event.cache;

	function getEventID(element) {
		if (element._prototypeEventID) return element._prototypeEventID[0];
		arguments.callee.id = arguments.callee.id || 1;
		return element._prototypeEventID = [++arguments.callee.id];
	}

	function getDOMEventName(eventName) {
		if (eventName && eventName.include(':')) return "dataavailable";
		//begin extension
		if(!Prototype.Browser.IE){
			eventName = {
				mouseenter: 'mouseover',
				mouseleave: 'mouseout'
			}[eventName] || eventName;
		}
		//end extension
		return eventName;
	}

	function getCacheForID(id) {
		return cache[id] = cache[id] || { };
	}

	function getWrappersForEventName(id, eventName) {
		var c = getCacheForID(id);
		return c[eventName] = c[eventName] || [];
	}

	function createWrapper(element, eventName, handler) {
		var id = getEventID(element);
		var c = getWrappersForEventName(id, eventName);
		if (c.pluck("handler").include(handler)) return false;

		var wrapper = function(event) {
			if (!Event || !Event.extend ||
				(event.eventName && event.eventName != eventName))
					return false;

			Event.extend(event);
			handler.call(element, event);
		};
		
		//begin extension
		if(!(Prototype.Browser.IE) && ['mouseenter','mouseleave'].include(eventName)){
			wrapper = wrapper.wrap(function(proceed,event) {	
				var rel = event.relatedTarget;
				var cur = event.currentTarget;			 
				if(rel && rel.nodeType == Node.TEXT_NODE)
					rel = rel.parentNode;	  
				if(rel && rel != cur && !rel.descendantOf(cur))	  
					return proceed(event);   
			});	 
		}
		//end extension

		wrapper.handler = handler;
		c.push(wrapper);
		return wrapper;
	}

	function findWrapper(id, eventName, handler) {
		var c = getWrappersForEventName(id, eventName);
		return c.find(function(wrapper) { return wrapper.handler == handler });
	}

	function destroyWrapper(id, eventName, handler) {
		var c = getCacheForID(id);
		if (!c[eventName]) return false;
		c[eventName] = c[eventName].without(findWrapper(id, eventName, handler));
	}

	function destroyCache() {
		for (var id in cache)
			for (var eventName in cache[id])
				cache[id][eventName] = null;
	}

	if (window.attachEvent) {
		window.attachEvent("onunload", destroyCache);
	}

	return {
		observe: function(element, eventName, handler) {
			element = $(element);
			var name = getDOMEventName(eventName);

			var wrapper = createWrapper(element, eventName, handler);
			if (!wrapper) return element;

			if (element.addEventListener) {
				element.addEventListener(name, wrapper, false);
			} else {
				element.attachEvent("on" + name, wrapper);
			}

			return element;
		},

		stopObserving: function(element, eventName, handler) {
			element = $(element);
			var id = getEventID(element), name = getDOMEventName(eventName);
			
			if (!handler && eventName) {
				getWrappersForEventName(id, eventName).each(function(wrapper) {
					element.stopObserving(eventName, wrapper.handler);
				});
				return element;

			} else if (!eventName) {
				Object.keys(getCacheForID(id)).each(function(eventName) {
					if (isIE && eventName!='load' ) {
						element.stopObserving(eventName);
					}
				});
				return element;
			}

			var wrapper = findWrapper(id, eventName, handler);
			if (!wrapper) return element;

			if (element.removeEventListener) {
				element.removeEventListener(name, wrapper, false);
			} else {
				element.detachEvent("on" + name, wrapper);
			}

			destroyWrapper(id, eventName, handler);

			return element;
		},

		fire: function(element, eventName, memo) {
			element = $(element);
			if (element == document && document.createEvent && !element.dispatchEvent)
				element = document.documentElement;

			var event;
			if (document.createEvent) {
				event = document.createEvent("HTMLEvents");
				event.initEvent("dataavailable", true, true);
			} else {
				event = document.createEventObject();
				event.eventType = "ondataavailable";
			}

			event.eventName = eventName;
			event.memo = memo || { };

			if (document.createEvent) {
				element.dispatchEvent(event);
			} else {
				element.fireEvent(event.eventType, event);
			}

			return Event.extend(event);
		}
	};
})());

Object.extend(Event, Event.Methods);

Element.addMethods({
	fire:			Event.fire,
	observe:		Event.observe,
	stopObserving:	Event.stopObserving
});

Object.extend(document, {
	fire:			Element.Methods.fire.methodize(),
	observe:		Element.Methods.observe.methodize(),
	stopObserving:	Element.Methods.stopObserving.methodize()
});

//mouse:wheel
(function(){
	function wheel(event){
		var delta;
		// normalize the delta
		if(event.wheelDelta) // IE & Opera
			delta = event.wheelDelta / 120;
		else if (event.detail) // W3C
			delta =- event.detail / 3;
		if(!delta)
			return;
		var custom_event = event.element().fire('mouse:wheel',{
			delta: delta
		});
		if(custom_event.stopped){
			event.stop();
			return false;
		}
	}
	document.observe('mousewheel',wheel);
	document.observe('DOMMouseScroll',wheel);
})();

/* End Core Extensions */

//from PrototypeUI
var IframeShim = Class.create({
	initialize: function() {
		this.element = new Element('iframe',{
			style: 'position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);display:none',
			src: 'javascript:void(0);',
			frameborder: 0 
		});
		$(document.body).insert(this.element);
	},
	hide: function() {
		this.element.hide();
		return this;
	},
	show: function() {
		this.element.show();
		return this;
	},
	positionUnder: function(element) {
		var element = $(element);
		var offset = element.cumulativeOffset();
		var dimensions = element.getDimensions();
		this.element.setStyle({
			left: offset[0] + 'px',
			top: offset[1] + 'px',
			width: dimensions.width + 'px',
			height: dimensions.height + 'px',
			zIndex: element.getStyle('zIndex') - 1
		}).show();
		return this;
	},
	setBounds: function(bounds) {
		for(prop in bounds)
			bounds[prop] += 'px';
		this.element.setStyle(bounds);
		return this;
	},
	destroy: function() {
		if(this.element)
			this.element.remove();
		return this;
	}
});
/*
**
** File 'kbPrototypes.js'
**
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////// ELEMENT FUNKTIONEN //////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
var elemMethods = {
	highlightBox: function(element,index){
		var boxIndex = index;
		var childNodes = $(element).childElements();
		childNodes.each(function(value,index){
			if ($(value)){ 
				var style = $H($(value).style);
				if ($(value).id == 'container'+boxIndex){
					$(value).setStyle({borderColor:'#0000ff'});
				} else {
					$(value).setStyle({borderColor:'#000'});
				}
			}
		});
		return $(element);
	},
	
	clone: function(element,options){
		element = $(element);
		if (!(element && element.cloneNode)) return null;
		var result = $(element.cloneNode(true));
		options = (options)?options:{};
		if (element._eventID) Object.extend(result,{_eventID:''});
		if (element._prototypeEventID) Object.extend(result,{_prototypeEventID:''});
		result.writeAttribute(options);
		return $(result);
	},
	
	incAttribute: function(element){
		var element = $(element);	

		var options = Object.extend({
			offset: 0,
			attribute: 'id',
			index:null,
			expression: '(-?[\\d]+)([^\\d]*)$',
			condition:	'.*',
			flags:'',
			init:'0',
			delimiter:'_'
		}, KB.parseArgument(arguments[1] || {}));
		
		options.expression = new RegExp(options.expression)
		var attributeValue = (element.readAttribute(options.attribute) || '').replace(/\[\]/,'');
		
		var search = (element.readAttribute(options.attribute) || '').match(options.expression);
		var index = (attributeValue.match(options.expression))?attributeValue.match(options.expression):options.init;
		var brackets = ((element.readAttribute(options.attribute) || '').match(/\[\]/) || ['']).first();
		// Wenn attribut nicht verfügbar
		if (!element.readAttribute(options.attribute)) return $(element);
		
		if (search && typeof index == 'object'){				
			index = (Object.isNumber(options.index))? options.index : parseInt(search[1] || options.init) ;
			var postfix = (search[2] || "");
			//index = (Object.isNumber(options.index))?options.index:index.match(options.expression);
			var newAttrib = attributeValue.replace(options.expression,(Number(index)+Number(options.offset)) + postfix);
			element.setAttribute(options.attribute,newAttrib);
		} else {
			index = parseInt((Object.isNumber(options.index))?options.index:index) +Number(options.offset);
			element.setAttribute(options.attribute, attributeValue + options.delimiter + index + brackets);
		}		 
		return $(element);
	},
	
	reOrder : function(element){
		var element = $(element);
		if (!element) return null;
		var options = Object.extend({
			className: '',
			attributes:['id'],
			offset:0,
			expression: '(-?[\\d]+)([^\\d]*)$'
		}, KB.parseArgument(arguments[1] || {}));		
		
		element.descendants().concat([element]).findAll(function(e){
			return (e.hasClassName(options.className) && $(e));
		}).each(function(e,index){
			var index = index;
			($(e).descendants() || []).concat([$(e)]).each(function(elem){
				options.attributes.each(function(a){
					
					if (elem.readAttribute(a)) {
						
						elem.incAttribute({attribute:a,index:index,offset:options.offset,expression:options.expression});
					}
				});
				
			});
		});			
		return element;
	},
	
	collectValues: function(element){	
		var resultObject = $H({});
		var element = $(element) || $(document.getElementsByTagName("body").item(0));	

		var options = Object.extend({
			type: 'value'
		}, KB.parseArgument(arguments[1]));
		
		var els = Element.select(element,'input, textarea, select');
		els = (els)?els:[];
		els.concat([element]).each(function(e){
			var elementname = (e.readAttribute('name'))?e.readAttribute('name'):'';
			var value =	(e.value)?e.value : ((e.readAttribute('value'))?e.readAttribute('value'):'');
			var type = (e.readAttribute('type'))?e.readAttribute('type'):'';
			var nodeType = e.tagName.toLowerCase()
			var twoselect = (e.readAttribute('rel') == 'twoselect');
			if (elementname == 'action' || type.search(/^(submit|reset|image|button)$/i) != -1) return;
			if (!(resultObject.get(elementname) || resultObject.get(elementname+'[]'))) resultObject.set(elementname,[]);
				
			if (type == 'checkbox') {
				
				if (e.value!='on') {
					value = (e.checked) ? e.value : '';
				} else {
					value = (e.checked) ? 1 : 0;
				}
			}
			
			
			if (nodeType == 'select'){
				$A(e.options).each(function(option){
					if (option.selected || twoselect ) {
						if (options.type == 'text') resultObject.get(elementname).push(option.innerHTML);
						else resultObject.get(elementname).push(option.value);
					} 
				});				
			} else if ((type.search(/^(radio|checkbox)$/i) != -1 && e.checked) || type.search(/^(radio|checkbox)$/i) == -1) {		
				resultObject.get(elementname).push(value);
			} 
		});
		
		resultObject = resultObject.inject($H({}),function (obj, item){
			var key = (Object.isArray(item.value) && item.value.length > 1 && item.key.search(/\[\]$/i) == -1)? item.key+'[]' : item.key;
			var value = (Object.isArray(item.value) && item.value.length == 1 && item.key.search(/\[\]$/i) == -1)? item.value.first() : item.value;
			if (!key.empty()) obj.set(key,value);
			return obj;
		}).toObject();
		
		return resultObject;
	},
	
	setValues: function (element,values){
		var element = $(element);
		var values = (Object.isArray(values))?values:[values];		
		var options = Object.extend({
			type: 'replace' // replace | append || prepend
		}, ((arguments[2] && Object.isString(arguments[2]) && unescape(arguments[2]).isJSON())? unescape(arguments[2]).evalJSON() : (arguments[2] || {} )));
		
		if (!element) return null;
		
		
		
			
		(element.select('input, textarea, select') || []).concat([element]).each(function(e,index){
			var value = (!Object.isUndefined(values[index]))?values[index]:values.first();
			var elementname = (e.readAttribute('name'))?e.readAttribute('name'):'';
			var type = (e.readAttribute('type'))?e.readAttribute('type'):'';
			var nodeType = e.tagName.toLowerCase();
			if (nodeType.search(/^(select)$/i) == -1 && type.search(/^(checkbox|radio)$/i) == -1) e.value = (options.type == 'append') ? e.value + value : ((options.type == 'prepend')? value + e.value : value);
			else if (nodeType.search(/^(input)$/i) != -1 && e.value == value) e.checked = 'checked';
			else if (nodeType.search(/^(select)$/i) != -1 ){
				$A(e.options).each(function(option){
					if (option.value == value) {
						option.selected = "selected";
					} else {
						option.selected = null;
					}
				});
			}
		});
		
		return $(element);
	},	
	
	clearValues: function(element){
		element = $(element);
		var element = $(element) || $(document.getElementsByTagName("body").item(0));	
		
		(element.select('input, textarea, select') || []).concat([element]).each(function(e){
			var elementname = (e.getAttribute('name'))?e.getAttribute('name'):'';
			var value =	(e.getAttribute('value'))?e.getAttribute('value'):'';
			var type = (e.getAttribute('type'))?e.getAttribute('type'):'';
			var nodeType = e.tagName.toLowerCase()
			var twoselect = (e.readAttribute('rel') == 'twoselect');
			if (elementname == 'action' || type.search(/^(submit|reset|image|button)$/i) != -1) return;
			
			if (nodeType == 'select' && twoselect){
						
			} else if (type == 'checkbox' || type == 'radio') {
				e.checked = false; 
			} else {
				e.value = '';
			}
		});
		
		return element;
	},
	
	toggleContent: function(element){
		var element = $(element).cleanWhitespace();
		var options = Object.extend({
			src: '',
			dst: '' 
		}, KB.parseArgument(arguments[1]));
		
		var value = (element.readAttribute('value'))?element.readAttribute('value'):element.innerHTML;
		var newValue = (value.search(new RegExp(options.src,'i')) > -1)? options.dst : options.src;
		if (element.readAttribute('value')){			
			element.writeAttribute('value',newValue);
		} else {
			element.update(newValue);
		}
		document.fire('content:change');
		return element;
	},
	
	getBgColor: function(element){
		element = $(element);
		
		var options = Object.extend({
			hex: true
		}, ((arguments[1] && Object.isString(arguments[1]) && unescape(arguments[1]).isJSON())? unescape(arguments[1]).evalJSON() : (arguments[1] || {} )));
		
		var element = $(element) || $(document.getElementsByTagName("body").item(0));		
		var result = "transparent";
		if (element.getStyle('backgroundColor') != result){
			result = element.getStyle('backgroundColor'); 
		} else {
			var parent = element.ancestors().find(function(e){
				return e.getStyle('backgroundColor') != result;
			});
			if (parent) result = parent.getStyle('backgroundColor'); 
		}
		
		return result.getColorVersions();
		
	},
	
	/** liefert das erste gefundene eingabe Element zurück 
	 * param Element (nötig für Prototype)
	 */
	firstInput: function(element){
		element = $(element);
		return (['input', 'select', 'textarea'].include(element.tagName.toLowerCase())) ? element : element.descendants().find(function(element){
			return element.type != 'hidden' && !element.disabled &&['input','select','textarea'] .include(element.tagName.toLowerCase());
		});
		
	},
	
	clearFloats:function(element,where){
		element = $(element);		
		var where = (where)? where : 'bottom';
		eval('var options = {'+where+': \'<div class="clear"></div>\'};');
		Element.insert(element,options);
		return $(element);
	},
	
	setCursor: function(el,position) {
		el = $(el);
		if (!el) return null;
		if( el.setSelectionRange) {
			el.focus();
			el.setSelectionRange(position,position);
		} else {
			if(el.createTextRange) {
				range=el.createTextRange();
				range.collapse(true);
				range.moveEnd('character',position);
				range.moveStart('character',position);
				range.select();
			}
		}
		return el;
	} 
	
};

Element.addMethods(elemMethods);

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////// STRING FUNKTIONEN //////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Object.extend(String.prototype,{ 

	/**
	 * formatiert "style.cssText"-attribut-strings nach einem einheitlichen schema;
	 */
	cssTextTrim: function(){
		return((this.replace(/\s*\:\s*/g,":").replace(/\s*\(\s*/g,"(").replace(/\s*\)\s*/g,")").replace(/\s*,\s*/g,",").replace(/\s*;\s*/g,";").replace(/\s+/g," ").replace(/^\s/,"").replace(/\s$/,"").replace(/;+/g,";").replace(/^;/,"").replace(/;$/,"")+";").toLowerCase());
	},
	
	/*
	 * erzeugt, wenn moeglich, 3 varianten von "cssText" sobald eine "#xxyyzz"- bzw. "rgb(aaa,bbb,ccc)"-anweisung in "cssText" gefunden wird;
	 * die varianten sind notwendig, um styles auch dann noch eindeutig identifizieren zu koennen, wenn diese z.b. durch den mozilla intern aus dem
	 * hexadezimalen ":#xxyyzz"- in das dezimale "rgb(aaa,bbb,ccc)"-format umgerechnet, oder falls styles mit mischungen aus diesen beiden formaten
	 * versehen wurden, oder aber wenn anwender die kurzschreibweise fuer das hexadezimale format beutzen - statt "#ffcc00" eben "#fc0";
	 *  varianten:
	 *    rgb(255,204,0)  - /rgb\s*\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/i - mit RegExp.$1,RegExp.$21,RegExp.$3;
	 *    #ffcc00         - /#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})/i                           - mit RegExp.$1,RegExp.$21,RegExp.$3;
	 *    #fc0            - /#([0-9a-f]{1})([0-9a-f]{1})([0-9a-f]{1})([;\s])/i                    - mit RegExp.$1,RegExp.$21,RegExp.$3,RegExp.$4;
	 *
	 * @return der rueckgabewert ist ein objekt mit den eigenschaften "rgb", "hex" und "half"; ("short" ist im javascript-sprachraum ein reserviertes wort)
	 */
	getColorVersions: function(){
		
	    var cssText = this.cssTextTrim(); // formatiert "style.cssText"-attribut-strings nach einem einheitlichen schema;
	    var versions = null;
	    if ((cssText.search(/rgb\s*\(\s*[0-9]{1,3}\s*,\s*[0-9]{1,3}\s*,\s*[0-9]{1,3}\s*\)/i) >= 0) || (cssText.search(/#[0-9a-f]{1}[0-9a-f]{1}[0-9a-f]{1}[;\s]/i) >= 0) || (cssText.search(/#[0-9a-f]{2}[0-9a-f]{2}[0-9a-f]{2}/i) >= 0)) {
	      var regX = null, regX_$1 = "", regX_$2 = "", regX_$3 = "", regX_$4 = "";
	      versions = {};        // alle moeglichen farbschemata:
	      versions.rgb = null;  // - dezimale schreibweise mit "rgb"-praefix;
	      versions.hex = null;  // - klassische hexadezimal-schreibweise;
	      versions.half = null; // - halbe hexadezimal-schreibweise;
	      versions.cleanHex = null; // - klassische hexadezimal-schreibweise ohne #;
	      
	    // - als ausgangsbasis fuer cssText dient die dezimale schreibweise mit "rgb"-praefix;
	    // - diese grundlage muss unter umstaenden erst einmal geschaffen werden;
	    // - die 3 moeglichen varianten werden dann vom ur-style abgeleitet;
	      regX = /#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})/i;
	      while (regX.test(cssText)) {
	        regX.exec(cssText);
	        regX_$1 = parseInt(RegExp.$1,16);
	        regX_$2 = parseInt(RegExp.$2,16);
	        regX_$3 = parseInt(RegExp.$3,16);
	        cssText = cssText.replace(regX,("rgb(" + regX_$1 + "," + regX_$2 + "," + regX_$3 + ")"));
	      }
	      regX = /#([0-9a-f]{1})([0-9a-f]{1})([0-9a-f]{1})([;\s])/i;
	      while (regX.test(cssText)) {
	        regX.exec(cssText);
	        regX_$1 = parseInt((RegExp.$1 + RegExp.$1),16);
	        regX_$2 = parseInt((RegExp.$2 + RegExp.$2),16);
	        regX_$3 = parseInt((RegExp.$3 + RegExp.$3),16);
	        regX_$4 = RegExp.$4;
	        cssText = cssText.replace(regX,("rgb(" + regX_$1 + "," + regX_$2 + "," + regX_$3 + ")" + regX_$4));
	      }
	    //alert("]" + cssText + "[");
	      versions.rgb = cssText; // "cssText"-basis !!
	
	      regX = /rgb\s*\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/i;
	      while (regX.test(cssText)) {
	        regX.exec(cssText);
	        regX_$1 = parseInt(RegExp.$1).toString(16);regX_$1 = ((regX_$1.length == 1) ? ("0" + regX_$1) : (regX_$1));
	        regX_$2 = parseInt(RegExp.$2).toString(16);regX_$2 = ((regX_$2.length == 1) ? ("0" + regX_$2) : (regX_$2));
	        regX_$3 = parseInt(RegExp.$3).toString(16);regX_$3 = ((regX_$3.length == 1) ? ("0" + regX_$3) : (regX_$3));
	        cssText = cssText.replace(regX,("#" + regX_$1 + regX_$2 + regX_$3));
	      }
	      versions.hex = cssText;
	
	      cssText = versions.rgb;
	      while (regX.test(cssText)) {
	        regX.exec(cssText);
	        regX_$1 = parseInt(RegExp.$1).toString(16);regX_$1 = ((regX_$1.length == 1) ? ("0" + regX_$1) : (regX_$1));
	        regX_$2 = parseInt(RegExp.$2).toString(16);regX_$2 = ((regX_$2.length == 1) ? ("0" + regX_$2) : (regX_$2));
	        regX_$3 = parseInt(RegExp.$3).toString(16);regX_$3 = ((regX_$3.length == 1) ? ("0" + regX_$3) : (regX_$3));
	        if ((regX_$1.charAt(0) == regX_$1.charAt(1)) && (regX_$2.charAt(0) == regX_$2.charAt(1)) && (regX_$3.charAt(0) == regX_$3.charAt(1))) {
	          cssText = cssText.replace(regX,("#" + regX_$1.charAt(0) + regX_$2.charAt(0) + regX_$3.charAt(0)));
	        } else {
	          cssText = cssText.replace(regX,("#" + regX_$1 + regX_$2 + regX_$3));
	        }
	      }
	      versions.half = cssText;
		  
		  versions.cleanHex = versions.hex.match(/[\dabcdef]{3,6}/).first();
	    }
	    return versions;
	},
	
	/**
	 * Sucht nach übereinstimmenden Tags im String und gibt den Inhalt des Tags zurück 
	 * @param {String} id
	 * @return String innerHTML
	 */
	getInnerHtml: function (n) {
		secure = 4000; /* SicherheitsZähler der zur Not die schleife abbricht... */
		
		// Wennn String eine ganze HTML Seite enthält wird im Fehlerfall ein leerer String Zurückgegeben,
		// sonst der String selbst
		var errorResult = (this.search(/<html[^>]*>/)  > -1 || this.search(/<head[^>]*>/)  > -1 || this.search(/<body[^>]*>/)  > -1)? '' : this;
		
		typeExpr = new RegExp("<([a-zA-Z]*)[^>]*id=."+n+"[^>]*>");
		if (!n || (n.length == 0) || (this.indexOf(n) == -1) || this.search(typeExpr)  == -1) return (errorResult);
		
		
		type = this.match(typeExpr)[1];	
				
		var front = ''
		var end = ''		
		if (type == null || type == undefined) return false;
		startExpression = new RegExp("<"+type+"[^>]*id=."+n+"[^>]*>");	
		startDivExp = new RegExp("<"+type+"[^>]*>");	
		endDivExp =  new RegExp("</"+type+">");
		
		startTag = new String(this.match(startExpression));
		startIndex = this.search(startTag) + startTag.length;
	
		var txt = new String(this.substr(startIndex)).replace(/<!--.*-->/,'');
		endMatch = txt.match(endDivExp);
		endIndex = 6 + txt.search(endDivExp);
		
		front = txt.substr(0,endIndex);
		end = txt.substr(endIndex);
		var lastIndex = endIndex;
		startMatch = front.split('<'+type);
		frontCount = 0;
		if (startMatch != null){
				startMatch = startMatch.uniq();
				frontCount += startMatch.length-1;
		}
		
		while (frontCount > 0 && --secure){
			endMatch = end.match(endDivExp);
			endIndex = 6 + end.search(endDivExp);
			lastIndex += endIndex;
			front = end.substr(0,endIndex);
			end = end.substr(endIndex);
		
			startMatch = front.split('<'+type);
			if (startMatch != null){
				startMatch = startMatch.uniq();
				frontCount += startMatch.length-1;
			}		
			frontCount--;
		}
		
		result = txt.substr(0,lastIndex-('</'+type+'>').length);
		
		return result;
	},
	
	/**
	 * Wie PHP-Addslashes
	 */
	addslashes: function() {
		var str = this;
		str = str.replace(/\'/g,'\\\'');
		str = str.replace(/\"/g,'\\"');
		str = str.replace(/\\/g,'\\\\');
		str = str.replace(/\0/g,'\\0');
		return str;
	},
	
	/**
	 * Wie PHP-Stripslashes
	 */
	stripslashes: function() {
		var str = this;
		str=str.replace(/\\'/g,'\'');
		str=str.replace(/\\"/g,'"');
		str=str.replace(/\\\\/g,'\\');
		str=str.replace(/\\0/g,'\0');
		return str;
	},
	
	/**
	 * Maskiert einen String für new RegEXP
	 */
	maskRegExpString: function() { // nicht fuer netscape 4;
 		return this.replace(/([\^\$\.\*\+\?\=\!\:\|\\\/\(\)\[\]\{\}])/g,"\\$1");
   	},
	
	/**
	 * Wandelt Newlines in bBRs um
	 */
	nl2br: function() {
		return this.replace(/(\r\n)|(\r)|(\n)/gi, "<br />");
	},
	
	/**
	 * Wandelt bBRs in Newlines um
	 */
	br2nl: function(){
		return this.replace(/<br\s*\/?>/gi, "\n");
	}
});


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////// HASH FUNKTIONEN //////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Object.extend(Hash.prototype,{ 
	without:function(){
		var values = $A(arguments);
		return this.each(function(obj){
			eval ('var object = {'+obj.key+':obj.value}');
			if (values.include(obj.value) || values.include(object)) this.unset(obj.key);
		}.bind(this));
	}
});

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////// WRAPPER FUNKTIONEN //////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 * Element.update() WRAPPER das event "content:changed" wird abgefeuert sobald der Inhalt geändert wird...
 */
 
 
Element.update = Element.update.wrap(
	function(proceed, element, contents) {
		var scripts = contents.extractScripts().partition(function(script){return (script.search(/(KuborghEvents\.require)|(\_form\_element\.init)/) >= 0)});
		var contents = contents.stripScripts();
		scripts[0].findAll(function(script){
			return !KB.Browser.IE || !/^\<\!\-\-/.test(script);
		}).map(function(script) { return eval(script) });
		element = proceed(element, contents);
		scripts[1].findAll(function(script){
			return !KB.Browser.IE || !/^\<\!\-\-/.test(script);
		}).map(function(script) { return eval(script) });
		if ($(element)) $(element).fire("content:changed");
		if ($(element) && scripts[0].size() || scripts[1].size()) $(element).fire("content:loaded");    
		return $(element);
	}
);

Element.remove = Element.remove.wrap(
	function(proceed, element) {
		var options = Object.extend({
			
		}, KB.parseArgument(arguments[1] || {}));	
		
		if (!element || !element.parentNode) return null;
		if (element && $(element.id+'_overlay')) $(element.id+'_overlay').remove();
		return proceed(element);
	}
);

Element.select = Element.select.wrap(
	function(proceed, element, contents) {
		if (KB.Browser.WebKit || KB.Browser.MobileSafari) {
			return (element.id)? $$('[id="' + element.id + '"] '+contents) : $$(element.tagName.toLowerCase() + '.' + $A(element.classNames()).first() + ' ' + contents);		
		} else {
			return proceed(element, contents);
		}
	}
);

Template.prototype.evaluate = Template.prototype.evaluate.wrap(
	function(proceed, object) {
		if (Object.isFunction(object.toTemplateReplacements))
			object = object.toTemplateReplacements();
		
		if (object.button_cancel && !object.button_cancel.match(/js_cancel/)) object.button_cancel = '<span class="js_cancel">' + object.button_cancel + '</span>';		
		if (object.button_ok && !object.button_ok.match(/js_ok/)) object.button_ok = '<span class="js_ok">' + object.button_ok + '</span>';	
		
		return proceed(object);
	}
);

/*
**
** File 'kb.js'
**
*/
/**
 * Kuborgh Klasse...
 */
var KB = { };

Object.extend(KB, {
	Version: '1.0.0.0',
	Browser: Object.extend(Prototype.Browser,{
		IE6: ((parseInt(navigator.appVersion) == 4) && (navigator.userAgent.toLowerCase().indexOf("msie 6.") != -1)),
		IE7: ((parseInt(navigator.appVersion) == 4) && (navigator.userAgent.toLowerCase().indexOf("msie 7.") != -1))
	}),
	
	Layout: null,
	CornerSettings: {
		tl: { radius: 10 },
		tr: { radius: 10 },
		bl: { radius: 10 },
		br: { radius: 10 },
		antiAlias: true,
		autoPad: true,
		validTags: ["div"]
	},
	CornerBoxes : [],
	Timeranges : [],
	
	Lightbox: null,
	Validate: new Validate()
});

KB.Methods = (function(){

	var currentLayer = null
	
	
	function parseResponse(response){
		
		var result = {
			type: arguments[1] || 'Error',
			message: '',
			content: ''
		}
		if (response && Object.isString(response) && response.isJSON()){
			Object.extend(result, response.evalJSON() || {});
		} else if (response && Object.isString(response) && unescape(response).isJSON()){
			Object.extend(result, unescape(response).evalJSON() || {});
		} else if (response && Object.isString(response) && !unescape(response).isJSON()){
			var type = (unescape(response).search(/^([a-zA-Z]*);/) == 0)? unescape(response).match(/^([a-zA-Z]*);/)[1] : 'Success';
			var message = (unescape(response).search(/^[a-zA-Z]*;[a-zA-Z]*;/) == 0)? unescape(response).match(/^[a-zA-Z]*;([a-zA-Z]*);/)[1] : '';
			var content = (unescape(response).search(/^[a-zA-Z]*;[a-zA-Z]*;/) == 0)? unescape(response).replace(/^^[a-zA-Z]*;[a-zA-Z]*;/g,''): unescape(response);
			Object.extend(result, {
				type: type,
				message: message,
				content: content
			});
		} else {
			Object.extend(result, response || {});
		}
		result.type	= result.type.camelize();
		result.content = (result.content.search(/\*#\*#\*#\*#\*#\*#\*/) > -1)? result.content.replace(/\*#\*#\*#\*#\*#\*#\*/g, '\\') : result.content;
		
		result = $H(result).inject($H({}),function (obj, item){
			obj.set(item.key,(Object.isString(item.value))?unescape(item.value):((Object.isNumber(item.value))?new String(item.value).toString():item.value));
			return obj;
		}).toObject();
		
		
		return result;
	}	
	
	return {
		
		/**
		 * Liefert das Object fï¿½r das ï¿½bergebene Argument zurï¿½ck (Kann JSON, Object oder undefined sein)
		 * @param {Object} argument
		 */
		parseArgument: function (argument){
			return ((argument && Object.isString(argument) && unescape(argument).isJSON()) ? unescape(argument).evalJSON() : (argument || {}));
		},
		
		/**
		 * Elemente Ein- bzw. Ausblenden
		 * @param {Array || Element} elements Array von elementen oder einzelnes Element
		 * @param {Object} options new Effect.SlideLeftIn('demo-effect', {duration: 2, queue: 'end'});
		 */
		toggle: function(elements){
			if (!(Object.isArray(elements) || $(elements))) 
				return false;
			if (!Object.isArray(elements) && $(elements)) 
				elements = [$(elements)];
				
			
			
			// Extend Default Options
			var options = Object.extend({
				duration: 0.7, // duration of the effect in seconds, given as a float.
				delay: 0.0, // Sets the number of seconds to wait before the effect actually starts.
				effect: 'Fade', // Welcher Effect: (Fade, Blind, Slide)
				force:'', // einblenden bzw. ausblenden erzwingen... (hide | show | appear | fade)
				
				maxOpacity:0.9,				
				remove:false,
				queue:{scope:'global'}, // um auf die queue zuzugreifen...
				beforeStart: Prototype.emptyFunction,  	// Wid aufgerufen, bevor der Effekt gestartet wird.
				beforeUpdate: Prototype.emptyFunction,	// Wird bei jedem Durchlauf des Effekts vor Neuzeichnen des Elements aufgerufen.
				afterUpdate: Prototype.emptyFunction,	// Wird bei jedem Durchlauf des Effekts nach Neuzeichnen des Elements aufgerufen.
				afterFinish: Prototype.emptyFunction	// Wird am Ende des Effektes, nach dem letzten Mal Neuzeichnen aufgerufen. 
				
			}, KB.parseArgument(arguments[1]));
			
			if (Effect.Queue.effects.size() > 0 && options.force.empty()) return;
			
			
			var effectMapping = $H({
				Fade: ['Fade', 'Appear'],
				Opacity: ['Opacity', 'Opacity'],
				Blind: ['BlindUp', 'BlindDown'],
				Slide: ['SlideUp', 'SlideDown'],
				SlideL: ['SlideLeftOut', 'SlideRightIn'],
				SlideR: ['SlideRightOut', 'SlideLeftIn']
			});
			
			
			
			var usedEffect = (effectMapping.get(options.effect)) ? effectMapping.get(options.effect) : effectMapping.get('Fade');
			
			var effects = [];
			elements.each(function(e){
				e = $(e);
				if (!e) return;
				
				var useOpacity = (e.getStyle('opacity') != null && options.effect == 'Fade' && !/((fade)|(appear))/i.test(options.force));
				
				var effect = (useOpacity)?'Opacity':options.effect;
				var maxOpacity = (useOpacity && e.getStyle('opacity') > 0.1)?e.getStyle('opacity'):options.maxOpacity;
				var effectObj = (useOpacity)?effectMapping.get('Opacity'):usedEffect;
				
				var id = e.readAttribute('id');		
				var overlay = (id && !id.include('overlay'))?$(id+'_overlay'):null;
				// Fï¿½r Effect.Opacity zusï¿½tzlich zu visible den test ob die opacity des Elements > 0.05 ist
				var visible = e.visible() && (e.getStyle('opacity') == null || e.getStyle('opacity') > 0.09)
				if ((visible && options.force == 'show') || (!visible && options.force == 'hide')) return;
				
				if (effect == 'Opacity' && e.getStyle('display') == 'none') {
					e.setStyle({ 
						opacity: 0.0,
						display:"block"
					});
				}
				
		
				if ((visible && !/((show)|(appear))/i.test(options.force) )|| /((fade)|(hide))/i.test(options.force)) {
					//	effects.push(new Effect.Fade(e, { sync: true, duration: 0.001 }));
					eval('effects.push(new Effect.' + effectObj[0] + '(e, { sync: true, options: options.duration ' + ((effect == 'Opacity')?',transition: Effect.Transitions.linear,from: ' + maxOpacity + ', to:  0.001 ':'') + ', queue: options.queue, object:e, afterFinish: function(){this.object.fire(\'toggle:hide\');} }));');
					if (overlay) eval('effects.push(new Effect.' + effectObj[0] + '(overlay, { sync: true, options: options.duration ' + ((effect == 'Opacity')?',transition: Effect.Transitions.linear,from: ' + maxOpacity + ', to:  0.001 ':'') + ', queue: options.queue, object:e, afterFinish: function(){this.object.fire(\'toggle:hide\');}}));');
					if (options.remove) {
						window.setTimeout(function(){
							this.remove();
							if (arguments[0]) arguments[0].remove();
						}.bind(e,overlay), (options.duration + 0.05 + options.delay)*1000);						
					}
				} else if ((!visible && !/((fade)|(hide))/i.test(options.force) ) || /((show)|(appear))/i.test(options.force)){
					//	effects.push(new Effect.Appear(e, { sync: true, duration: 0.001 }));
					eval('effects.push(new Effect.' + effectObj[1] + '(e, { sync: true, duration: options.duration ' + ((effect == 'Opacity')?',transition: Effect.Transitions.linear,from: 0.01, to: ' + maxOpacity : '') + ', queue: options.queue, object:e, afterFinish: function(){this.object.fire(\'toggle:show\');} }));');
					if (overlay) eval('effects.push(new Effect.' + effectObj[1] + '(overlay, { sync: true, duration: options.duration ' + ((effect == 'Opacity')?',transition: Effect.Transitions.linear,from: 0.01, to: ' + maxOpacity : '') + ', queue: options.queue, object:e, afterFinish: function(){this.object.fire(\'toggle:show\');} }));');
				}
			});			
			new Effect.Parallel(effects, options);
			
			document.fire('content:changed');
		},
		
		/**
		 * Request Wrapper...
		 * @param {Object} options
		 */
		request: function(){
			var options = Object.extend({
				url: '/index.php', // Url for the Request
				action: '', // Action for the Request
				id: '', // Id of the Element which will be replaced
				element: '', // Id of the Element which will be replaced
				params: {}, // Params Object
				collectAll: null, // Collect all Values 
				collectIds: [], // Collect Values in given Id's
				append: false, // Don't replace Ccontent... append it			
				update: true, // if set to false nothing will be updated
				clean: false, // clean up the form...				
				success_extra: '', 
				successFunc: Prototype.emptyFunction, 
				onSuccess: Prototype.emptyFunction, 
				failureFunc: Prototype.emptyFunction, 
				onFailure: Prototype.emptyFunction, 
				onLoad: Prototype.emptyFunction, 
				beforeStart: Prototype.emptyFunction, 
				functionParams: {}, 
				template: '#{content}', 
				infoElement: '',
				effectElement: '',
				errorElement: 'global_error_stack_output',
				infoElementContainer: '',
				errorElementContainer: 'global_error_stack_output_container',
				// Effect Zeug
				effect: false,
				effectOptions:{},
				overlay: true,
				overlayOptions: {},
				keepOverlay: false,
				indicator: null,
				duration: 0.7,
				// Deprecated
				doRedirect: false,
				// redirectOnSuccess (True, false)
				redirectOnSuccess: false,
				redirectURL: window.location.href,
				redirectOverlay: false
			}, KB.parseArgument(arguments[0]) || {});
			
			if (options.onSuccess != Prototype.emptyFunction) options.successFunc = options.onSuccess;
			if (options.onFailure != Prototype.emptyFunction) options.failureFunc = options.onFailure;
			if (options.onLoad != Prototype.emptyFunction) options.beforeStart = options.onLoad;
			options.template =  new Template(options.template);
			options.infoElement = ($(options.errorElement))? $(options.errorElement) : $(options.infoElement);
			options.infoElementContainer = ($(options.errorElementContainer))? $(options.errorElementContainer) : $(options.infoElementContainer);
			if (!options.infoElementContainer && options.infoElement) options.infoElementContainer = options.infoElement;
			//if (options.infoElementContainer) options.infoElementContainer.hide();
			
			var element = ($(options.id))?$(options.id):$(options.element);
			if (!element) options.update = false;
			effectElement = $(options.effectElement);
			if (!effectElement) effectElement = element;
			
			options.overlayOptions = Object.extend({
				bgColor : (effectElement) && effectElement.getBgColor() ? '#'+effectElement.getBgColor().cleanHex : '',
				indicator: options.indicator
			},options.overlayOptions);			
			var overlay = (options.overlay)?((effectElement && options.overlay)? KB.overlay(effectElement,options.overlayOptions) : null):null;
			// Post Parameter zusammensetzen...
			// Alle inputs innerhalb der Elemente die ï¿½ber collectIds angegeben sind
			if (!Object.isArray(options.collectIds)) options.collectIds = [options.collectIds];
			
			if (Object.isArray(options.collectIds)) {
				options.collectIds.each(function(el){
					collectElement = $(el);
					if (collectElement) {
						options.params = Object.extend(collectElement.collectValues(),options.params);
						if (options.clean) collectElement.clearValues();
					}
				});
			}
			
			// alles holen (jeder Input im Document)
			if (options.collectAll) {
				options.params = Object.extend($(document.getElementsByTagName("body").item(0)).collectValues(), options.params);
				if (options.clean) $(document.getElementsByTagName("body").item(0)).clearValues();
			}
		
			// action setzen
			if (!options.action.empty()) {
				Object.extend(options.params, {
					action: unescape(options.action).match(/^[^&]*/).first()
				});
				// fals an action weitere parameter angehï¿½ngt wurden...
				if (unescape(options.action).search(/&/) != -1){
					Object.extend(options.params, unescape(options.action).match(/&.*/).first().parseQuery());
				}
			}	
					
			options.params = $H(options.params);
			
			if (!element && options.params.get('destId') && $(options.params.get('destId'))) {
				element = $(options.params.get('destId'));
				options.id = $(options.params.get('destId'));
			}
			
			var opt = {
				// Use POST
				method: 'post',
				
				contentType:  'application/x-www-form-urlencoded',
				encoding:     'utf-8',
				// Send this lovely data
				postBody: options.params.toQueryString(),
				// Handle successful response
				onSuccess: function(t){
					var options = this;
					var element = ($(options.id))?$(options.id):$(options.element);
					var response = parseResponse(t.responseText);
					options.functionParams = Object.extend(options.functionParams,{
						response:response
					});
					
					// Redirect im Erfogsfall
					if (response.type == "Success" && options.redirectOnSuccess && !options.redirectURL.empty()){
						if (options.redirectOverlay){
							var windowOverlay = KB.overlay('document');
							KB.toggle(windowOverlay,{
								duration: options.duration,
								effect: 'Fade',
								force: 'show'
							});
						}
						setTimeout(function(){
							self.location=options.redirectURL;
						}, options.duration * 1100);
						return;
					}
					
					// Error Handling...
					if (options.infoElement && !response.message.empty()) {
						
						var queue = Effect.Queues.get('info');
						queue.each(function(effect) { 
							effect.cancel(); 
						});
						
						options.infoElement.classNames().each(function(e){
							if (e.include('errorStack')) options.infoElement.removeClassName(e);
						});
						
						Element.update(options.infoElement, response.message);
						options.infoElement.addClassName('errorStack'+response.type);
						KB.toggle(options.infoElementContainer,Object.extend({
							effect: options.effect,
							force: 'show',
							delay: 0.5,
							queue:{scope:'info'}
						},options.effectOptions));
							
						KB.toggle(options.infoElementContainer,Object.extend({
							effect: options.effect,
							force: 'hide',
							delay: 10.0,
							queue:{scope:'info'}
						},options.effectOptions));
								
					} 
					
					
					
					if (options.update) {
						if (response.type != 'Error'){					
							if (response.content && element) {
								
								response.content = (options.append) 
									? element.innerHTML + options.template.evaluate(response)
									: options.template.evaluate(response);
								response.content = 	response.content.getInnerHtml(element.readAttribute('id'));
								Element.update(element, response.content);															
							} 
						}						
					}
					if (effectElement) {
						if (options.effect && !KB.Browser.IE6) KB.toggle(effectElement,Object.extend({
							duration: options.duration,
							effect: options.effect,
							force: 'show'
						},options.effectOptions));
						if (options.overlay && !options.keepOverlay) {
							KB.toggle(overlay,Object.extend({
								duration: options.duration,
								effect: 'Fade',
								force: 'hide'
							},options.effectOptions));
							window.setTimeout(function(){
								if (overlay) overlay.remove();
							}, options.duration * 1100);	
						}
					}
					if (Object.isString(options.success_extra) && options.success_extra.length > 0 && response.type != 'Error') {
						eval(options.success_extra);
					}
										
					// Own functions for success/failure
					options.functionParams = Object.extend(options.functionParams,{
						response:Object.extend({
							template:options.template
						},response),
						overlay : overlay,
						request : options.params.toObject()
					});
					if (Object.isFunction(options.successFunc) && response.type == 'Success'){
						options.successFunc(element,options.functionParams);
		
					}
					if (Object.isFunction(options.failureFunc) && response.type != 'Success'){
						options.failureFunc(element,options.functionParams);
					}
					
				}.bind(options),
				// Handle 404
				on404: function(t){
					var options = this;
					var response = parseResponse(t.statusText,'Error');
					// Own functions for success/failure
					options.functionParams = Object.extend(options.functionParams,{
						response:Object.extend({
							template:options.template
						},response)
					});
					if (Object.isFunction(options.failureFunc) && response.type != 'Success'){
						options.failureFunc(element,functionParams);
					}
				}.bind(options),
				
				// Handle other errors
				onFailure: function(t){
					var options = this;
					var response = parseResponse(t.statusText,'Error');
					// Own functions for success/failure
					options.functionParams = Object.extend(options.functionParams,{
						response:Object.extend({
							template:options.template
						},response)
					});
					if (Object.isFunction(options.failureFunc) && response.type != 'Success'){
						options.failureFunc(element,functionParams);
					}
				}.bind(options)
			}
			
			if (effectElement) {
				if (options.effect && !KB.Browser.IE6) KB.toggle(effectElement,Object.extend({
					duration: options.duration,
					effect: options.effect,
					force: 'hide'
				},options.effectOptions));
				if (options.overlay) KB.toggle(overlay,Object.extend({
					duration: options.duration,
					effect: 'Fade',
					force: 'show'
				},options.effectOptions));
			} 
		
			options.beforeStart(element,options);
			
			setTimeout(function(){
				// Anfrage nicht per Ajax senden, sondern per self.location
				// 
				if (options.doRedirect) {
					self.location=options.url+'?'+opt['postBody'];
				} else {
					new Ajax.Request(options.url, opt);
				}
			}, options.duration * 1100);			
			
		},
		
		/**
		 * Erstellt ein Overlay fï¿½r das angegebene Element im DOM z.B. verwendet fï¿½r 
		 * @param {Object} element
		 * @param {Object} options 
		 */
		overlay:function(element){
			var bodyOverlay = (element == 'document' || element == 'body');
			var elem = (!bodyOverlay)? $(element) : $(document.getElementsByTagName("body").item(0));
			if (!elem) return null;
			var options = Object.extend({
				bgColor: null,	
				close: false,
				dimensions: null,
				indicatorDimensions: {width:16,height:16},
				indicator: null,
				className:'overlay',
				opacity:0.8,
				id:(bodyOverlay)?'window':elem.id
			}, KB.parseArgument(arguments[1]) || {});
			
			var overlayid = options.id + '_overlay';
			
			
			
			// IE Bugfix Overlay jedesmal neu erstellen und das alte lï¿½schen
			if (elem && $(overlayid) && (KB.Browser.IE || KB.Browser.IE6) && !bodyOverlay) {
				$(overlayid).remove();
			}
			
			if (elem && !$(overlayid)) {				
				var objOverlay = new Element("div",{id:overlayid,style:'position:absolute;display:none;z-index:999'});
		
				var indicator = (options.indicator && Object.isString(options.indicator) && !options.indicator.empty())		
					? new Element('img',{src:options.indicator,id: elem.id+'_overlay_loader'})
					: null;
				if (indicator) objOverlay.insert({top:indicator});	
				else objOverlay.insert({top: new Element("div")});			
				$(document.getElementsByTagName("body").item(0)).insert({bottom: objOverlay});
				
				objOverlay.clonePosition(elem);
				
				
				if (bodyOverlay){
					var dim = KB.getPageSize();
					//var dim = $(document.getElementsByTagName("body").item(0)).getDimensions();
					var height1 = $(document.getElementsByTagName("body").item(0)).getHeight();
					var height2 = $(document.getElementsByTagName("body").item(0)).firstDescendant().getHeight();
	
					var height = (height1 > height2)?height1 :height2;
					height = (dim[1] > height)?dim[1] :height;
					
					objOverlay.setStyle({
						width: '100%',
						height:height+'px'
					});
					//var dim = $(document.getElementsByTagName("body").item(0)).getDimensions();
					//var height1 = $(document.getElementsByTagName("body").item(0)).getHeight();
					//var height2 = $(document.getElementsByTagName("body").item(0)).firstDescendant().getHeight();
					
					//objOverlay.setStyle({
					//	width:dim.width+'px',
					//	height:((height1 > height2)?height1 :height2)+'px'
					//});
				}
				
				
				
				var cDimensions = objOverlay.getDimensions();	
				if (!cDimensions.width && !cDimensions.height) cDimensions = elem.getDimensions();	
				var lDimensions = (options.indicator)?indicator.getDimensions():{width:0,height:0};		
				if (lDimensions.width == 0) lDimensions = options.indicatorDimensions;
				
				if (options.indicator) {
					var indicatorTop = 0;
					if (bodyOverlay){
						var dim = KB.getPageSize();
				        var arrayPageScroll = document.viewport.getScrollOffsets();
				        indicatorTop = arrayPageScroll[1] + ((document.viewport.getHeight()- lDimensions.height) / 2);
						indicatorTop = dim.windowHeight/2 - lDimensions.height / 2;
						if (parseInt (navigator.appVersion) >3 ) {
							if (navigator.appName.indexOf ('Microsoft')!= -1) {
								indicatorTop = arrayPageScroll[1] + ((document.body.offsetHeight- lDimensions.height) / 2);
							}
						}
					} else {
						indicatorTop = (cDimensions.height - lDimensions.height)/2;
					}
					indicator.absolutize();
					indicator.setStyle({
						left: (cDimensions.width - lDimensions.width)/2+'px', 
						top: indicatorTop +'px',
						width: lDimensions.width+'px',
						height: lDimensions.height+'px'
					});
					
				}
				
				var changeContent = function(event){
					// Overlayposition anpassen						
					if (bodyOverlay){
						var dim = KB.getPageSize();
						var height1 = $(document.getElementsByTagName("body").item(0)).getHeight();
						var height2 = $(document.getElementsByTagName("body").item(0)).firstDescendant().getHeight();
		
						var height = (height1 > height2)?height1 :height2;
						height = (dim[1] > height)?dim[1] :height;
						//var dim = $(document.getElementsByTagName("body").item(0)).getDimensions();
						//var height1 = $(document.getElementsByTagName("body").item(0)).getHeight();
						//var height2 = $(document.getElementsByTagName("body").item(0)).firstDescendant().getHeight();
						this.setStyle({
							width: '100%',
							height:height+'px'
						});
					} else {
						this.clonePosition(event.element());
					}					
					
					// indicatorposition in mitte setzen...
					if ($(arguments[1])){
						var cDimensions = this.getDimensions();
						var lDimensions = arguments[1].getDimensions();
						var indicatorTop = 0;
						if (bodyOverlay){
							var arrayPageScroll = document.viewport.getScrollOffsets();
							indicatorTop = arrayPageScroll[1] + ((document.viewport.getHeight()- lDimensions.height) / 2);
							indicatorTop = dim.windowHeight/2 - lDimensions.height / 2 -  dim.windowHeight/10;
							/*if (parseInt (navigator.appVersion) >3 ) {
								if (navigator.appName.indexOf ('Microsoft')!= -1) {
									indicatorTop = arrayPageScroll[1] + ((document.body.offsetHeight- lDimensions.height) / 2);
								}
							}*/
						} else {
							indicatorTop = (cDimensions.height - lDimensions.height)/2;
						}
						arguments[1].absolutize();
						arguments[1].setStyle({
							left: (cDimensions.width - lDimensions.width)/2+'px', 
							top: indicatorTop +'px',
							//position: (KB.Browser.IE)?'absolute':'fixed'
							position: 'absolute'
						});
					
					}
				}
		
				if (bodyOverlay){
					// Start Observer to content:changed to resize the overlay if content changes
					document.stopObserving('content:changed');	
					document.observe('content:changed', changeContent.bindAsEventListener(objOverlay,indicator));		
				} else {
					// Start Observer to content:changed to resize the overlay if content changes
					$(elem).stopObserving('content:changed');	
					$(elem).observe('content:changed',  changeContent.bindAsEventListener(objOverlay,indicator));		
					objOverlay.observe('overlay:changed',  changeContent.bindAsEventListener(objOverlay,indicator));	
				}
				if (indicator && !indicator.visible()) new Effect.Appear(indicator,{duration:0.5});	
			
				
				if (options.bgColor && /\#[a-fA-F0-9]{3,6}|(transparent)/.test(options.bgColor)) objOverlay.setStyle({backgroundColor: options.bgColor.match(/\#[a-fA-F0-9]{3,6}|(transparent)/).first()});
			
				if (options.opacity) objOverlay.setStyle({opacity: options.opacity });
			
				if (options.className) objOverlay.addClassName(options.className);
			
				this.currentLayer = objOverlay;
				
			} else if ($(overlayid)){
				this.currentLayer = $(overlayid);			
				var indicator = this.currentLayer.select('img').first();
				
				
						
				if (bodyOverlay){	
					document.fire("content:changed");
					var dim = KB.getPageSize();
					//var dim = $(document.getElementsByTagName("body").item(0)).getDimensions();
					//var height1 = $(document.getElementsByTagName("body").item(0)).getHeight();
					//var height2 = $(document.getElementsByTagName("body").item(0)).firstDescendant().getHeight();
					this.currentLayer.setStyle({
						width:dim[0]+'px',
						height:dim[1]+'px'
					});
				}
				if (indicator && !indicator.visible()) new Effect.Appear(indicator,{duration:0.5});
			}
			this.currentLayer.indicator = function(){
				return this.select('img').first();
			}.bind(this.currentLayer );
			
			
			
			return this.currentLayer;
		},
		
		getLayout: function(){
			return (KB.Layout)?KB.Layout:KB.setLayout();
		},
		
		setLayout: function(){
			KB.Layout = {};
			
			var options = Object.extend({
				header: 'header',
				content: 'content',
				footer: 'footer'
			}, KB.parseArgument(arguments[0]) || {});		
			
			var ps = KB.getPageSize();
			
			Object.extend(KB.Layout,{
				header:  KB.Layout.header ? KB.Layout.header : (($(options.header))? $(options.header).getDimensions()  : {width:0,height:0}),
				footer:  KB.Layout.footer ? KB.Layout.footer : (($(options.footer))? $(options.footer).getDimensions()  : {width:0,height:0}),
				content: (($(options.content))? $(options.content).getDimensions() : {width:0,height:0}),
				viewport: {width: ps.windowWidth, height: ps.windowHeight}
			});
			
			$H(options).findAll(function(object){return ($(object.value) != null)}).each(function(object){
				var relevantStyles = $H($(object.value).getStyles()).findAll(function(style){return style.key.match(/((margin)|(border))/i);});	
				var w = relevantStyles.findAll(function(style){return style.key.match(/(left)|(right)/i)  && !style.key.match(/(color)/i);}).collect(function(s){return s.value.replace(/[^\d]*/g,'');}).inject(0, function(acc, n) { return Number(acc) + Number(n); });		
				var h = relevantStyles.findAll(function(style){return style.key.match(/(top)|(bottom)/i) && !style.key.match(/(color)/i) ;}).collect(function(s){return s.value.replace(/[^\d]*/g,'');}).inject(0, function(acc, n) { return Number(acc) + Number(n); });			
				eval('KB.Layout.'+object.key+'.width = KB.Layout.'+object.key+'.width + '+w+';');
				eval('KB.Layout.'+object.key+'.height = KB.Layout.'+object.key+'.height + '+h+';');
			});
			
			return KB.Layout;
		},
		
		addCorners: function(el) {
			var element = $(el);
			if (!element || KB.CornerSettings.validTags.indexOf(element.tagName.toLowerCase()) < 0 || !element.id) return;
			KB.CornerBoxes.push(new curvyCorners(KB.CornerSettings, element.id));
		},
		
		roundCorners: function(){
			KB.CornerBoxes.each(function(el){
				el.applyCornersToAll();
			});
		},
		
		getPageSize: function() {
	        
	     var xScroll, yScroll;
		
		if (window.innerHeight && window.scrollMaxY) {	
			xScroll = window.innerWidth + window.scrollMaxX;
			yScroll = window.innerHeight + window.scrollMaxY;
		} else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac
			xScroll = document.body.scrollWidth;
			yScroll = document.body.scrollHeight;
		} else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
			xScroll = document.body.offsetWidth;
			yScroll = document.body.offsetHeight;
		}
		
		var windowWidth, windowHeight;
		
		if (self.innerHeight) {	// all except Explorer
			if(document.documentElement.clientWidth){
				windowWidth = document.documentElement.clientWidth; 
			} else {
				windowWidth = self.innerWidth;
			}
			windowHeight = self.innerHeight;
		} else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
			windowWidth = document.documentElement.clientWidth;
			windowHeight = document.documentElement.clientHeight;
		} else if (document.body) { // other Explorers
			windowWidth = document.body.clientWidth;
			windowHeight = document.body.clientHeight;
		}	
		
		// for small pages with total height less then height of the viewport
		if(yScroll < windowHeight){
			pageHeight = windowHeight;
		} else { 
			pageHeight = yScroll;
		}
	
		// for small pages with total width less then width of the viewport
		if(xScroll < windowWidth){	
			pageWidth = xScroll;		
		} else {
			pageWidth = windowWidth;
		}
		
		var res = $H({
				windowWidth: windowWidth,
				windowHeight: windowHeight,
				pageWidth: pageWidth,
				pageHeight: pageHeight
		});
		res.set('0',pageWidth);
		res.set('1',pageHeight);
		return res.toObject();
	},
		
		confirm: function(element){
			var options = Object.extend({
				onOk:Prototype.emptyFunction,
				onCancel:Prototype.emptyFunction,
				onLoad:Prototype.emptyFunction,
				cancelObj:[],
				okObj:[]
			}, KB.parseArgument(arguments[1]) || {});
			
			if (!$(element) && Object.isString(element)) {
				options.onLoad(element,options);
				if (confirm(element)){
					options.onOk(element,options);
				} else {
					options.cancelObj(element,options);
				}				
			}
			
			if (!$(element)) return null;
			var element = $(element);
			var dim = element.getDimensions();
			var overlay = KB.overlay('document',{
				indicator:null,
				bgColor:null
			});
			
			
			element.setStyle({
				left:((KB.getLayout().viewport.width - dim.width)/2)+'px',
				top:((KB.getLayout().viewport.height - dim.height)/2)+'px',
				zIndex:1001,
				position:((KB.Browser.IE || KB.Browser.IE6)?'absolute':'fixed')
			});
			
			overlay.insert({after:$(element)});
		
			
			
			overlay.show();
			element.show();
			options.onLoad(element,options);
			
			options.cancelObj.push(overlay);
			options.cancelObj.each(function(el){
				if ($(el)) {
					Event.observe(el,'click',function(){						
						overlay.hide();
						element.hide();
						options.onCancel(element,options);
						options.cancelObj.concat(options.okObj).findAll(function(el){return $(el);}).each(function(el){Event.stopObserving(el,'click');});
					});
				}
			});
			
			options.okObj.each(function(el){
				if ($(el)) {
					Event.observe(el,'click',function(){
						if ((options.onOk == Prototype.emptyFunction)?true:options.onOk(element,options)){
							overlay.hide();
							element.hide();
						}
						
					});

				}
			});
		}
	}
})();

KB.Confirm = {
		
	/**
	  * Ruft modal Dialog auf
	  */
	modal: function(element){
		var options = Object.extend({
			onOk:Prototype.emptyFunction,
			onCancel:Prototype.emptyFunction,
			onLoad:Prototype.emptyFunction,
			cancelObj:[],
			okObj:[],
			params:{},
			handle:null,
			draggable:null,
			duration: 1.0
		}, KB.parseArgument(arguments[1] || {}));
		
		
		var overlay = KB.overlay('document',{
			indicator:'/img/lightbox/loading.gif',
			indicatorDimensions: {width:32,height:32},
			bgColor:null
		}).show();
		
		
		
		
		if (!$(element) && KB.Validate.isURL(element)) {
			// Get Ajax return before inserting page (options.urlobject kommt aus 
			var url =  element;
			var element = new Element('div').hide();
			$(document.getElementsByTagName("body").item(0)).insert({bottom:element});			
			KB.request({
				element:element,
				url:url,				
				effect:null,
				params: Object.extend({
					popup:1,
					modal:1
				},options.params),				
				successFunc: KB.Confirm.modal,
				functionParams:Object.extend({
					
					deleteElement: true
				},options)	
			});
			return false;
		} else {
			overlay.select('img').first().hide();
		}
		
		
		
		var element = $(element);
		var dim = element.getDimensions();
		
				
		if (!$(element) && Object.isString(element)) {
			options.onLoad(element,options);
			if (confirm(element)){
				options.onOk(element,options);
			} else {
				options.cancelObj(element,options);
			}				
		}
		
		if (!$(element)) {
			overlay.hide();
			return null;
		} 
		
		if (options.draggable) {
			options.draggable = new Draggable($(element),Object.extend(options,{ scroll: window }));
		}
		
		element.setStyle({
			left:((KB.Layout.viewport.width - dim.width)/2)+'px',
			top:((KB.Layout.viewport.height - dim.height)/2)+'px',
			zIndex:1001,
			xposition:((KB.Browser.IE || KB.Browser.IE6)?'absolute':'fixed')
		});
		
		overlay.insert({after:$(element)});
	
		
		
		overlay.show();
		element.show();
		options.onLoad(element,options);
		
		options.cancelObj.push(overlay);
		options.cancelObj.each(function(el){
			if ($(el)) {
				Event.observe(el,'click',function(){						
					overlay.hide();
					
					options.onCancel(element,options);
					options.cancelObj.concat(options.okObj).findAll(function(el){return $(el);}).each(function(el){Event.stopObserving(el,'click');});
					if (options.deleteElement) element.remove()
					else element.hide();
				});
			}
		});
		
		options.okObj.each(function(el){
			if ($(el)) {
				Event.observe(el,'click',function(){
					if ((options.onOk == Prototype.emptyFunction)?true:options.onOk(element,options)){
						overlay.hide();
						if (options.deleteElement) element.remove()
						else element.hide();
					}
					
				});

			}
		});
	}
};





Object.extend(KB, KB.Methods)

document.observe("dom:loaded",KB.roundCorners);
document.observe("dom:loaded", function(){
	document.fire('content:changed');
	if (!KB.Browser.IE) {
	
		Event.observe(window,'load',function(){
			document.fire('content:changed');
			document.fire('content:resize');

		});

		Event.observe(window,'resize',function(){
			document.fire('content:resize');
		});
		Event.observe(window, 'change', function(){
			document.fire('content:resize');
		});
		
	} else {
		// security check for undefinded functions
		if ((typeof window.onresize).toUpperCase() != "FUNCTION")window.onresize = Prototype.emptyFunction;
		if ((typeof window.onchange).toUpperCase() != "FUNCTION")window.onchange = Prototype.emptyFunction;
		if ((typeof window.onload).toUpperCase() != "FUNCTION")window.onload = Prototype.emptyFunction;
		
		// wraporiginal functions and dispatch events
		window.onresize = window.onresize.wrap(function(proceed){
			proceed();
			document.fire('content:resize');
		});
		
		window.onchange = window.onchange.wrap(function(proceed){
			proceed();
			document.fire('content:resize');
		});
		
		window.onload = window.onload.wrap(function(proceed){
			proceed();
			document.fire('content:changed');
			document.fire('content:resize');			
		});
	}
});

document.observe("content:changed", function(){
	document.fire('content:resize');
});


/*
*/









/*
**
** File 'kbEvents.js'
**
*/
/**
 * Kuborgh Eventverwaltung
  */
var KuborghEvents = {
	events :  $H({}),
	submitStop: 0,
	
	/**
	 * Registriert ein Formelement. Läd gegebenfalls die zugehörige JS Datei nach
	 * @param {Object} Object 
	 */
	require: function(){
		// Extend default options
		var options = Object.extend({
			libraryName:'',
			libraryPath:'',
			id:'',
			lang_code: 'de',
			type: ''
		}, ((arguments[0] && Object.isString(arguments[0]) && unescape(arguments[0]).isJSON())? unescape(arguments[0]).evalJSON() : (arguments[0] || {} )));	
		var init = false;
		
		if (!this.isRegistered(options)){		
			try {
		        eval('Object.isUndefined('+ options.libraryName+ ');');
		    } catch (e) {
				//alert(e);
				document.write('<script type="text/javascript" src="'+options.libraryPath+'"><\/script>');
			}			
			options.instances = {};
			this.register(options);			
		}
	},
	
	/**
	 * Jedes Element was den Submit unterbrechen will muss einen submitStop registrieren
	 */
	pushStops: function(){
		this.submitStop += 1;
	},
	
	/**
	 * Wenn submitunterbrechung fertig den stop wieder rausnehmen
	 */	
	popStops: function(){
		this.submitStop -= 1;
		return (this.submitStop <= 0);
	},
	
	/**
	 * Registriert ein Formelement
	 * @param {Object} Object
	 */
	register: function(){
		// Extend default options
		var options = Object.extend({
			name:'',
			libraryPath:'',
			instance:''
		}, arguments[0] || {});	
		this.events.set(options.libraryName,{instance:[]});
	},
	
	/**
	 * Prüft ob eine Bibliothek registriert ist
	 * @param {Object} Object
	 */
	isRegistered: function(){
	    // Extend default options
		var options = Object.extend({
			libraryName:''
		}, arguments[0] || {});			
		return (options.libraryName.empty())? true : this.events.get(options.libraryName);
	}
}

/**
 * Abstrakter Formelement Handler
 * @param {Object} element
 * @param Object
 */
var FormElementEvent = {
	options:$H({}),
	elements:$H({})
};

FormElementEvent.Methods = (function(){
	
	
	
	return {
		/**
		 * Läd die jeweiligen Eventobserver  
		 * @param {Element} element
	 	 * @param {Object} Object
		 */
		loadObservers:function(element){
			element = $(element);
			if (!element) return;
			// Extend default options
			var options = Object.extend({
				id:Math.floor(Math.random()*1000000),
				form_id: null,
				libraryName: '',
				submit_function: true
			//}, ((arguments[1] && Object.isString(arguments[1]) && unescape(arguments[1]).isJSON())? unescape(arguments[1]).evalJSON() : (arguments[1] || {} )));		
			}, KB.parseArgument(arguments[1] || {}));	
	
			if (element.id) this.options.set(element.id,options);
			element.stopObserving();
			if (this.click) 		Event.observe(element, 'click', this.click.bindAsEventListener(this,options));
			if (this.change) 		Event.observe(element, 'change', this.change.bindAsEventListener(this,options));
			if (this.mouseover) 	Event.observe(element, 'mouseover', this.mouseover.bindAsEventListener(this,options));
			if (this.mouseout) 		Event.observe(element, 'mouseout', this.mouseout.bindAsEventListener(this,options));
			if (this.mousedown) 	Event.observe(element, 'mousedown', this.mousedown.bindAsEventListener(this,options));
			if (this.mouseup) 		Event.observe(element, 'mouseup', this.mouseup.bindAsEventListener(this,options));
			if (this.mousemove)		Event.observe(element, 'mousemove', this.mousemove.bindAsEventListener(this,options));
			if (this.dblclick) 		Event.observe(element, 'dblclick', this.dblclick.bindAsEventListener(this,options));
			if (this.blur)	 		Event.observe(element, 'blur', this.blur.bindAsEventListener(this,options));
			if (this.abort) 		Event.observe(element, 'abort', this.abort.bindAsEventListener(this,options));
			if (this.error) 		Event.observe(element, 'error', this.error.bindAsEventListener(this,options));
			if (this.select) 		Event.observe(element, 'select', this.select.bindAsEventListener(this,options));
			if (this.keyup) 		Event.observe(element, 'keyup', this.keyup.bindAsEventListener(this,options));
			if (this.keydown) 		Event.observe(element, 'keydown', this.keydown.bindAsEventListener(this,options));
			if (this.keypress) 		Event.observe(element, 'keypress', this.keypress.bindAsEventListener(this,options));
			if (this.focus) 		Event.observe(element, 'focus', this.focus.bindAsEventListener(this,options));
			if (this.domloaded)   {
				this.domloadedCache =  this.domloaded.bindAsEventListener(this,options);
				document.stopObserving('content:loaded',this.domloadedCache);
				document.observe('content:loaded', this.domloadedCache);
				if (KB.Browser.IE) {
					Event.stopObserving(document,'dom:loaded',this.domloadedCache);
					Event.observe(document,'dom:loaded', this.domloadedCache);
				} else {
					document.stopObserving('dom:loaded',this.domloadedCache);
					document.observe('dom:loaded', this.domloadedCache);
				}
				
			}
			if (this.formsubmit && options.form_id && $(options.form_id) && options.submit_function) {
				this.formsubmitCache = this.formsubmit.bindAsEventListener(this,options);
				Event.stopObserving(options.form_id,'submit',this.formsubmitCache);
				Event.observe(options.form_id, 'submit', this.formsubmitCache);
			}							
		}
	
	
}})();
Object.extend(FormElementEvent, FormElementEvent.Methods);


/*
**
** File 'kbDialog.js'
**
*/
/** CHECK Required Libraries */
if (parseFloat(Prototype.Version) < 1.6)  throw("KB.Dialog requires the Prototype JavaScript framework >= 1.6.0");



window.DialogOptions = Object.extend({
	fileIndicator: "/img/lightbox/loading.gif",		
	fileIndicatorTransparent: "/img/lightbox/loading.gif",		
	indicatorDimensions: {width:32,height:32},
	fadeDuration:1.0,
	forbiddenCssClasses: []
},window.DialogOptions || {});

KB.Dialog = {};

/*
* Basisklasse fÃ¼r Dialog
*/
KB.Dialog.Base = Class.create({
	
	options:{},
	overlay:null,
	style:null,
	html:'',
	contentLoaded:false,
	baseZIndex: 999,
	source:null,
	replacement:{},	
	
	result: null, // Set to 1  when ok clicked otherwise to 0
	/*
	* Initialisierung
	*/
	baseInitialize: function(source){
		this.source = source;
		if 	(!Object.isString(source)) source = '';
		
		// Default Options initialisieren
		this.options = Object.extend({
			
			id:Math.random(),					// Id des Dialogs im DialogManager
			title: '',							// Window Title
			onOk:Prototype.emptyFunction,		// onSuccess FUNKTION
			onCancel:Prototype.emptyFunction,	// onCancel FUNKTION
			onLoad:Prototype.emptyFunction,		// onLoad FUNKTION
			onOkIntern: Prototype.emptyFunction,
			onCancelIntern: Prototype.emptyFunction,
			require: null,
			init: true,
			
			cancelObj:[],						// Objecte die CANCEL auslï¿½sen			
			okObj:[],							// Objecte die SUCCESS auslï¿½sen
			params:{},							// PARAMETER fï¿½r Url Content
			submit:'ajax',						// Wie sollen Formulare abgeschickt werden?
			index:KB.DialogManager.count(),		// Index (wird bei mehreren Dialogen hochgezï¿½hlt)
			modal:true,							// Modal?			
			response:{},
			
			//draggable
			draggable: false,
			onDrag: Prototype.emptyFunction,
			handle:'.js_handle',				// HANDLE zum bewegen		
			infoClass:'.js_infomessage',		// HANDLE zum bewegen		
			infoContainerClass:'.js_infocontainer',		// HANDLE zum bewegen		
			template: '#{content}',
			
			status: {		
				ready: false,
				loading: false,	
				visible: false
			},		
			
			//any element with an href (image,iframe,ajax) will call this after it is done loading
			indicator: false,
			indicatorDimensions: {},
			clean:false,
			cancelOnOverlay:false				// Selbstreferenz zum laden der Daten per Request
		}, KB.parseArgument(arguments[1]) || {});

		
		
				
		// Bei uebergebener URL einen Request abschicken
		if (KB.Validate.isURL(source)) {	
			this.initOverlay();
			if (this.options.id && !KB.DialogManager.get(this.options.id)) {
				 KB.DialogManager.set(this.options.id,this);
			}	
			this.options.status.loading = true;
			if (this.options.init) {
				KB.request({
					update:false,
					url:source,				// Url
					effect:null,			// Keine Effekte
					params: Object.extend({ // Parameter fï¿½r URL
						popup:1,
						dialog:((this.options.modal)?'modal':'window'),
						title:this.options.title,
						dmode:'json'
					},this.options.params),				
					template: this.options.template, 
					successFunc: this.baseInitialize.bind(this), // Funktion die nach erfolgreichem Request aufgerufen wird ( Diese FUNKTION )
					functionParams:this.options	
				});
			} else {
				// DialogManager aktualisieren
				if (this.options.id) {
					this.options.status.loading = false;
					this.options.status.ready = false;
					 KB.DialogManager.set(this.options.id,this);
				}
			}
			// rausspringen (erneuter Funktionsaufruf nach erfolgreichem Request)
			return false;
		} 
		
		this.source = null;
		// Source ist DOM Element
		if (source.length && $(source)) {
		//	this.initOverlay();
		//	var template = new Template($(source).innerHTML);
		////	this.html = unescape(template.evaluate(this.options.response));	
			
			this.template = new Template($(source).innerHTML);
			this.html = this.template.evaluate(this.options.response);
			if (this.options.clean) $(source).remove();
			this.replacement = this.options.response;
		// Source ist URL Request	
		} else if (!source && this.options.response) {	
			this.template = (typeof this.options.response.template == 'object' && this.options.response.template.template)
				? this.options.response.template
				: new Template(this.options.response.template);
			var tmpElement = new Element('div',{style:'display:none'});	
		//	$(document.getElementsByTagName("body").item(0)).insert({bottom:tmpElement});
		
			var scripts = this.options.response.content.extractScripts().partition(function(script){
				return (script.search(/(KuborghEvents\.require)|(\_form\_element\.init)/) >= 0)
			});
			
			tmpElement.innerHTML = this.options.response.content.stripScripts();
			
		
				
		
			// Replace OK Button
			if (this.options.response.button_ok && tmpElement.select('[id="'+this.options.response.button_ok+'"]').size()) {
				this.options.response.button_ok = tmpElement.select('[id="'+this.options.response.button_ok+'"]').first().addClassName('js_ok').remove().wrap(new Element('div')).innerHTML;
			} else if (this.options.response.button_ok && tmpElement.select('[id="'+this.options.response.button_ok+'_input"]').size()) {
				this.options.response.button_ok = tmpElement.select('[id="'+this.options.response.button_ok+'_input"]').first().addClassName('js_ok').remove().wrap(new Element('div')).innerHTML;
			} else if (this.options.response.button_ok) {
				this.options.response.button_ok = null;
			}
			// Replace Cancel Button
			if (this.options.response.button_cancel &&  tmpElement.select('[id="'+this.options.response.button_cancel+'"]').size()) {
				this.options.response.button_cancel = tmpElement.select('[id="'+this.options.response.button_cancel+'"]').first().addClassName('js_cancel').remove().wrap(new Element('div')).innerHTML;
			} else if (this.options.response.button_cancel &&  tmpElement.select('[id="'+this.options.response.button_cancel+'_input"]').size()) {
				this.options.response.button_cancel = tmpElement.select('[id="'+this.options.response.button_cancel+'_input"]').first().addClassName('js_cancel').remove().wrap(new Element('div')).innerHTML;
			} else if (this.options.button_cancelbutton_ok) {
				this.options.response.button_cancel = null;
			}
			
			this.options.response.content = scripts[0].inject('', function(script, n) { return script + '<script type="text/javascript">'+n+'</script>'+"\n" });
			this.options.response.content+= tmpElement.innerHTML;
			this.options.response.content+= scripts[1].inject('', function(script, n) { return script + '<script type="text/javascript">'+n+'</script>'+"\n" });
			
			$A(DialogOptions.forbiddenCssClasses).each(function(css){
				this.select('.'+css).invoke('removeClassName',css);
			}.bind(tmpElement));
			
			this.replacement = this.options.response;
			this.html = this.template.evaluate(this.options.response);
			
		}
		
		
		
		// DialogManager aktualisieren
		if (this.options.id) {
			this.options.status.loading = false;
			this.options.status.ready = true;
			KB.DialogManager.set(this.options.id,this);			
		}	

		
		
		if (this.options.status.waiting) {
			this.options.status.waiting = false;
			this.show();
		}
	},
	
	overlay:function(){
		if (!this._overlay && !this.initOverlay()) return null;
		this._overlay.clonePosition(this._element).setStyle({zIndex: (parseInt(this._element.getStyle('zIndex')) + 1)});
		if (!KB.Browser.IE) this._overlay.setStyle({position:'fixed'});
		return this._overlay;
	},
	
	initOverlay:function(){
		// Dialog - interne variablen initialisieren	
		if (!this._element) return false;
		this._overlay = (this._overlay)? this._overlay : KB.overlay(this._element,{
			bgColor:(this.options.modal)?null:'transparent',
			indicator: this.options.indicator,
			opacity:0.5,
			indicatorDimensions: this.options.indicatorDimensions
		}).hide();
		this._overlay.id = this.options.id+'_overlay';
		this._overlay.clonePosition(this._element);
		
		return this._overlay;
	},
	
	initEvents:function(element){		

		// onCancel Event
		if (this.options.cancelOnOverlay) this.options.cancelObj.push(KB.DialogManager.overlay());	
		this.options.cancelObj.concat($$('.js_cancel')).each(function(el){
			if ($(el)) {
				$(el).observe('click',function(event){		
					this.hide();	
					this.result = false;					
					this.options.onCancel(event,this);
					this.options.onCancelIntern(event,this);
					this.options.cancelObj.concat(this.options.okObj).findAll(function(el){return $(el);}).each(function(el){Event.stopObserving(el,'click');});
					
				}.bindAsEventListener(this));
				$(el).observe('mouseover',function(event){
					event.element().style.cursor='pointer';
				}.bindAsEventListener(this));
			}
		}.bind(this));
		
		// onOk Event
		
		this.options.okObj.concat($$('.js_ok')).each(function(el){
			if ($(el)) {
				$(el).observe('click',function(event){
					if (this.options.require && KB.DialogManager.get(this.options.require)){
						if (this.overlay()) KB.toggle(this.overlay(),{ force: 'show' });						
						KB.DialogManager.get(this.options.require).show({
							onOkIntern: function(){
								if ((this.options.onOk == Prototype.emptyFunction) || this.options.onOk(event,this)){
									this.hide();
									this.result = true;
									this.options.cancelObj.concat(this.options.okObj).findAll(function(el){return $(el);}).each(function(el){Event.stopObserving(el,'click');});
								}
							}.bind(this)
						});
					} else {
						if ((this.options.onOk == Prototype.emptyFunction) || this.options.onOk(event,this)){
							
							this.hide();
							this.result = true;
							this.options.onOkIntern(event,this);
							this.options.cancelObj.concat(this.options.okObj).findAll(function(el){return $(el);}).each(function(el){Event.stopObserving(el,'click');});
						}
					}						
				}.bindAsEventListener(this));
				$(el).observe('mouseover',function(event){
					event.element().style.cursor='pointer';
				}.bindAsEventListener(this));

			}
		}.bind(this));
	},
	
	clearEvents:function(element){	
		// onCancel Event
		if (this.options.cancelOnOverlay) this.options.cancelObj.push(KB.DialogManager.overlay());		
		this.options.cancelObj.concat($$('.js_cancel')).each(function(el){
			if ($(el)) {
				Event.stopObserving($(el));
			}
		});
		// onOk Event
		this.options.okObj.concat($$('.js_ok')).each(function(el){
			if ($(el)) {
				if ($(el)) {
				Event.stopObserving($(el));
				}
			}
		});
		
		// Alle events innerhalb des dialogs
		if ($(this._element)) {
			this._element.descendants().reject(function(el){
				return Object.isUndefined(el._prototypeEventID);
			}).each(function(el){
				Event.stopObserving(el);
			});			
		}
		
		document.stopObserving('dialog:ready');
	},

	setZ: function(zIndex){
		if ($('Dialog:'+this.options.id+'_dialog')) $('Dialog:'+this.options.id+'_dialog').setStyle({zIndex:((this.options.modal)?this.baseZIndex:this.baseZIndex-200) + (zIndex * 2)});
	},
	
	element: function(){
		return this._element;
	},
	
	infoElement: function(){
		return (this._element) ? Element.select(this._element,this.options.infoClass).first() : null;
	},
	
	infoContainer: function(){
		return (this._element) ? Element.select(this._element,this.options.infoContainerClass).first() : null;
	},
	
	
	form: function(){

		return (this._element) ? Element.select(this._element,'form').first() : null;
	}
});


/* DIALOG */
KB.Dialog = Class.create(KB.Dialog.Base, {

	initialize: function(element,options) {
		this.baseInitialize(element, options);
		
	},
  
	show: function(){
			
		this.options = Object.extend(this.options, KB.parseArgument(arguments[0]) || {});
		this.replacement = Object.extend(this.replacement, this.options.response);
		
		if (this.options.require) KB.DialogManager.setResult(this.options.require,false);
		
		if ($('Dialog:'+this.options.id+'_dialog')) return;
		
		if (this.options.modal && !KB.DialogManager.overlayActive()) {						
			KB.toggle(KB.DialogManager.overlay(),{force:'show',duration:window.DialogOptions.fadeDuration});//this.overlay.show()
			if (this.options.status.waiting && KB.DialogManager.overlay().indicator()) KB.DialogManager.overlay().indicator().show();
		}		
		
		if (!this.options.status.ready || this.options.status.loading ) {
			if (KB.DialogManager.overlay() && KB.DialogManager.overlay().indicator()) KB.toggle(KB.DialogManager.overlay().indicator(),{force:'show',duration:window.DialogOptions.fadeDuration});
			this.options.status.waiting = true;
			if (!this.options.init) {
				this.options.init = true;
				this.baseInitialize(this.source,this.options);
			}
			return false;
		} else {
			if (KB.DialogManager.overlay() && KB.DialogManager.overlay().indicator()) KB.toggle(KB.DialogManager.overlay().indicator(),{force:'hide',duration:window.DialogOptions.fadeDuration});
			//var template = new Template(this.html);
			if (this.template) this.html = this.template.evaluate(this.replacement);	
			this.html = this.html.replace(/\{\*[^\}]*\*\}/gi,'');
		}
		
		
		
		var element = new Element('div',{id:'Dialog:'+this.options.id+'_dialog', style:'display:none'},this.html);
		$(document.getElementsByTagName("body").item(0)).insert({bottom:element});
		Element.update(element,this.html);
					
		var dimensions = element.getDimensions();
		var pageDimensions = KB.getPageSize();
		dimensions.top = (pageDimensions.windowHeight - dimensions.height)/4;
		dimensions.left = (pageDimensions.windowWidth - dimensions.width)/2;
		if ( dimensions.top < 0 ) dimensions.top = 0;

		this.style = (KB.Browser.IE || KB.Browser.IE6) 
			? {
				position:'absolute',
				left:dimensions.left+'px',
				top:dimensions.top+'px'
			}:{   
				left:dimensions.left+'px',
				top:dimensions.top+'px',
				position:'fixed'
			};
		
		
		element.setStyle(this.style);
		element.addClassName('dialog');
		this.setZ(this.options.index);
		this._element = element;		
		
		
		this.options.onLoad(this._element,this.options);	
		
		
		if (KB.DialogManager.overlay() && !KB.DialogManager.overlayActive()) {			
			window.setTimeout(function(){
				//this.show();
				KB.toggle(this.element(),{
					force:'show',
					duration:window.DialogOptions.fadeDuration,
					beforeStart:function(){	element.fire("dialog:loading"); },
					afterUpdate:function(){	element.fire("dialog:fading");  },
					afterFinish:function(){	
						element.fire("dialog:loaded"); 
						element.fire("dialog:ready");  
						this.initEvents(element);
					}.bind(this)
				});
				
			}.bind(this), 550);		
		} else {
			KB.toggle(this.element(),{
				force:'show',
				duration:window.DialogOptions.fadeDuration,
				beforeStart:function(){	element.fire("ajax:loaded");element.fire("dialog:loading");},
				afterUpdate:function(){	element.fire("dialog:fading");  },
				afterFinish:function(){	
					element.fire("dialog:loaded"); 
					element.fire("dialog:ready"); 
					this.initEvents(element);
				}.bind(this)
			});
		}
		
		var handle = [$(this.options.handle)].concat($(element).select(this.options.handle)).detect(function(e){return $(e);});	
		if (handle) {		
			handle.observe('mouseover',function(event){		
				var pointer = this.options.cancelObj.concat(element.select('.js_cancel')).concat(this.options.okObj.concat(element.select('.js_ok')))
				if (pointer.indexOf(event.element()) < 0) {
					event.element().style.cursor='move';
				}
				this.bringToFront();
			}.bindAsEventListener(this));		
			this.draggable =  new Draggable($(element),Object.extend({ 
				scroll: window, 
				handle:handle,
				onDrag : function(){
					this.bringToFront();
					this.options.onDrag.bind(this)
                }.bind(this)
			}));
		}
		this.bringToFront();			
		
		
		this.initOverlay()
	},
  
	hide: function(){
		var element = $('Dialog:'+this.options.id+'_dialog');
		var overlay = KB.DialogManager.overlay();
		this.clearEvents(element);
		if (this.draggable) this.draggable.destroy();
		if (overlay && KB.DialogManager.countActive().modal <= 1) new Effect.Fade(KB.DialogManager.overlay(),{duration:window.DialogOptions.fadeDuration});//overlay.hide();
		if (element) {			
			KB.toggle(this.element(),{
				force:'hide',
				duration:window.DialogOptions.fadeDuration,
				afterFinish:function(){	
					if (this._element) {
						this._element.fire('dialog:closed');
						this.element().remove();
						this._element = null;
					}
				}.bind(this)
			});
			
		}
	},
	
	visible: function(){
		return $('Dialog:'+this.options.id+'_dialog') != null;
	},
	
	bringToFront: function(){
		KB.DialogManager.bringToFront(this);
	}
	
	
  
});

KB.DialogManager = (function(){


	
	return {
			
		dialogs: $H({}),
		
		register: function(id,source) {			
			var options = Object.extend({		
				index:this.dialogs.values().size(),
				id:id
			}, KB.parseArgument(arguments[2]) || {});
			this.dialogs.set(id,'pending...');
			var dialog = new KB.Dialog(source,options);
			this.dialogs.set(id,dialog);
			return this.dialogs;
		},	
		
		
		unregister: function(id){		
			this.dialogs.unset(id);
			return this.dialogs;
		},
		
		get: function(id){
			return this.dialogs.get(id);
		},
		
		getActive: function(){
			return this.dialogs.values().find(function(dialog){
				return (dialog.visible());
			});
		},
		
		set: function(id,dialog){
			this.dialogs.set(id,dialog);
		},
		
		count: function(){
			return this.dialogs.values().size();
		},
		
		countActive: function(){
			var index = 0;
			var indexModal = 0;
			var active = this.getActive();
			this.dialogs.values().each(function(dialog,i){
				if (dialog.visible()){
					++index;
					if (dialog.options.modal) ++indexModal;
				}
			});
			return {all:index,modal:indexModal};
		},
		
		bringToFront: function(dialog){
			var index = 0;
			var dIndex = dialog.options.index;
			this.dialogs.values().each(function(dialog,i){
				if (dialog.visible() && dialog.options.index != dIndex) {
					dialog.setZ(++index);
				}				
			}.bind(dialog))
			dialog.setZ(++index);
		},
		
		overlay: function() {
			return (this._overlay) ? this._overlay : this.initOverlay();
		},
		
		initOverlay:function(){
		// Dialog - interne variablen initialisieren	
		
			this._overlay = (this._overlay)? this._overlay : KB.overlay('document',{
				bgColor:null,
				indicator: window.DialogOptions.fileIndicator,
				transparentIndicator: (window.DialogOptions.fileIndicatorTransparent)?window.DialogOptions.fileIndicatorTransparent:null,
				indicatorDimensions: window.DialogOptions.indicatorDimensions,
				id: 'dialog'
			}).hide();
			
			if (this._overlay.indicator()) this._overlay.indicator().hide();
			return this._overlay;
		},
	
		overlayActive: function(){
			//return !Object.isUndefined(this.dialogs.values().find(function(dialog){
			//	return dialog.overlay && dialog.overlay.visible();
			//}));
			return this._overlay && this._overlay.visible();
		},
		
		getResult: function(id){
			return (this.dialogs.get(id))? this.dialogs.get(id).result: true;
		},
		
		setResult: function(id,result){
			if (this.dialogs.get(id)) this.dialogs.get(id).result = result;
		},
		
		parseLinks: function(event) {
			$$('a').findAll(function(link){
				var rel = link.readAttribute('rel');
				return rel && rel.include('dialog');
			}).each(function(dialog,index){		
				var source = dialog.readAttribute('href');				
				if (!source) return;
				dialog.writeAttribute({href:'javascript:void(0);'});
				var id = (dialog.readAttribute('id'))? dialog.readAttribute('id') : index;
				var snippet = 'default';
				if (dialog.readAttribute('rel').search(/\[([^\]]*)\]/) >= 0 && !dialog.readAttribute('rel').match(/\[([^\]]*)\]/).last().empty()) {
					snippet = dialog.readAttribute('rel').match(/\[([^\]]*)\]/).last();
				}
				var options = {
					submit: dialog.readAttribute('submit') || 'normal',
					title: dialog.readAttribute('title'),
					onSuccess: (dialog.readAttribute('onsuccess'))? '<script>'+dialog.readAttribute('onsuccess')+'</script>' : '',
					onFailure: (dialog.readAttribute('onfailure'))? '<script>'+dialog.readAttribute('onfailure')+'</script>' : '',
					modal: dialog.hasClassName('modal'),
					init: (dialog.readAttribute('init') && parseInt(dialog.readAttribute('init')))? true : false,
					require: dialog.readAttribute('require'),
					indicator: (dialog.hasClassName('modal'))?window.DialogOptions.fileIndicator:window.DialogOptions.fileIndicatorTransparent,
					indicatorDimensions: window.DialogOptions.indicatorDimensions,
					params: { dialogTheme: snippet	},
					onOk: function(event,dialog){
						if (dialog.form()) {
							var form = dialog.form();
							
							if (dialog.options.submit == 'normal') {
								if (dialog.initOverlay()) KB.toggle(dialog.overlay(),{ force: 'show' });
								if (document.getElementsByName('dmode') && $A(document.getElementsByName('dmode')).first()) $A(document.getElementsByName('dmode')).first().value = 'normal';
								if (document.getElementsByName('popup') && $A(document.getElementsByName('popup')).first()) $A(document.getElementsByName('popup')).first().value = '0';
								form.submit();								
							} else {
								var url = (Object.isString(form.action) ? form.action : '/index.php?').replace(/popup/,'');
								if (dialog.initOverlay()) KB.toggle(dialog.overlay(),{ force: 'show' });
								KB.request({
									url: url, 
									redirectOnSuccess: (dialog.options.submit == 'ajax_reload'),
									collectIds: dialog.element(),
									params: Object.extend((dialog.form())? dialog.form().serialize(true) : {},{
										dmode:'json',
										subaction: 'save',
										popup:1
									}),
									onSuccess: function(element,options){		
										if (this.overlay()) KB.toggle(this.overlay(),{ force: 'fade' });
										this.options.onSuccess.evalScripts();
										this.hide();
										location.reload();
									}.bind(dialog),
									onFailure: function(element,options){
										var type = "warning";
										/* Field specific error handling */																			
										this.element().descendants().invoke('removeClassName', 'form_warning');
										this.element().descendants().invoke('removeClassName', 'form_error');
										this.element().cleanWhitespace();
										
										if (options.response.error) options.response.error.each(function(el){
											var el = Object.extend({
												label:'',
												type:'error',
												form_element:''
											},el);
											type = (el.type == 'error')?'error':'warning';
											var errorEl = $A(document.getElementsByName(el.form_element)).first() || $A(document.getElementsByName(el.form_element+'[]')).first();
											var errorLabel = this.descendants().find(function(el){
												return !this.empty() && el.innerHTML && this.toLowerCase() == el.innerHTML.strip().toLowerCase();
											}.bind(el.label.strip()));
											if (errorLabel) errorLabel.addClassName('form_' + el.type);
											if (errorEl) errorEl.addClassName('form_' + el.type);
										}.bind(this.element()));
										
										// Show e
										if (this.infoContainer()) {
											this.infoContainer().show();
											this.infoContainer().setStyle({display:'block'});
										}
										if (!options.response.message.replace(/\&nbsp\;/,'').strip().empty() && this.infoElement()){											
											this.infoContainer().addClassName('form_' + type);
											this.infoElement().update(options.response.message.replace(/\&nbsp\;/,'').nl2br() );											
										}
										document.fire('dialog:changed');
										this.options.onFailure.evalScripts();										
										if (this.overlay()) KB.toggle(this.overlay(),{ force: 'fade'  });
									}.bind(dialog)
									
								});
							}
							return false;
						} else {
							return true;
							this.hide();
						}
					}
				}		
				
				if (!KB.DialogManager.get(id)) { 
					KB.DialogManager.register(id,source,options)
					dialog.observe('click',function(e){
						KB.DialogManager.get(this).show();
					}.bindAsEventListener(id));
				}
			});
		}
		
		
}})();



document.observe("dom:loaded",KB.DialogManager.parseLinks);
document.observe("content:loaded",KB.DialogManager.parseLinks);

/*
**
** File 'ajax_clone_form_element.js'
**
*/
var Ajax_clone_form_element = Object.extend({
	
	containers:$H({}),
	
	domloaded: function(e){
		var options = Object.extend({
			elements: [],
			clear_value: true
		}, KB.parseArgument(arguments[1] || {}));	
		var i = 1;
		
		options.elements.flatten().findAll(function(e){ return $(e);}).each(function(el){
			var c = new Element('div',  { className: 'js_clone_blockwrapper' });
			Element.wrap(el, c);
			$(el).addClassName('js_clone_block');
			Ajax_clone_form_element.containers.set(el,{
				container:c,
				elements: $(el).descendants().concat([el]).findAll(function(e){return (e._eventID || e._prototypeEventID) && e.id}).collect(function(e){			
					return {element:e,options:FormElementEvent.options.get(e.id)};
				})				
			});	
		});
	},
	
	click: function(e){
		var options = Object.extend({
			elements: [],
			clear_value: true
		}, KB.parseArgument(arguments[1] || {}));		
		var offset = e.element().readAttribute('rel');		
		var insertAfter = $(options.elements.last());
		options.elements.flatten().reverse(false).each(function(el){
			var object = Ajax_clone_form_element.containers.get(el);
			var container = object.container;
			var element = $(el)?$(el):container.childElements().last();	
			var offset = (container.descendants().find(function(x){ return x.readAttribute('name')}).readAttribute('name').match(/(\d+)[^\d]*$/) || [0]).last() ;
			if (!element || !container) return;
			var temp = element.descendants().find(function(e){return (e.id && FormElementEvent.options.get(e.id) && FormElementEvent.options.get(e.id).libraryName.search(/flash/i) >= 0);});			
			if (temp ) return;
			
			var cloneNode = element.clone();	
			var referenceNodes = element.descendants().concat([element]);
			cloneNode.descendants().concat([cloneNode]).each(function(e){
				var tmp = referenceNodes.find(function(t){return t.id == e.id});
				if ((tmp._eventID || tmp._prototypeEventID) && tmp.id){
					e = Object.extend(e,{
						_eventID:'event',
						options:FormElementEvent.options.get(tmp.id)
					});
				}
			});		

			
			
			Element.insert(container,{bottom:cloneNode});			
			container.reOrder({className:'js_clone_block',attributes:['name','id'],offset:offset});		
				
			var evalIds = [];		
			var cloneNodeId = cloneNode.id;			
			evalIds = cloneNode.descendants().concat([cloneNode]).findAll(function(e){return ((e._eventID || e._prototypeEventID) && e.id)}).collect(function(e){
				var options = {};
				Object.extend(options,e.options || {});					
				return {id:e.id,options:options};
			});
			
			element.descendants().concat([element]).concat(cloneNode.descendants().concat([cloneNode])).findAll(function(e){
				return e.readAttribute('kbEvent');
			}).each(function(e){
				e.writeAttribute({kbEvent:null});
			});
			
			if (options.clear_value) cloneNode.clearValues();			
			
			evalIds.each(function(obj){
				Object.extend(obj.options,{id:cloneNodeId});
				Object.extend($(obj.id),{options:obj.options});
				eval('if ('+obj.options.libraryName+'.init) '+obj.options.libraryName+'.init(obj.options);');
				eval(obj.options.libraryName+'.loadObservers(\''+obj.id+'\',obj.options);');
			});
			
			document.fire("content:changed");
			document.fire("dialog:changed");
		});
		
	},
	
	mouseover: function(e){
		e.element().style.cursor = 'pointer';
	},
	
	mouseout: function(e){
		e.element().style.cursor = 'default';
	}
	
	
},FormElementEvent);



/*
**
** File 'button_form_element.js'
**
*/
var Button_form_element = Object.extend({

	click: function(e){
		// Extend default options
		var options = Object.extend({
			submit_type: '',
			form_id: null,
			ajax: null
		}, KB.parseArgument(arguments[1] || {}));
			
		var forms = $$('form');
		
		// wenn form_id nicht gesetzt oder element mit form_id nicht vorhanden dann nehme erstes formular aus seite
		if (!(options.form_id && $(options.form_id)) && forms.length > 0){
			options.form_id = forms.first().id;
		}
		
		// Find hidden "submit_type" input
		var hidden = (options.form_id && $(options.form_id))
			? $(options.form_id).select('input[name="submit_type"]').first()
			: $$('input[name="submit_type"]').first();
		
		// wenn hidden nichtvorhanden -> erstelle hidden element für 'submit_type'	
		if (!$(hidden) && (options.form_id && $(options.form_id))) {
			hidden = new Element('input',{type:'hidden', name:'submit_type'});
			$(options.form_id).insert({bottom: hidden});
		} else if (!$(hidden)) {
			hidden = new Element('input',{type:'hidden', name:'submit_type'});
			$(document.getElementsByTagName("body").item(0)).insert({bottom:hidden});
		}
		
		// Set "submit_type" if found
		if (hidden) hidden.value = options.submit_type;		
		
		// unregister other submit Observers if cancel button is pressed
		if (options.submit_type == 'cancel' && $(options.form_id)) {
			$(options.form_id).stopObserving('submit');
		}
		
		// Ajax Request
		if (options.ajax) {
			KB.request(options.ajax);
			if (options.ajax.clean) clearFormParams()
			e.stop();
		}
	},
	
	mouseover: function(e){
		var element = ($(e.element().parentNode).select('img, input') || ['']).first();
		
		var options = Object.extend({
		}, KB.parseArgument(arguments[1] || {}));
		if (!element || Object.isUndefined(options.image_source_highlight) || Object.isUndefined(options.image_source)) return;
		if (element.readAttribute('src') && !options.image_source_highlight.empty()){
			element.writeAttribute('src',options.image_source_highlight);
		}	
		
		element.style.cursor = 'pointer';
	},
	
	mouseout: function(e){	
		var element = ($(e.element().parentNode).select('img, input') || ['']).first();

		var options = Object.extend({
		}, KB.parseArgument(arguments[1] || {}));		
		if (!element || Object.isUndefined(options.image_source_highlight) || Object.isUndefined(options.image_source)) return;
		if (element.readAttribute('src') && !options.image_source.empty() && !options.image_source_highlight.empty()){
			element.writeAttribute('src',options.image_source);
		}
		
	}
},FormElementEvent);
/*
**
** File 'checkbox_form_element.js'
**
*/
var Checkbox_form_element = Object.extend({
	mouseover: function(e){
		e.element().style.cursor = 'pointer';
	},
		
	change: function(e){
		var options = Object.extend({
			notify_change: false
		}, KB.parseArgument(arguments[1] || {}));
		
		if (options.notify_change) document.fire('form:changed');
	}
},FormElementEvent);
/*
**
** File 'flash_file_form_element.js'
**
*/
var Flash_file_form_element = Object.extend({
	// Private 
	form: null,
	lcId: $H({}),
	flashProxy: $H({}),
	
	init: function(){
		var options = Object.extend({
			id: null
		}, KB.parseArgument(arguments[0] || {}));
		
		this.lcId.set(options.id,new Date().getTime() + Math.round(1000 * Math.random())) + this.lcId.size();
		
	},
	
	blur: function(e){
	},
	
	
	domloaded: function(e){
		if(!$('_flash_proxy_' + this.lcId)) {
			element = new Element('div',{id:'_flash_proxy_' + this.lcId});
			var objBody = document.getElementsByTagName("body").item(0);
			objBody.appendChild(element);
			document.body.appendChild(element);
		}	
		options = KB.parseArgument(arguments[1]);
		if (options.flash_type!='swfobject') {
			this.flashProxy.set(options.id,new FlashProxy(this.lcId.get(options.id), "/java/JavaScriptFlashGateway.swf"));
			this.flashProxy.get(options.id).setWmode(0); 
		}
		
	}, 
	
	formsubmit: function(e){
		var options = Object.extend({
			id: null
		}, KB.parseArgument(arguments[1] || {}));
		this.form = e.element();
		if ($(options.id)){	
			if (options.flash_type=='swfobject') {
				var name = 'flash_upload_'+options.id+'_content';
				if (navigator.appName.indexOf("Microsoft") != -1) {
					var movie = window[name];
				} else {
					var movie = document[name]
				}
				if (movie) {
					movie.uploadFiles();
				} else {
					alert('Flash not locateable');
				}
					
					
			} else {
				this.flashProxy.get(options.id).call('uploadFiles');
				this.flashProxy.get(options.id).setWmode(0);
			}
			KuborghEvents.pushStops();
		}
	},
	
	submit:function(){
		//Flash_file_single_new_form_element.uploaded = true;
		var submit = KuborghEvents.popStops();
		if (submit) this.form.submit();
	},
		
	change: function(e){
		var options = Object.extend({
			notify_change: false
		}, KB.parseArgument(arguments[1] || {}));
		
		if (options.notify_change) document.fire('form:changed');
	}

	
	
},FormElementEvent);


/*
**
** File 'headline_form_element.js'
**
*/
var Headline_form_element = Object.extend({
	
	change: function(e){
		var options = Object.extend({
			notify_change: false
		}, KB.parseArgument(arguments[1] || {}));
		
		if (options.notify_change) document.fire('form:changed');
	}
},FormElementEvent);
/*
**
** File 'info_form_element.js'
**
*/
var Info_form_element = Object.extend({

		change: function(e){
			var options = Object.extend({
				notify_change: false
			}, KB.parseArgument(arguments[1] || {}));
			
			if (options.notify_change) document.fire('form:changed');
		}
},FormElementEvent);
/*
**
** File 'input_form_element.js'
**
*/
var Input_form_element = Object.extend((function(){
	return {
		elements:$H({}),
		
		domloaded: function(e){
			var options = Object.extend({
				validate: '',
				validate_text: 'error'
			}, KB.parseArgument(arguments[1] || {}));
			
			

			if ($(options.id+'_input') && $(options.id+'_input').select('input').first() && $(options.id+'_input').select('input').first().type == 'password'){
				$(options.id+'_input').select('input').first().update('');
			}
			
			if ($(options.id+'_input') && $(options.id+'_input').select('input').first() && $(options.id+'_input').select('input').first().readAttribute('disabled')){
				$(options.id+'_input').select('input').first().setStyle({color:'#aaa'});
			}
			
		    // turn on validation errors beside the field globally		
			if (options.validate && typeof Ext != 'undefined'){					
				Ext.QuickTips.init();
				$(options.id+'_input').update('');
				this.elements.set(options.id,{
					el: Ext.get(String(options.id+'_content')),
					tf: new Ext.form.TextField({
			            fieldLabel:options.label,
			            renderTo:options.id+'_input',
			            name:options.name,
			            allowBlank:!options.mandatory,
			            blankText:"please enter value",
			            vtype:'validFunc'+options.id,
			            vtypeText:options.validate_text
			        }),
					validation:function(val,field){
						var reg = new RegExp(options.validate);
					    return (field.getValue().match(reg) == field.getValue());
					}
				});			
				// Add the additional 'advanced' VTypes
				eval('Ext.apply(Ext.form.VTypes, { validFunc'+options.id+':this.elements.get(options.id).validation});');
			
			}
			
			
			
		},
	  
		
		keyup: function(e){
			var options = Object.extend({
				validate: ''
			}, KB.parseArgument(arguments[1] || {}));
			/*if (!options.validate.empty()) {
				var re = new RegExp(options.validate);
				if ($(options.id) && $(options.id+'_error') && re && e.element().value.match(re) && e.element().value.match(re).first() == e.element().value) $(options.id+'_error').hide();
				if ($(options.id) && $(options.id+'_error') && re && !e.element().value.match(re)){
					$(options.id+'_error').show();
					var tmp = Ext.get(String(options.id));
					tmp.highlight();
					
				}
			}		*/	
		},
		
		change: function(e){
			var options = Object.extend({
				notify_change: false
			}, KB.parseArgument(arguments[1] || {}));
			
			if (options.notify_change) document.fire('form:changed');
		}
		
		
	}	
})(),FormElementEvent);


/*
**
** File 'radio_form_element.js'
**
*/
var Radio_form_element = Object.extend({
	
		change: function(e){
			var options = Object.extend({
				notify_change: false
			}, KB.parseArgument(arguments[1] || {}));
			
			if (options.notify_change) document.fire('form:changed');
		}
},FormElementEvent);
/*
**
** File 'select_form_element.js'
**
*/
var Select_form_element = Object.extend({		
		change: function(e){
			var options = Object.extend({
				notify_change: false
			}, KB.parseArgument(arguments[1] || {}));
			
			if (options.notify_change) document.fire('form:changed');
		}
},FormElementEvent);
/*
**
** File 'text_form_element.js'
**
*/
var Text_form_element = Object.extend({
	
		change: function(e){
			var options = Object.extend({
				notify_change: false
			}, KB.parseArgument(arguments[1] || {}));
			
			if (options.notify_change) document.fire('form:changed');
		}
},FormElementEvent);
/*
**
** File 'textarea_form_element.js'
**
*/
var Textarea_form_element = Object.extend((function(){
	
	return {
	
			
		domloaded: function(e){
			var options = Object.extend({
				addon: ''
			}, KB.parseArgument(arguments[1] || {}));
			
			if ($(options.id+'_input') && $(options.id+'_input').select('textarea').first() && $(options.id+'_input').select('textarea').first().readAttribute('disabled')){
				$(options.id+'_input').select('textarea').first().setStyle({color:'#aaa'});
			}						
		},
		
		change: function(e){
			var options = Object.extend({
				notify_change: false
			}, KB.parseArgument(arguments[1] || {}));
			
			if (options.notify_change) document.fire('form:changed');
		}
		
		
}})(),FormElementEvent);

/*
**
** File 'two_select_form_element.js'
**
*/
var Two_select_form_element = Object.extend((function(){
	
	var NONE = 1;
	var ALL = 2;
	
	/**
	 * Sortierfunktion für Two Selects
	 */
	function sortId(a,b) { 
		if ((a.value+"") < (b.value+"")) { return -1; }
		if ((a.value+"") > (b.value+"")) { return 1; }
		return 0;
	} 
	/**
	 * Sortierfunktion für Two Selects
	 */
	function sortName(a,b) { 
		if (String(a.text).toLowerCase() < String(b.text).toLowerCase()) { return -1; }
		if (String(a.text).toLowerCase() > String(b.text).toLowerCase()) { return 1; }
		return 0;
	}
	
	function move(name){
		var name = (Object.isString(name))? name : '';
		var insert = true;
		var locked = false;
		// Parse Options
		var options = Object.extend({
			clone: false,	 // Clones the element and moves the clone leaving the original in place.
			sort: false, 	 // Select Options werden sortiert
			max_length: 0, 		 // Maximale Anzahl der Elemente im Ziel Select
			extended: false, // Für Proove Select (select beinhaltet die optionen ALLE bzw. KEINE
			multiple: false	 // mehrere options gleichen Types kopieren
		},KB.parseArgument(arguments[1] || {}));		
		options.max_length = (options.max_length)?options.max_length:-1;
		
		var elements = {}
		// Get Source && Dest Select
		if (name.search(/unselected/) >= 0){
			elements.selected = Element.select($(name.replace(/unselected/,'selected')),'select').first();
			elements.unselected = Element.select($(name),'select').first();	
			elements.dest = Element.select($(name.replace(/unselected/,'selected')),'select').first();
			elements.src  = Element.select($(name),'select').first();					
		} else {
			elements.selected = Element.select($(name),'select').first();	
			elements.unselected = Element.select($(name.replace(/selected/,'unselected')),'select').first();
			elements.src  = Element.select($(name),'select').first();
			elements.dest = Element.select($(name.replace(/selected/,'unselected')),'select').first();
			insert = false;	
		}	
		
		/* Alle rueber schieben bei proove_select */
		if (options.extended && (elements.dest == elements.selected)){
			var option = elements.unselected.select('option').findAll(function(o){ return o.selected && (o.value == ALL || o.value == NONE);}).collect(function(s){return s.value;}).inject(0,function(acc,n){return (Number(acc) >= Number(n))? Number(acc): Number(n);});
			locked = (!option && !Object.isUndefined(elements.selected.select('option').find(function(o){ return o.value == ALL || o.value == NONE; })));
			
			if (option != 0){
				elements.selected.select('option').each(function(o){
					var opt = o;
					if (Object.isUndefined(elements.unselected.select('option').find(function(s){ return s.value == opt.value }))) elements.unselected.insert(opt.clone());
					opt.remove();
				});
				elements.unselected.select('option').each(function(o){
					o.selected = (o.value == option);
				});
			}
		}
		
		// Wenn kein Elemente ungültig
		if (!elements.src || !elements.dest) return;
		
		elements.src.select('option').each(function(o){
			var opt = o;
			oInsert = insert || Object.isUndefined(elements.unselected.select('option').find(function(s){ return s.value == opt.value }));
			/* Maximale anzahl ueberschritten ? */
			oLocked = locked || (elements.dest.select('option').length - options.max_length == 0);
			/* Element schon vorhanden oder mehrfach erlaubt */
			oLocked |= (!Object.isUndefined(elements.selected.select('option').find(function(s){ return s.value == opt.value })) && !options.multiple);
			oLocked &= (elements.dest == elements.selected);			
			if (!opt.selected) return;
			if ((!options.clone || (options.clone &&  oInsert)) && !oLocked) elements.dest.insert(opt.clone());
			if ((!options.clone || (options.clone && !insert)) && !oLocked) opt.remove();
		});
		
		/* Nicht sortieren, wenn manuell eingeschaltet */
		if (!options.sort) {
			//var temp = elements.selected.select('option').sort(selectSort);
			var temp = (options.extended)?elements.selected.select('option').sort(sortId):elements.selected.select('option').sort(sortName);
			elements.selected.select('option').each(function(o){ o.remove(sortName); });
			temp.each(function(o){ elements.selected.insert(o);});
		}	
		
		/* Sortierung */
		//var temp = elements.unselected.select('option').sort(selectSort);
		var temp = (options.extended)?elements.unselected.select('option').sort(sortId):elements.unselected.select('option').sort(sortName);
		elements.unselected.select('option').each(function(o){ o.remove(); });
		temp.each(function(o){ elements.unselected.insert(o);});				
	}
	
	
	/////////////////////////////////////////////////////////////////////////////////////////////////////////
	function moveUp(obj) {
		obj = $(obj);
		if (!obj || !obj.previous()) return;
		obj.previous().insert({before:obj});
	}

	/////////////////////////////////////////////////////////////////////////////////////////////////////////
	function moveDown(obj) {
		obj = $(obj);
		if (!obj || !obj.next()) return;
		obj.next().insert({after:obj});
	}
	
		
	return {
	
		domloaded: function(e){	
			var options = Object.extend({
				name_unselected: ''
			}, KB.parseArgument(arguments[1] || {}));
			if ($(options.name_unselected)) {
				var unselected = $(options.name_unselected).select('select').first();
				if (unselected){
					var temp = (options.extended)?unselected.select('option').sort(sortId):unselected.select('option').sort(sortName);
					unselected.select('option').each(function(o){ o.remove(); });
					temp.each(function(o){ unselected.insert(o);});	
				}
			}
		},
		
		click: function(e){
			/* Sucht einen umschliessenden Link */
			var element = e.findElement('a');
			/* Soll eigentlich das div um den link finden. ist aber nicht zwangsläufig vorhanden (dd dl styling) */
			var elementUpDown = e.findElement('div');
			var name = (element)?element.getAttribute('rel'):null;
			var options = Object.extend({
				form_id: null,
				libraryName: '',
				name_selected: '',
				name_unselected: ''
			}, KB.parseArgument(arguments[1] || {}));

			/* Klick in Liste macht nichts */
			if (e.element().tagName.toUpperCase()=='OPTION') {
				//noop
			/* Hinzufuegen/Entfernen Link geklickt */
			} else if ((element && name)) {			
				move(name,options);
			/* Hoch Link geklickt  neu */
			} else if (element.hasClassName('js_moveup')) {
				var selected = $(options.name_selected).select('option').findAll(function(o){ return o.selected });
				selected.each(function(o){
					moveUp(o);
				});
			/* Runter Link geklickt  neu */
			} else if (element.hasClassName('js_movedown')) {
				var selected = $(options.name_selected).select('option').findAll(function(o){ return o.selected });
				selected.each(function(o){
					moveDown(o);
				});
			/* Hoch-Runter Link geklickt */
			} else if (elementUpDown) {
				var element = e.findElement('div');
				var selected = $(options.name_selected).select('option').findAll(function(o){ return o.selected });
				/* matcht auch gerne mal auf "group" */
				if (element.id.search(/up/i) > -1) {
					selected.each(function(o){
						moveUp(o);
					});
				}
				if (element.id.search(/down/i) > -1) {
					selected.each(function(o){
						moveDown(o);
					});
				}
			}
		},
		
		dblclick: function(e){
			var options = KB.parseArgument(arguments[1] || {});			
			var element = e.findElement('div');
			var name = (element)?element.id:null;
			// Name kann am besten ueber umschliessendes select ermittelt werden
			if (e.findElement('select').hasClassName('js_unselected')) {
				name = options.id+'_unselected';
			} else if (e.findElement('select').hasClassName('js_selected')) {
				name = options.id+'_selected';
			}
			
			/* Doppelklick auf einen Eintrag */
			if (e.element().tagName.toUpperCase()=='OPTION') {
				move(name,options);
			}
		},
		
		formsubmit: function(e){
			var options = Object.extend({
				form_id: null,
				libraryName: '',
				name_selected: '',
				name_unselected: ''
			}, arguments[1] || {});
			
			$$('.'+options.name_selected+', .'+options.name_unselected).each(function(el){
				if ($(el)) {
					Element.select(Element.select($(el),'select').first(),'option').each(function(o){o.selected = true});
				}
			});			
		},
		
		change: function(e){
			var options = Object.extend({
				notify_change: false
			}, KB.parseArgument(arguments[1] || {}));
			
			if (options.notify_change) document.fire('form:change');
		}
		
}})(),FormElementEvent);


/*
**
** File 'variants_select_form_element.js'
**
*/
var Variants_select_form_element = Object.extend({

	
	change: function(e){
	
		var options = Object.extend({
			image:'',
			path:'',
			imgType:'jpg',
			notify_change: false,
			template:'memorial'
		}, KB.parseArgument(arguments[1]));
		var image = $(options.image);	
		var src = options.path + options.template + '__' + $F(e.target)+'.'+options.imgType;
		if (image && image.src) image.src = src;
		
		if (options.notify_change) document.fire('form:changed');
	}
	
},FormElementEvent);

/*
**
** File 'wysiwyg_form_element.js'
**
*/
var Wysiwyg_form_element = Object.extend({

	formsubmit: function(e) {
		//Flash_file_single_new_form_element.uploaded = true;
		//e.element().onsubmit();
	},
		
	change: function(e){
		var options = Object.extend({
			notify_change: false
		}, KB.parseArgument(arguments[1] || {}));
		
		if (options.notify_change) document.fire('form:changed');
	}
	
},FormElementEvent);

/*
**
** File 'image_resize_form_element.js'
**
*/
var Image_resize_form_element = Object.extend({
	// Private 
	images: $H({}),
	
	domloaded: function(e){	
		options = KB.parseArgument(arguments[1] || {});
		
		options.sourceDimensions = $('image_resize_'+options.id).getDimensions();
		if (!options.sourceDimensions.width) options.sourceDimensions.width = $('image_resize_'+options.id).readAttribute('width');
		if (!options.sourceDimensions.height) options.sourceDimensions.height = $('image_resize_'+options.id).readAttribute('height');
		options.sourceDimensions.ratio = options.sourceDimensions.width / options.sourceDimensions.height;
		options.destDimensions = ($$('.aform_input_content').first())
			?{width: $$('.aform_input_content').first().getStyle('width').replace(/px/,''),height: $$('.aform_input_content').first().getStyle('height').replace(/px/,'')}
			:$('image_resize_content_'+options.id).getDimensions();
		
		if ( options.destDimensions.width > options.sourceDimensions.width ) {
			options.destDimensions.width = options.sourceDimensions.width;
			
		}
		options.destDimensions.height = options.destDimensions.width / options.sourceDimensions.ratio;
	//	if ( options.destDimensions.height > options.sourceDimensions.height ) options.destDimensions.height = options.sourceDimensions.height ;
	
		options.zoom = options.destDimensions.width / options.sourceDimensions.width;
		 
		var minWidth = Math.ceil(options.crop_x * options.zoom);
		var minHeight = Math.ceil(options.crop_y * options.zoom);
		 
		var ratio = {
			x: options.destDimensions.width / minWidth,
			y: options.destDimensions.height / minHeight 
		}
		
	//	if ()
		
		ratio = Math.min(ratio.x,ratio.y);
		options.ratio_multiplier = (ratio >= 1)? 1 : ratio;
		
		$('image_resize_'+options.id).writeAttribute({
			width: options.destDimensions.width,
			height: options.destDimensions.height		
		});
		
		if ($(options.form_id)){
			$(options.form_id).insert(new Element('input',{type:'hidden', id:'scale_'+options.id, name:'scale'+options.nameAddon}));
			$(options.form_id).insert(new Element('input',{type:'hidden', id:'width_'+options.id, name:'width'+options.nameAddon}));
			$(options.form_id).insert(new Element('input',{type:'hidden', id:'height_'+options.id, name:'height'+options.nameAddon}));
			$(options.form_id).insert(new Element('input',{type:'hidden', id:'x_'+options.id, name:'x'+options.nameAddon}));
			$(options.form_id).insert(new Element('input',{type:'hidden', id:'y_'+options.id, name:'y'+options.nameAddon}));
			$(options.form_id).insert(new Element('input',{type:'hidden', id:'custom_width_'+options.id, name:'custom_width'+options.nameAddon}));
			$(options.form_id).insert(new Element('input',{type:'hidden', id:'custom_height_'+options.id, name:'custom_height'+options.nameAddon}));
			$(options.form_id).insert(new Element('input',{type:'hidden', id:'temp_file_'+options.id, name:'temp_file'+options.nameAddon, value:options.imageUrl}));
			$(options.form_id).insert(new Element('input',{type:'hidden', id:'Bild des Nutzers', name:options.name+'_crop', value:options.nameAddon.replace(/_/,'')}));
		}
		
		this.images.set(options.id, new Cropper.KbImage(
			'image_resize_'+options.id,	{
				previewWrap: 'image_resize_'+options.id+'_preview',
				minWidth: minWidth * options.ratio_multiplier,
				minHeight: minHeight * options.ratio_multiplier, 
				ratioDim: { x: options.crop_x* options.ratio_multiplier , y: options.crop_y* options.ratio_multiplier  },
				kbOptions:options,
				displayOnInit: 1,
				onEndCrop: this.writeParams
			}
		));
	},
	
	
	writeParams: function(coords, dimensions,options){
		var id = this.kbOptions.id;
		var srcDimensions = this.kbOptions.sourceDimensions;
		var zoomFaktor =  Math.round(((dimensions.width / srcDimensions.width) *10000))/100;
		$( 'scale_' + id ).setValues(zoomFaktor);
		$( 'custom_width_' + id ).setValues(dimensions.width);
		$( 'custom_height_' + id ).setValues(dimensions.height);
		$( 'x_' + id ).setValues(coords.x1);
		$( 'y_' + id ).setValues(coords.y1);
		$( 'width_' + id ).setValues(Math.floor((coords.x2 - coords.x1) * this.kbOptions.ratio_multiplier));
		$( 'height_' + id ).setValues(Math.floor((coords.y2 - coords.y1) * this.kbOptions.ratio_multiplier));
	},
		
	change: function(e){
		var options = Object.extend({
			notify_change: false
		}, KB.parseArgument(arguments[1] || {}));
		
		if (options.notify_change) document.fire('form:changed');
	}
	
},FormElementEvent);


/*
**
** File 'dhtml_list_form_element.js'
**
*/


var Dhtml_list_form_element = Object.extend((function(){

	
	
	function addNode(){
		return $(element);
	}
	
	return {
		expression: '(-?[\\d]+)([\\[\\]]*)$',
		
		removeRow : function(e){		
			var element = e.findElement('.js_list_row');	
			if (!element) return null;			
			var parent = e.findElement('.js_list_container').select('.js_list_content').first();	
			if (!parent) return null;	
			var container = e.findElement('.js_list_container');
			
			var options = Object.extend({
				addon: ''
			}, KB.parseArgument(arguments[1] || {}));			
			
			// Element löschen
			element.remove();
			
			// Attribute der Zeilen neu Sortieren 
			parent.reOrder({className:'asset_list_row',attributes:['id','name'],expression: Dhtml_list_form_element.expression});			
			// Anzahl der Elemente zählen
			var count = parent.select('.js_list_row').length;
			// Attribute der Input Felder anpassen
			if (container) 
				container.reOrder({className:'js_list_input',attributes:['name'],offset:count,expression: Dhtml_list_form_element.expression});	
		},
		
		
		cancelRow : function(e,s){
			var edit = (e.findElement)?e.findElement('.js_list_row'):$(e);	
			var show = s;
			if (!edit || !show) return null;			
			edit.remove();
			show.show();
		},

		submitRow : function(e,s){		
			var edit = (e.findElement)?e.findElement('.js_list_row'):$(e);	
			if (!edit) return null;
			var params = $H(edit.collectValues()).values().flatten().toArray();	
			var texts  = $H(edit.collectValues({type:'text'})).values().flatten().toArray();
			var container = e.findElement('.js_list_container').select('.js_list_content').first();
			var show = s;
			var newElement = false;
			if (!show) {
				// Neues Element Erzeugen
				newElement = true;
				show = e.findElement('.js_list_container').select('.js_clone_show').first().clone();
				if (!show) return null;
				// Neues Element einfügen
				container.insert({bottom: show});
				// Anzahl der Elemente zählen
				var count = container.select('.js_list_row').length;
				// Attribute des erzeugten Elements anpassen
				show.reOrder({className:'asset_list_row',attributes:['id','name'],offset:count-1,expression: Dhtml_list_form_element.expression});
				// Attribute der Input Felder anpassen
				if (e.findElement('.js_list_container')) 
					e.findElement('.js_list_container').reOrder({className:'js_list_input',attributes:['name'],offset:count,expression: Dhtml_list_form_element.expression});
				
				
				// Bind Event Listener
				show.select('.js_list_delete').each(function(el) { 
				Event.observe(el,'click',Dhtml_list_form_element.removeRow.bindAsEventListener());
				});
				show.select('.js_list_edit').each(function(el) { 
					Event.observe(el,'click',Dhtml_list_form_element.editRow.bindAsEventListener());
				});
				show.select('.js_list_up').each(function(el) { 
					Event.observe(el,'click',Dhtml_list_form_element.moveUp.bindAsEventListener());
				});
				show.select('.js_list_down').each(function(el) { 
					Event.observe(el,'click',Dhtml_list_form_element.moveDown.bindAsEventListener());
				});
				
					
			}
			if (!show) return null;					
			
			show.setValues(params);			
			show.select('.js_list_show').each(function(e,index){
				var value = ((!Object.isUndefined(texts[index]))?texts[index]:texts.first()).strip();
				e.update((value.empty())?'&nbsp;':value);
			});			
			
			if (!newElement) edit.remove();
			else edit.clearValues();
			
			show.show();					
		},


		editRow : function(e){
			var element = (e.findElement)?e.findElement('.js_list_row'):$(e);	
			if (!element) return null;			
			var container = e.findElement('.js_list_container').cleanWhitespace();	
			if (!container) return null;
		
			var options = Object.extend({
			}, KB.parseArgument(arguments[1] || {}));	
			var params = $H(element.collectValues()).values().flatten().toArray()
			var edit = container.select('.js_clone_edit').first();
			var editListRow = edit.clone().setValues(params).show();	
			element.insert({before:editListRow});
			
			editListRow.select('.js_list_cancel').first().observe('click',Dhtml_list_form_element.cancelRow.bindAsEventListener(null,element));
			editListRow.select('.js_list_submit').first().observe('click',Dhtml_list_form_element.submitRow.bindAsEventListener(null,element));
			element.hide();
			
			return $(element);
		},
		
		moveDown: function(e){	
			var element = (e.findElement)?e.findElement('.js_list_row'):$(e);	
			if (!element) return null;			
			var next = element.next('.js_list_row');	
			if (!next) return element;
			next.insert({after:element});
			
			parent = e.findElement('.js_list_container').select('.js_list_content').first();
			parent = parent.reOrder({className:'asset_list_row',attributes:['id','name'],expression: Dhtml_list_form_element.expression});
		},
		
		moveUp: function(e){
			var element = (e.findElement)?e.findElement('.js_list_row'):$(e);	
			if (!element) return null;			
			var previous = element.previous('.js_list_row');	
			if (!previous) return element;
			previous.insert({before:element});		
			
			parent = e.findElement('.js_list_container').select('.js_list_content').first();
			parent = parent.reOrder({className:'asset_list_row',attributes:['id','name'],expression: Dhtml_list_form_element.expression});
		},
		
		change: function(e){
			var options = Object.extend({
				notify_change: false
			}, KB.parseArgument(arguments[1] || {}));
			
			if (options.notify_change) document.fire('form:changed');
		}
		

		
}})(),FormElementEvent);
/*
**
** File 'kbLightbox.js'
**
*/
// -----------------------------------------------------------------------------------
//
//	Lightbox v2.04
//	by Lokesh Dhakar - http://www.lokeshdhakar.com
//	Last Modification: 2/9/08
//
//	For more information, visit:
//	http://lokeshdhakar.com/projects/lightbox2/
//
//	Licensed under the Creative Commons Attribution 2.5 License - http://creativecommons.org/licenses/by/2.5/
//  	- Free for use in both personal and commercial projects
//		- Attribution requires leaving author name, author link, and the license info intact.
//	
//  Thanks: Scott Upton(uptonic.com), Peter-Paul Koch(quirksmode.com), and Thomas Fuchs(mir.aculo.us) for ideas, libs, and snippets.
//  		Artemy Tregubenko (arty.name) for cleanup and help in updating to latest ver of proto-aculous.
//
// -----------------------------------------------------------------------------------
/*

    Table of Contents
    -----------------
    Configuration

    Lightbox Class Declaration
    - initialize()
    - updateImageList()
    - start()
    - changeImage()
    - resizeImageContainer()
    - showImage()
    - updateDetails()
    - updateNav()
    - enableKeyboardNav()
    - disableKeyboardNav()
    - keyboardAction()
    - preloadNeighborImages()
    - end()
    
    Function Calls
    - document.observe()
   
*/
// -----------------------------------------------------------------------------------

//
//  Configurationl
//

var INIT_LIGHTBOX = false;

LightboxOptions = Object.extend(Object.extend({
	emptyImage: "/img/blank.gif",		
	fileIndicator: "/img/lightbox/loading.gif",		
	fileTopNavCloseImage: "/img/lightbox/close_small_bg.png",
	fileTopNavDLImage: "/img/blank.gif",
	fileTopNavCloseImageSize: {width:'25px',height:'22px'},
	fileTopNavDLImageSize: {width:'79px',height:'31px'},
	
	fileBottomNavCloseImage: "/img/lightbox/close_large.png",
	fileBottomNavDLImage: "/img/lightbox/downloadlabel.png",
	fileBottomNavPrevImage: "/img/lightbox/inner_prev.png",
	fileBottomNavNextImage: "/img/lightbox/inner_next.png",
	fileBottomNavPlayImage: "/img/lightbox/inner_slideshow_play.png",
	fileBottomNavPauseImage: "/img/lightbox/inner_slideshow_stop.png",
	fileBottomNavCloseImageSize: {width:'77px',height:'22px'},
	fileBottomNavDLImageSize: {width:'95px',height:'22px'},
	fileBottomNavPrevImageSize: {width:'14px',height:'14px'},
	fileBottomNavNextImageSize: {width:'14px',height:'14px'},
	fileBottomNavPlayImageSize: {width:'44px',height:'14px'},
	fileBottomNavPauseImageSize: {width:'44px',height:'14px'},
	
	
    overlayOpacity: 0.8,   // controls transparency of shadow overlay

    animate: true,         // toggles resizing animations
    resizeSpeed: 7,        // controls the speed of the image resizing animations (1=slowest and 10=fastest)

    borderSize: 5,         //if you adjust the padding in the CSS, you will need to update this variable

	// When grouping images this is used to write: Image # of #.
	// Change it for non-english localization
	labelImage: "Foto",
	labelOf: "von",
	
	endlessLoop: true,
	autoplaytiming: 10,
	autoplay: false,
	
	autoSize:true
	
},window.LightboxOptions || {}),Enumerable);

// -----------------------------------------------------------------------------------

var Lightbox = Class.create();
var kbLightbox = null;

Lightbox.prototype = {
    imageArray: [],
    activeImage: undefined,
    
	pe:null,  // Periodical Executer for Slideshow
	autoplaytiming: 10,
	autoplay: false,
	
    // initialize()
    // Constructor runs on completion of the DOM loading. Calls updateImageList and then
    // the function inserts html at the bottom of the page which is used to display the shadow 
    // overlay and the image container.
    //
    initialize: function() {    
        var LB = this;
        
		$H(LightboxOptions).each(function(option){
			if (Object.isString(option.value) && option.value.strip().empty()) 
				eval("LightboxOptions." + option.key + " = '" + LightboxOptions.emptyImage + "';");
		});
		
		
		this.updateImageList();
        
        this.keyboardAction = this.keyboardAction.bindAsEventListener(this);

        if (LightboxOptions.resizeSpeed > 10) LightboxOptions.resizeSpeed = 10;
        if (LightboxOptions.resizeSpeed < 1)  LightboxOptions.resizeSpeed = 1;

	    this.resizeDuration = LightboxOptions.animate ? ((11 - LightboxOptions.resizeSpeed) * 0.15) : 0;
	    this.overlayDuration = LightboxOptions.animate ? 0.2 : 0;  // shadow fade in/out duration

        // When Lightbox starts it will resize itself from 250 by 250 to the current image dimension.
        // If animations are turned off, it will be hidden as to prevent a flicker of a
        // white 250 by 250 box.
        var size = (LightboxOptions.animate ? 250 : 1) + 'px';
        

        // Code inserts html at the bottom of the page that looks similar to this:
        //
        //  <div id="overlay"></div>
        //  <div id="lightbox">
        //      <div id="outerImageContainer">
        //          <div id="imageContainer">
        //              <img id="lightboxImage">
        //              <div style="" id="hoverNav">
        //                  <a href="#" id="prevLink"></a>
        //                  <a href="#" id="nextLink"></a>
        //              </div>
        //              <div id="loading">
        //                  <a href="#" id="loadingLink">
        //                      <img src="images/loading.gif">
        //                  </a>
        //              </div>
        //          </div>
        //      </div>
        //      <div id="imageDataContainer">
        //          <div id="imageData">
        //              <div id="imageDetails">
        //                  <span id="caption"></span>
        //                  <span id="numberDisplay"></span>
        //              </div>
        //              <div id="bottomNav">
        //                  <a href="#" id="bottomNavClose">
        //                      <img src="images/close.gif">
        //                  </a>
        //              </div>
        //          </div>
        //      </div>
        //  </div>


        var objBody = $$('body')[0];

		objBody.appendChild(Builder.node('div',{id:'overlay'}));
	
        objBody.appendChild(Builder.node('div',{id:'lightbox'}, [
            Builder.node('div', {id:'imageDataContainerTop'},
                Builder.node('div',{id:'imageDataTop'}, [
                    Builder.node('div',{id:'imageDetailsTop'}, [
                        Builder.node('span',{id:'captionTop'}),
                        Builder.node('span',{id:'numberDisplayTop'})
                    ]),
                    Builder.node('div', {id:'topNav'}, [
                        Builder.node('a',{id:'topNavClose', className:'closeLink', href: '#' },
                            Builder.node('img', { src: LightboxOptions.fileTopNavCloseImage})
                        ),
						Builder.node('a',{id:'topNavDownload', href: '#' },
                            Builder.node('img', { src: LightboxOptions.fileTopNavDLImage})
                        )
                    ])
                ])
            ),
			Builder.node('div',{id:'outerImageContainer'}, 
                Builder.node('div',{id:'imageContainer' }, [
                    Builder.node('img',{id:'lightboxImage', src:LightboxOptions.emptyImage}), 
                    Builder.node('div',{id:'hoverNav',className:'hoverNav'}, [
                        Builder.node('a',{className:'prevLink', href: '#' }),
                        Builder.node('a',{className:'nextLink', href: '#' }),
                        Builder.node('a',{className:'closeLink', href: '#' })
                    ]),
                    Builder.node('div',{id:'loading'}, 
                        Builder.node('a',{id:'loadingLink', href: '#' }, 
                            Builder.node('img', {src: LightboxOptions.fileIndicator})
                        )
                    )
                ])
            ),
          Builder.node('div', {id:'imageDataContainer'},
                Builder.node('div',{id:'imageData'}, [
                    Builder.node('div',{id:'imageDetails'}, [
                        Builder.node('span',{id:'caption'}),
                        Builder.node('span',{id:'numberDisplay'})
                    ]),
                    Builder.node('div',{id:'bottomNav'}, [
						Builder.node('div',{className:'controlls'}, [
	                        Builder.node('a',{className:'prevLink', href: '#' },
								Builder.node('img', {className:'png',  src: LightboxOptions.fileBottomNavPrevImage, style:LightboxOptions.fileBottomNavPrevImageSize})
							),
	                        Builder.node('a',{className:'startStopLink', href: '#' },
								Builder.node('img', {className:'png', src: LightboxOptions.fileBottomNavPlayImage, style:LightboxOptions.fileBottomNavPlayImageSize})
							),
	                        Builder.node('a',{className:'nextLink', href: '#' },
								Builder.node('img', {className:'png', src: LightboxOptions.fileBottomNavNextImage, style:LightboxOptions.fileBottomNavNextImageSize})
							)
	                    ]),
                        Builder.node('a',{id:'bottomNavClose',className:'closeLink', href: '#' },
                            Builder.node('img', {className:'png', src: LightboxOptions.fileBottomNavCloseImage})
                        ),
						Builder.node('a',{id:'bottomNavDownload',className:'downloadLink', href: '#' },
                            Builder.node('img', {className:'png', src: LightboxOptions.fileBottomNavDLImage})
                        )
                    ])
                ])
            )
        ]));

		/* BUGFIX FÜR FF3 */
		$$('img').findAll(function(img){ 
			return (img.src && (img.src.strip().empty() ||  img.src.strip() == document.baseURI));
		}).each(function(emptyImage){
			$(emptyImage).remove();
		});
		
		$('overlay').hide().observe('click', (function() { this.end(); }).bind(this));
		$('lightbox').hide().observe('click', (function(event) { if (event.element().id == 'lightbox') this.end(); }).bind(this));
		$('outerImageContainer').setStyle({ width: size, height: size,padding: LightboxOptions.borderSize+'px' });
		$$('.prevLink').each(function(el){el.observe('click', (function(event) { this.slideshow(event,{stop:true}); this.changeImage(this.activeImage - 1);}).bindAsEventListener(LB))});
		$$('.nextLink').each(function(el){el.observe('click', (function(event) { this.slideshow(event,{stop:true}); this.changeImage(this.activeImage + 1);}).bindAsEventListener(LB))});
		$$('.closeLink').each(function(el){el.observe('click', (function(event) { event.stop(); this.end();}).bindAsEventListener(LB))});
		
		$$('.startStopLink').each(function(el){el.observe('click', LB.slideshow.bindAsEventListener(LB))});
		$('loadingLink').observe('click', (function(event) { event.stop(); this.end(); }).bind(this));
		//$('bottomNavClose').observe('click', (function(event) { event.stop(); this.end(); }).bind(this));		
		//$('topNavClose').observe('click', (function(event) { event.stop(); this.end(); }).bind(this));
		
		//BUGFIX PNG Ie6 
		$$('.closeLink img').first().setStyle(LightboxOptions.fileTopNavCloseImageSize);
		$$('#bottomNav .closeLink img').first().setStyle(LightboxOptions.fileBottomNavCloseImageSize);		
		$$('.downloadLink img').first().setStyle(LightboxOptions.fileTopNavDLImageSize);
		$$('#bottomNav .downloadLink img').first().setStyle(LightboxOptions.fileBottomNavDLImageSize);
		$$('.prevLink img').first().setStyle(LightboxOptions.fileBottomNavPrevImageSize);
		$$('#bottomNav .prevLink img').first().setStyle(LightboxOptions.fileBottomNavPrevImageSize);
		$$('.nextLink img').first().setStyle(LightboxOptions.fileBottomNavNextImageSize);
		$$('#bottomNav .nextLink img').first().setStyle(LightboxOptions.fileBottomNavNextImageSize);
		$$('.startStopLink img').first().setStyle(LightboxOptions.fileBottomNavPlayImageSize);
		$$('#bottomNav .startStopLink img').first().setStyle(LightboxOptions.fileBottomNavPlayImageSize);		
        var th = this;
        (function(){
            var ids = 
                'overlay lightbox outerImageContainer imageContainer lightboxImage hoverNav loading loadingLink ' + 
                'imageDataContainer imageData imageDetails caption numberDisplay bottomNav bottomNavClose bottomNavDownload ' +   
                'imageDataContainerTop imageDataTop imageDetailsTop captionTop numberDisplayTop topNav topNavClose topNavDownload';   
            $w(ids).each(function(id){
				th[id] = $(id); 
			});
			
			th['prevLink'] = $$('.hoverNav .prevLink').first();
			th['nextLink'] = $$('.hoverNav .nextLink').first();
			
        }).defer();
    },
	
	//
    // slideshow()
    // Loops through images w/ajax.
    //
	slideshow: function(event){
		if (event) event.stop(); 
		var options = Object.extend({
			stop: false,
			num: undefined
		}, KB.parseArgument(arguments[1] || {}));
		
		
		if (Object.isNumber(options.num)){
			var imageNum = options.num -1;
			this.activeImage = (imageNum < 0)?0:((imageNum >= this.imageArray.size())?this.imageArray.size():imageNum);
		}
		
		if (this.pe) {
			$$('.startStopLink img').each(function(el){
				el.src = LightboxOptions.fileBottomNavPlayImage;
			});
			this.pe.stop();
			this.pe = null;					
		} else if (!options.stop) {	
			$$('.startStopLink img').each(function(el){el.src = LightboxOptions.fileBottomNavPauseImage;});
			var num = (this.activeImage + 1) % this.imageArray.size();
			this.changeImage(num);			
			this.pe = new PeriodicalExecuter((function(pe){
				var num = (this.activeImage + 1) % this.imageArray.size();
				this.changeImage(num);
			}).bind(this),this.autoplaytiming);
		}
	},
	
	
    //
    // updateImageList()
    // Loops through anchor tags looking for 'lightbox' references and applies onclick
    // events to appropriate links. You can rerun after dynamically adding images w/ajax.
    //
    updateImageList: function() {   
        this.updateImageList = Prototype.emptyFunction;

        document.observe('click', (function(event){
            var target = event.findElement('a[rel^=lightbox]') || event.findElement('area[rel^=lightbox]');
            if (target) {
                event.stop();
                this.start(target);
            }
        }).bind(this));
    },
    
    //
    //  start()
    //  Display overlay and lightbox. If image is part of a set, add siblings to imageArray.
    //
    start: function(imageLink,autoplay,autoplaytiming) {
		if (autoplay == undefined) this.autoplay = LightboxOptions.autoplay;
		if (autoplaytiming == undefined) this.autoplaytiming = LightboxOptions.autoplaytiming;

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

        // stretch overlay to fill page and fade in
        var arrayPageSize = this.getPageSize();
        $('overlay').setStyle({ width: arrayPageSize[0] + 'px', height: arrayPageSize[1] + 'px' });

        new Effect.Appear(this.overlay, { duration: this.overlayDuration, from: 0.0, to: LightboxOptions.overlayOpacity });

        this.imageArray = [];
        var imageNum = 0;       

        if ((imageLink.rel == 'lightbox')){
            // if image is NOT part of a set, add single image to imageArray
            this.imageArray.push([imageLink.href, imageLink.title]);         
        } else {
            // if image is part of a set..
            this.imageArray = 
                $$(imageLink.tagName + '[href][rel="' + imageLink.rel + '"]').
                collect(function(anchor){ return [anchor.href, anchor.title]; }).
                uniq();
            
            while (this.imageArray[imageNum][0] != imageLink.href) { imageNum++; }
        }

        // calculate top and left offset for the lightbox 
        var arrayPageScroll = document.viewport.getScrollOffsets();
        var lightboxTop = arrayPageScroll[1] + (document.viewport.getHeight() / 10);
		if (parseInt (navigator.appVersion) >3 ) {
			if (navigator.appName.indexOf ('Microsoft')!= -1) {
				lightboxTop = arrayPageScroll[1] + (document.body.offsetHeight / 10);
			}
		}
		//if (Prototype.Browser.IE) lightboxTop += 50;
        var lightboxLeft = arrayPageScroll[0];
        this.lightbox.setStyle({ top: lightboxTop + 'px', left: lightboxLeft + 'px' }).show();
        
		// Downloadlink entfernen falls unsichtbar
		if ($('topNavDownload') && $('topNavDownload').getStyle('display') == 'none') $('topNavDownload').remove();
		if ($('bottomNavDownload') && $('bottomNavDownload').getStyle('display') == 'none') $('bottomNavDownload').remove();
		
		if (this.autoplay) {
			this.slideshow(null,{num:imageNum});
		} else {
			this.changeImage(imageNum);
		}
    },

    //
    //  changeImage()
    //  Hide most elements and preload image in preparation for resizing image container.
    //
    changeImage: function(imageNum) {   
        
        this.activeImage = (imageNum < 0)?this.imageArray.size()-1:((imageNum >= this.imageArray.size())?0:imageNum); // update global var


        // hide elements during transition
        if (LightboxOptions.animate) this.loading.show();
        this.lightboxImage.hide();
        this.hoverNav.hide();
     //   this.prevLink.hide();
     //   this.nextLink.hide();
		// HACK: Opera9 does not currently support scriptaculous opacity and appear fx
        this.imageDataContainer.setStyle({opacity: .0001});
        this.imageDataContainerTop.setStyle({opacity: .0001});
        this.numberDisplay.hide();      
        
        var imgPreloader = new Image();
        
        // once image is preloaded, resize image container

        imgPreloader.onload = (function(){
            this.lightboxImage.src = this.imageArray[this.activeImage][0];			
			this.lightboxImage.writeAttribute({width:imgPreloader.width, height:imgPreloader.height});
			this.lightboxImage.setStyle({width:imgPreloader.width+'px', height:imgPreloader.height+'px'});
			
			// PNG FIX FÜR IE
			if (KB.Browser.IE6 && this.lightboxImage.getStyle('filter')  && this.lightboxImage.getStyle('filter').length) {
				var filter = this.lightboxImage.getStyle('filter');
				var match = new RegExp((filter.match(/src\=[\"\']([^\"\']*)[\"\']/i) || ['']).last());
				this.lightboxImage.setStyle({filter:filter.replace(match,this.imageArray[this.activeImage][0])});				
			}
			
			// AUTOSIZE WENN BILD ZU GROSS
			if (LightboxOptions.autoSize==true){
			
				var dimensions = document.viewport.getDimensions();
				if (parseInt (navigator.appVersion) >3) {
					if (navigator.appName.indexOf ('Microsoft') != -1) {
						Object.extend(dimensions,{
							width : document.body.offsetWidth,
							height: document.body.offsetHeight
						});
					}
				}

				var mWidth  = dimensions.width-70;
				var mHeight = dimensions.height-90;
				var width  = 0;
				var height = 0;
				var arrayPageScroll = document.viewport.getScrollOffsets();
				var lightboxTop = arrayPageScroll[1] + (document.viewport.getHeight() / 10);
				if (Prototype.Browser.IE) lightboxTop += 50;
				
				
				if (imgPreloader.width > mWidth) {
					width 	= mWidth;
					ratio 	= imgPreloader.width / width;
					height	= imgPreloader.height / ratio;
				} else {
					width	= imgPreloader.width;
					height	= imgPreloader.height;
				}
				
				if (height > mHeight) {
					tmpH 	= mHeight;
					ratio	= height/tmpH;
					height 	= mHeight;
					width 	= width/ratio;					
					// calculate top and left offset for the lightbox 
			        var arrayPageScroll = document.viewport.getScrollOffsets();
			        var lightboxTop = arrayPageScroll[1] +  10;			        
				}
				
				// Differenz zu dem Errechneten Offset und dem momentanen Offset
				var diffY = lightboxTop - parseInt(this.lightbox.getStyle('top'));
				// Lightbox verschieben
				if (diffY.abs() > 5) new Effect.Move(this.lightbox,{x : 0,y : diffY , duration:0.5});
				
				width  = width.floor().abs();
				height = height.floor().abs();
				
				this.lightboxImage.setStyle({width:width+'px', height:height+'px'});
				this.resizeImageContainer(width, height);
			} else {
				this.resizeImageContainer(imgPreloader.width, imgPreloader.height);
			}
        }).bind(this);
		

		
        imgPreloader.src = this.imageArray[this.activeImage][0];
		var match = this.imageArray[this.activeImage][0].match(/(?:(?:special)|(?:files)|(?:downloads)|(?:data))[^0-9]*([0-9\_]+)?[^0-9\_]*([0-9\_]+)?(?:.*\.([a-zA-Z]*$))?/);
		var dlLink = this.imageArray[this.activeImage][0];
		var iid = (match[1] || '0').replace(/\_.*$/i,'');
		var size = (match[2] || match[1] || '0').replace(/^.*\_/i,'');
		var filetype = (match[3] || '');
		dlLink = dlLink.replace(new RegExp(size),((size.length > 0)?'0':''));
		dlLink+= ((dlLink.search(/\?/) < 0)?'?':'&')+'dl=1';
		if ($('topNavDownload'))    $('topNavDownload').writeAttribute('href',dlLink);
		if ($('bottomNavDownload')) $('bottomNavDownload').writeAttribute('href',dlLink);

		var name = (this.imageArray[this.activeImage][1] || '');
		var infoLink = "javascript:window.open('/data/photoalbum_show_download.php?iid="+iid+"&amp;pop=1&amp;w=800&amp;h=600&amp;filename="+name+"','flash_popup','width=800,height=640')"
		if ($('topNavInfo'))    $('topNavInfo').writeAttribute('href',infoLink);
		if ($('bottomNavInfo')) $('bottomNavInfo').writeAttribute('href',infoLink);
		
    },
    //
    //  resizeImageContainer()
    //
    resizeImageContainer: function(imgWidth, imgHeight) {

        // get current width and height
        var widthCurrent  = this.outerImageContainer.getWidth();
        var heightCurrent = this.outerImageContainer.getHeight();

        // get new width and height
     
		//var widthNew  = (imgWidth  + LightboxOptions.borderSize * 2);
        //var heightNew = (imgHeight + LightboxOptions.borderSize * 2);
		
		var widthNew  = (imgWidth);
        var heightNew = (imgHeight);
		
        // scalars based on change from old to new
        var xScale = (widthNew  / widthCurrent)  * 100;
        var yScale = (heightNew / heightCurrent) * 100;

        // calculate size difference between new and old image, and resize if necessary
        var wDiff = widthCurrent - widthNew  - (LightboxOptions.borderSize *2);
        var hDiff = heightCurrent - heightNew - (LightboxOptions.borderSize *2);

        if (hDiff != 0) new Effect.Scale(this.outerImageContainer, yScale, {scaleX: false, duration: this.resizeDuration, queue: 'front'}); 
        if (wDiff != 0) new Effect.Scale(this.outerImageContainer, xScale, {scaleY: false, duration: this.resizeDuration, delay: this.resizeDuration}); 

        // if new and old image are same size and no scaling transition is necessary, 
        // do a quick pause to prevent image flicker.
        var timeout = 0;
        if ((hDiff == 0) && (wDiff == 0)){
            timeout = 100;
            if (Prototype.Browser.IE) timeout = 250;   
        }

        (function(){
			
            this.prevLink.setStyle({ height: (imgHeight + LightboxOptions.borderSize *2) + 'px' });
            this.nextLink.setStyle({ height: (imgHeight + LightboxOptions.borderSize *2) + 'px' });
            this.imageDataContainer.setStyle({ width: (widthNew + LightboxOptions.borderSize *2) +  'px' });
            this.imageDataContainerTop.setStyle({ width: (widthNew + LightboxOptions.borderSize *2) + 'px' });
			this.hoverNav.setStyle({ width: (widthNew + LightboxOptions.borderSize *2) + 'px' });
            this.showImage();
        }).bind(this).delay(timeout / 1000);
    },
    
    //
    //  showImage()
    //  Display image and begin preloading neighbors.
    //
    showImage: function(){
        this.loading.hide();
        new Effect.Appear(this.lightboxImage, { 
            duration: this.resizeDuration, 
            queue: 'end', 
            afterFinish: (function(){ this.updateDetails(); }).bind(this) 
        });
        this.preloadNeighborImages();
    },

    //
    //  updateDetails()
    //  Display caption, image number, and bottom nav.
    //
    updateDetails: function() {
    
        // if caption is not null
        if (this.imageArray[this.activeImage][1] != ""){
            this.caption.update(this.imageArray[this.activeImage][1]).show();
            this.captionTop.update(this.imageArray[this.activeImage][1]).show();
        }
        
        // if image is part of set display 'Image x of x' 
        if (this.imageArray.length > 1){
            this.numberDisplay.update( LightboxOptions.labelImage + ' ' + (this.activeImage + 1) + ' ' + LightboxOptions.labelOf + '  ' + this.imageArray.length).show();
            this.numberDisplayTop.update( LightboxOptions.labelImage + ' ' + (this.activeImage + 1) + ' ' + LightboxOptions.labelOf + '  ' + this.imageArray.length).show();
        }

        new Effect.Parallel(
            [ 
             //   new Effect.SlideDown(this.imageDataContainer, { sync: true, duration: this.resizeDuration, from: 0.0, to: 1.0 }), 
                new Effect.Appear(this.imageDataContainer, { sync: true, duration: this.resizeDuration }), 
                new Effect.Appear(this.imageDataContainerTop, { sync: true, duration: this.resizeDuration }) 
            ], 
            { 
                duration: this.resizeDuration, 
                afterFinish: (function() {
	                // update overlay size and update nav
	                var arrayPageSize = this.getPageSize();
	                this.overlay.setStyle({ height: arrayPageSize[1] + 'px' });
	                this.updateNav();
                }).bind(this)
            } 
        );
    },

    //
    //  updateNav()
    //  Display appropriate previous and next hover navigation.
    //
    updateNav: function() {

        this.hoverNav.show();               

        // if not first image in set, display prev image button
      //  if (this.activeImage > 0) this.prevLink.show();

        // if not last image in set, display next image button
     //   if (this.activeImage < (this.imageArray.length - 1)) this.nextLink.show();
        
        this.enableKeyboardNav();
    },

    //
    //  enableKeyboardNav()
    //
    enableKeyboardNav: function() {
        document.observe('keydown', this.keyboardAction); 
    },

    //
    //  disableKeyboardNav()
    //
    disableKeyboardNav: function() {
        document.stopObserving('keydown', this.keyboardAction); 
    },

    //
    //  keyboardAction()
    //
    keyboardAction: function(event) {
        var keycode = event.keyCode;

        var escapeKey;
        if (event.DOM_VK_ESCAPE) {  // mozilla
            escapeKey = event.DOM_VK_ESCAPE;
        } else { // ie
            escapeKey = 27;
        }

        var key = String.fromCharCode(keycode).toLowerCase();
        
        if (key.match(/x|o|c/) || (keycode == escapeKey)){ // close lightbox
            this.end();
        } else if ((key == 'p') || (keycode == 37)){ // display previous image
            if (this.activeImage != 0){
                this.disableKeyboardNav();
                this.changeImage(this.activeImage - 1);
            }
        } else if ((key == 'n') || (keycode == 39)){ // display next image
            if (this.activeImage != (this.imageArray.length - 1)){
                this.disableKeyboardNav();
                this.changeImage(this.activeImage + 1);
            }
        }
    },

    //
    //  preloadNeighborImages()
    //  Preload previous and next images.
    //
    preloadNeighborImages: function(){
        var preloadNextImage, preloadPrevImage;
        if (this.imageArray.length > this.activeImage + 1){
            preloadNextImage = new Image();
            preloadNextImage.src = this.imageArray[this.activeImage + 1][0];
        }
        if (this.activeImage > 0){
            preloadPrevImage = new Image();
            preloadPrevImage.src = this.imageArray[this.activeImage - 1][0];
        }
    
    },

    //
    //  end()
    //
    end: function() {
        this.disableKeyboardNav();
        this.lightbox.hide();
		this.slideshow(null,{stop:true});
        new Effect.Fade(this.overlay, { duration: this.overlayDuration });
        $$('select', 'object', 'embed').each(function(node){ node.style.visibility = 'visible' });
    },

    //
    //  getPageSize()
    //
    getPageSize: function() {
	        
	     var xScroll, yScroll;
		
		if (window.innerHeight && window.scrollMaxY) {	
			xScroll = window.innerWidth + window.scrollMaxX;
			yScroll = window.innerHeight + window.scrollMaxY;
		} else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac
			xScroll = document.body.scrollWidth;
			yScroll = document.body.scrollHeight;
		} else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
			xScroll = document.body.offsetWidth;
			yScroll = document.body.offsetHeight;
		}
		
		var windowWidth, windowHeight;
		
		if (self.innerHeight) {	// all except Explorer
			if(document.documentElement.clientWidth){
				windowWidth = document.documentElement.clientWidth; 
			} else {
				windowWidth = self.innerWidth;
			}
			windowHeight = self.innerHeight;
		} else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
			windowWidth = document.documentElement.clientWidth;
			windowHeight = document.documentElement.clientHeight;
		} else if (document.body) { // other Explorers
			windowWidth = document.body.clientWidth;
			windowHeight = document.body.clientHeight;
		}	
		
		// for small pages with total height less then height of the viewport
		if(yScroll < windowHeight){
			pageHeight = windowHeight;
		} else { 
			pageHeight = yScroll;
		}
	
		// for small pages with total width less then width of the viewport
		if(xScroll < windowWidth){	
			pageWidth = xScroll;		
		} else {
			pageWidth = windowWidth;
		}

		return [pageWidth,pageHeight];
	}
}


function initLightbox() { 
	if (KB.Lightbox) {
		KB.Lightbox.updateImageList();
	} else {
		KB.Lightbox = new Lightbox();
	}
}

//document.observe('dom:loaded', function () { kbLightbox = new Lightbox(); });
//function initLightbox() { 
//	if (!INIT_LIGHTBOX){
//		return new Lightbox(); 
//		INIT_LIGHTBOX = true;
//	} else return null;
//}
if (KB.Browser.IE){
	Event.observe(window,'load', function () { initLightbox();});
} else {
	document.observe('dom:loaded', function () { initLightbox();});
}
document.observe('lightbox:changed', function () { initLightbox()});/* Error Loading main.js */
/* Error Loading functions.js */

/* End of combine.js */