function scrollable(divId, firstCellId, secondCellId, speed, enableRandom, itemNum, itemWidth, direction) {
	this.div = document.getElementById(divId);
	this.firstCell = document.getElementById(firstCellId);
	this.secondCell = document.getElementById(secondCellId);
	this.speed = speed;
	this.secondCell.innerHTML = this.firstCell.innerHTML;
	//this.div.scrollLeft = this.div.scrollWidth;
	if ( enableRandom == true )
		this.div.scrollLeft = (Math.floor(Math.random()*itemNum)) * itemWidth;
	else
		this.div.scrollLeft = 0;
	this.marquee = null;
	if ( direction != null && direction != "" )
		this.direction = direction;
	else
		this.direction = "left";
	
	this.prev = function() {
		if ( this.marquee != null )
		{
			clearInterval(this.marquee);
			this.marquee = null;
		}
		
		var instance = this;
		this.marquee = setInterval(function(){instance.doLeftMarquee();}, instance.speed);
		this.div.onmouseover = function(){clearInterval(instance.marquee);instance.marquee=null;}
		this.div.onmouseout = function(){var i = instance;instance.marquee = setInterval(function(){i.doLeftMarquee();}, i.speed);}
		this.direction = "left";
	}
	
	this.next = function() {
		if ( this.marquee != null )
		{
			clearInterval(this.marquee);
			this.marquee = null;
		}
		
		var instance = this;
		this.marquee = setInterval(function(){instance.doRightMarquee();}, instance.speed);
		this.div.onmouseover = function(){clearInterval(instance.marquee)}
		this.div.onmouseout = function(){var i = instance;instance.marquee = setInterval(function(){i.doRightMarquee();}, i.speed);}
		this.direction = "right";
	}
	
	this.doLeftMarquee = function() {
		if ( this.secondCell.offsetWidth-this.div.scrollLeft <= 0 )
			this.div.scrollLeft -= this.firstCell.offsetWidth;
		else
			this.div.scrollLeft++;
	}
	
	this.doRightMarquee = function() {
		if ( this.div.scrollLeft <= 0 )
			this.div.scrollLeft += this.secondCell.offsetWidth;
		else
			this.div.scrollLeft--;
	}
	
	this.start = function() {
		if ( this.direction == "right" )
			this.next();
		else
			this.prev();
	}
	
	this.pause = function() {
		if ( this.marquee != null )
		{
			clearInterval(this.marquee);
			this.marquee = null;
		}
		
		this.div.onmouseover = null;
		this.div.onmouseout = null;
	}
	
	this.start();
}

function rollOverImg(name, path) {
	document[name].src = path;
}

/*
 * Utility class
 */
(function(){

	var l=this;
	l.deffect = {
	
		popUpLayerId: "popUpLayer",
		divPopUpContainer: null,
		popUpLayerBackgroundId: "popUpLayerBg",
		divPopUpBackground: null,
		overlayForDivPopUp: null,
		hasClosePopUpRequest: false,
		image_interval: null,
		checking_images_interval: 50,
		image_timeOut: null,
		checking_images_timeOut: 3000,
		autocompleter:{defaults:{
			inputClass: "ac_input",
			resultsClass: "ac_results",
			loadingClass: "ac_loading",
			headerClass: "ac_header",
			minChars: 1,
			delay: 400,
			matchCase: false,
			matchSubset: true,
			matchContains: false,
			cacheLength: 10,
			max: 100,
			mustMatch: false,
			extraParams: {},
			selectFirst: false,
			formatItem: function(row) { return row[0]; },
			formatMatch: null,
			autoFill: false,
			width: 0,
			multiple: false,
			multipleSeparator: ", ",
			highlight: function(value, term) {
				return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
			},
			scroll: true,
			scrollHeight: 180,
			includeHeader: true,
			isHeader: function(row) {
				if ( row[0].substring(0,1) == "[" && row[0].substring(row[0].length-1) == "]" )
					return true;
				return false;
			},
			formatHeader: function(row) { return row[0].substring(1, row[0].length-1); }
		}},
		userAgent: navigator.userAgent.toLowerCase(),
		onload_event_timeout: 0,
		isReady: false,
		readyList: [],
		array: {
			inArray:function(object, array) {
				for ( var i=0; i<array.length; i++ ) {
					if ( array[i] === object ) { return i; }
				}
				return -1;
			},
			
			remove:function(array, from, to) {
				var rest = array.slice((to || from) + 1 || array.length);
				array.length = from < 0 ? array.length + from : from;
				return array.push.apply(array, rest);
			}
		},
		overlay: {
			TOP_LEFT: "tl",
			TOP_RIGHT: "tr",
			BOTTOM_LEFT: "bl",
			BOTTOM_RIGHT: "br",
			FADE:function(overlay, dur) {
				var fin = {
					attributes: {opacity:{from:0, to:1}},
					duration: dur
				}
				var fout = {
					attributes: {opacity:{to:0}},
					duration: dur
				}
				return new deffect.overlay.effect(overlay, fin, fout);
			},
			effect:function(overlay, attrIn, attrOut) {
				var anim = new animation(overlay);
				
				this.animateIn = function() {
					anim.setAttr(attrIn);
					anim.start();
				}
				
				this.animateOut = function() {
					anim.setAttr(attrOut);
					anim.start();
				}
			},
			configVisible:function(overlay, visible) {
				if ( overlay == null )
					return;
				
				if ( visible ) {
					deffect.css.set(overlay, "visibility", "visible");
					deffect.css.set(overlay, "display", "block");
				} else {
					deffect.css.set(overlay, "visibility", "hidden");
					deffect.css.set(overlay, "display", "none");
				}
			}
		},
		css: {
			get:function(elem, property, force, extend) {
				if ( property == "width" || property == "height" ) {
					var L,G={position:"absolute",visibility:"hidden",display:"block"},K=property=="width"?["Left","Right"]:["Top","Bottom"];
					function I() {
						L=property=="width"?elem.offsetWidth:elem.offsetHeight;
						if(extend==="border"){return;}
						deffect.each(K, function(){
							if(!extend){L-=parseFloat(curCSS(elem,"padding"+this,true))||0}
							if(extend==="margin"){L+=parseFloat(curCSS(elem,"margin"+this,true))||0}else{L-=parseFloat(curCSS(elem,"border"+this+"Width",true))||0}
						})
					}
					if(elem.offsetWidth!==0){I()}else{deffect.css.swap(elem,G,I)}
					return Math.max(0,Math.round(L));
				}
				return curCSS(elem, property, force);
				
				function curCSS(elem, name, force) {
					var ret, style = elem.style;
					var defaultView = document.defaultView || {};
			
					// A helper method for determining if an element's values are broken
					function color( elem ) {
						if ( !deffect.browser().safari )
							return false;
			
						// defaultView is cached
						var ret = defaultView.getComputedStyle(elem, null);
						return !ret || ret.getPropertyValue("color") == "";
					}
			
					// We need to handle opacity special in IE
					if ( name == "opacity" && deffect.browser().msie ) {
						return "1";
					}
					// Opera sometimes will give the wrong display answer, this fixes it, see #2037
					if ( deffect.browser().opera && name == "display" ) {
						var save = style.outline;
						style.outline = "0 solid black";
						style.outline = save;
					}
			
					// Make sure we're using the right name for getting the float value
					if ( name.match( /float/i ) )
						name = styleFloat;
			
					if ( !force && style && style[ name ] )
						ret = style[ name ];
			
					else if ( defaultView.getComputedStyle ) {
			
						// Only "float" is needed here
						if ( name.match( /float/i ) )
							name = "float";
			
						name = name.replace( /([A-Z])/g, "-$1" ).toLowerCase();
			
						var computedStyle = defaultView.getComputedStyle( elem, null );
			
						if ( computedStyle && !color( elem ) )
							ret = computedStyle.getPropertyValue( name );
			
						// If the element isn't reporting its values properly in Safari
						// then some display: none elements are involved
						else {
							var swap = [], stack = [], a = elem, i = 0;
			
							// Locate all of the parent display: none elements
							for ( ; a && color(a); a = a.parentNode )
								stack.unshift(a);
			
							// Go through and make them visible, but in reverse
							// (It would be better if we knew the exact display type that they had)
							for ( ; i < stack.length; i++ )
								if ( color( stack[ i ] ) ) {
									swap[ i ] = stack[ i ].style.display;
									stack[ i ].style.display = "block";
								}
			
							// Since we flip the display style, we have to handle that
							// one special, otherwise get the value
							ret = name == "display" && swap[ stack.length - 1 ] != null ?
								"none" :
								( computedStyle && computedStyle.getPropertyValue( name ) ) || "";
			
							// Finally, revert the display styles back
							for ( i = 0; i < swap.length; i++ )
								if ( swap[ i ] != null )
									stack[ i ].style.display = swap[ i ];
						}
			
						// We should always get a number back from opacity
						if ( name == "opacity" && ret == "" )
							ret = "1";
			
					} else if ( elem.currentStyle ) {
						var camelCase = name.replace(/\-(\w)/g, function(all, letter){
							return letter.toUpperCase();
						});
			
						ret = elem.currentStyle[ name ] || elem.currentStyle[ camelCase ];
			
						// From the awesome hack by Dean Edwards
						// http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
			
						// If we're not dealing with a regular pixel number
						// but a number that has a weird ending, we need to convert it to pixels
						if ( !/^\d+(px)?$/i.test( ret ) && /^\d/.test( ret ) ) {
							// Remember the original values
							var left = style.left, rsLeft = elem.runtimeStyle.left;
			
							// Put in the new values to get a computed value out
							elem.runtimeStyle.left = elem.currentStyle.left;
							style.left = ret || 0;
							ret = style.pixelLeft + "px";
			
							// Revert the changed values
							style.left = left;
							elem.runtimeStyle.left = rsLeft;
						}
					}
			
					return ret;
				}
			},
			set:function(elem, key, value) {
				if ( typeof key == 'string' ) {
					elem.style[key] = value;
				} else {
					var length = key.length;
					if ( length == undefined ) {
						for ( name in key ) {
							elem.style[name] = key[name];
						}
					}
				}
			},
			swap:function(elem, options, callback) {
				var old = {};

				// Remember the old values, and insert the new ones
				for ( var name in options ) {
					old[name] = elem.style[name];
					elem.style[name] = options[name];
				}

				callback.call(elem);

				// Revert the old values
				for ( var name in options ) {
					elem.style[name] = old[name];
				}
			}
		},
	
		$:function() {
			if ( arguments.length > 0 && this.isFunction(arguments[0]) ) {
				deffect.addLoadEvent(arguments[0]);
			} else if ( arguments.length == 1 && this.isElement(arguments[0]) ) {
				arguments[0].height = function() {
					return deffect.css.get(this, "height");
				}
				arguments[0].css = function() {
					switch (arguments.length) {
						case 0:
							break;
							
						case 1:
							return deffect.css.get(this, arguments[0]);
							
						case 2:
							deffect.css.set(this, arguments[0], arguments[1]);
							break;
					}
				}
				return arguments[0];
			} else if ( arguments.length == 1 && this.isDocument(arguments[0]) ) {
				arguments[0].ready = function(E) {
					B();
					if ( deffect.isReady )
						E.call(document, deffect);
					else
						deffect.readyList.push(E);
					
					var x;
					function B(){
						if(x){return}
						x=true;
						if ( document.addEventListener ) {
							document.addEventListener("DOMContentLoaded", function(){
								document.removeEventListener("DOMContentLoaded", arguments.callee, false);
								deffect.ready();
							}, false);
						} else {
							if ( document.attachEvent ) {
								document.attachEvent("onreadystatechange", function(){
									if ( document.readyState==="complete" ) {
										document.detachEvent("onreadystatechange", arguments.callee);
										deffect.ready();
									}
								});
							}
						}
					}
				}
				return arguments[0];
			} else {
				var oElm = document;
				var strTagName = "*";
				var separator = ".";
				var strClassName = arguments[0];
				if ( arguments.length > 1 ) {
					if ( arguments[0] != null )
						oElm = arguments[0];
					strClassName = arguments[1];
				}
				var arrayOfStr = strClassName.split(separator);
				if ( arrayOfStr.length > 1 ) {
					strTagName = arrayOfStr[0];
					strClassName = arrayOfStr[1];
				}
				var arrReturnElements = deffect.getElements(oElm, strTagName, strClassName);
				if ( arrReturnElements.length == 0 ) { arrReturnElements = deffect.getElements(oElm, strClassName, ""); }
				var lastshowntabindex, lastshownpaneindex;
				
				arrReturnElements.tabs = function() {
					if ( arguments.length > 0 ) {
						var R = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g;
						var Z = [];
						//var nodes = [document];
						var tabs = [];
						var panes;
						var defaultShown = arguments[1];
						var onclick = arguments[2];
						var event = arguments[3];
						var consistent = arguments[4];
						while ( (W=R.exec(arguments[0]))!==null ) {
							Z.push(W[1]);	
						}
						panes = deffect.$(document, Z[0]);
						for ( var i=1; i<Z.length; i++ ) {
							for ( var j=0; j<panes.length; j++ ) {
								temp = deffect.$(panes[j], Z[i]);
								if ( i==(Z.length-1) )
									panes[j] = temp;
								else if ( temp != null && temp.length > 0 )
									panes[j] = temp[0];
							}
						}
						if ( panes != null && panes.length > 0 ) {
							for ( var i=0; i<arrReturnElements.length; i++ ) {
								if ( arrReturnElements[i].hasChildNodes() ) {
									tabs[i] = arrReturnElements[i];
									var temp = 0;
									for ( var j=0; j<arrReturnElements[i].childNodes.length; j++ ) {
										if ( arrReturnElements[i].childNodes[j].nodeType != 1 ) { continue; }
										if ( panes[i].length-1 >= temp ) {
											deffect.attr(arrReturnElements[i].childNodes[j], "tabsindex", j);
											deffect.attr(arrReturnElements[i].childNodes[j], "paneindex", temp);
											deffect.attr(arrReturnElements[i].childNodes[j], "componentindex", i);
											if ( defaultShown != null && deffect.isPositiveInteger(defaultShown) ) {
												if ( temp == defaultShown )
													showTab(arrReturnElements[i].childNodes[j]);
											} else if ( temp == 0 ) {
												showTab(arrReturnElements[i].childNodes[j]);
											}
											//var onclick = arguments[1];
											
											function handler() {
												if ( lastshowntabindex != null && lastshowntabindex != parseInt(this.getAttribute("tabsindex")) ) {
													if ( consistent ) {
														for ( var k=0; k<tabs.length; k++ ) {
															tabs[k].childNodes[lastshowntabindex].className = "";
															if ( tabs[k].childNodes[lastshowntabindex].hasChildNodes() ) {
																for ( var l=0; l<this.parentNode.childNodes[lastshowntabindex].childNodes.length; l++ ) {
																	if ( tabs[k].childNodes[lastshowntabindex].childNodes[l].nodeType != 1 ) { continue; }
																	tabs[k].childNodes[lastshowntabindex].childNodes[l].className = "";
																}
															}
															panes[k][lastshownpaneindex].style.display = "none";
														}
													} else {
														this.parentNode.childNodes[lastshowntabindex].className = "";
														if ( this.parentNode.childNodes[lastshowntabindex].hasChildNodes() ) {
															for ( var k=0; k<this.parentNode.childNodes[lastshowntabindex].childNodes.length; k++ ) {
																if ( this.parentNode.childNodes[lastshowntabindex].childNodes[k].nodeType != 1 ) { continue; }
																this.parentNode.childNodes[lastshowntabindex].childNodes[k].className = "";
															}
														}
														panes[parseInt(this.getAttribute("componentindex"))][lastshownpaneindex].style.display = "none";
													}
												}
											
												if ( panes[parseInt(this.getAttribute("componentindex"))][parseInt(this.getAttribute("paneindex"))].style == null
													|| panes[parseInt(this.getAttribute("componentindex"))][parseInt(this.getAttribute("paneindex"))].style.display == ""
													|| panes[parseInt(this.getAttribute("componentindex"))][parseInt(this.getAttribute("paneindex"))].style.display == "none" ) {
													if ( consistent ) {
														for ( var k=0; k<tabs.length; k++ ) {
															showTab(tabs[k].childNodes[parseInt(this.getAttribute("tabsindex"))]);
														}
													} else { showTab(this); }
												}
													
												if ( typeof onclick == 'function' )
													onclick(this);
											}
											
											if ( event != null && typeof event == "string" && (event.toLowerCase() == "mouseover" || event.toLowerCase() == "onmouseover") ) {
												arrReturnElements[i].childNodes[j].onmouseover = handler;
											} else {
												arrReturnElements[i].childNodes[j].onclick = handler;
											}
											temp++;
											
										}
									}
								}
							}
						}
					}
					
					function showTab(object) {
						object.className = "current";
						if ( object.hasChildNodes() ) {
							for ( var i=0; i<object.childNodes.length; i++ ) {
								if ( object.childNodes[i].nodeType != 1 ) { continue; }
								object.childNodes[i].className = "current";
							}
						}
						panes[parseInt(object.getAttribute("componentindex"))][parseInt(object.getAttribute("paneindex"))].style.display = "block";
						lastshowntabindex = parseInt(object.getAttribute("tabsindex"));
						lastshownpaneindex = parseInt(object.getAttribute("paneindex"));
					}
				}
				
				arrReturnElements.autocomplete = function(urlOrData, options) {
					var isUrl = typeof urlOrData == "string";
					var autocompleters = [];
					/*
					options = {
						url: isUrl ? urlOrData : null,
						data: isUrl ? null : urlOrData,
						delay: isUrl ? deffect.autocompleter.defaults.delay : 10,
						max: options && !options.scroll ? 10 : 150,
						minChars: options && options.minChars ? options.minChars : deffect.autocompleter.defaults.minChars,
						matchCase: options && options.matchCase ? options.matchCase : deffect.autocompleter.defaults.matchCase
					};
					*/
					options = deffect.extend({}, deffect.autocompleter.defaults, {
						url: isUrl ? urlOrData : null,
						data: isUrl || typeof urlOrData == 'function' ? null : urlOrData,
						trigger: typeof urlOrData == 'function' ? urlOrData : null,
						delay: isUrl ? deffect.autocompleter.defaults.delay : 10,
						max: options && !options.scroll ? 10 : 150
					}, options);
					
					// if highlight is set to false, replace it with a do-nothing function
					options.highlight = options.highlight || function(value) { return value; };
					
					// if the formatMatch option is not specified, then use formatItem for backwards compatibility
					options.formatMatch = options.formatMatch || options.formatItem;
					
					for ( var i=0; i<arrReturnElements.length; i++ ) {
						autocompleters.push(new autocompleter(arrReturnElements[i], options));
					}
					
					return autocompleters;
				}
				
				return (arrReturnElements);
			}
		},
		
		getElements:function(oElm, strTagName, strClassName) {
			var arrElements = (strTagName == "*" && oElm.all)? oElm.all : oElm.getElementsByTagName(strTagName);
			var arrReturnElements = [];
			if ( strClassName.charAt(0) == "#" ) {
				arrElements = new Array();
				var element = oElm.getElementById(strClassName.substring(1));
				if ( element != null )
					arrReturnElements.push(element);
			}
			for(var i=0; i<arrElements.length; i++){
				var temp = arrElements[i];      
				if(deffect.check(temp, strClassName)){
					arrReturnElements.push(temp);
				}
			}
			return arrReturnElements;
		},
		
		check:function(oElm, strClassName) {
			strClassName = strClassName.replace(/\-/g, "\\-");
			var oRegExp = new RegExp("(^|\\s)" + strClassName + "(\\s|$)");
			return oRegExp.test(oElm.className);
		},
		
		isElement:function(o) {
			try {
				return (
					typeof HTMLElement === "object" ? o instanceof HTMLElement : //DOM2
					typeof o === "object" && o.nodeType === 1 && typeof o.nodeName==="string"
				);
			} catch (err) {
				return false;
			}
		},
		
		isDocument:function(o) {
			return ( o === document );
		},
		
		isString:function(o) {
			return ( typeof o === "string" );
		},
		
		isFunction:function(o) {
			return ( typeof o === "function" );
		},
		
		addLoadEvent:function(func) {
			var oldonload = window.onload;
			if (typeof window.onload != 'function') {
				window.onload = func;
			} else {
				window.onload = function() {
					if (oldonload)
						oldonload();
					func();
					/*
					setTimeout(func, this.onload_event_timeout);
					this.onload_event_timeout = this.onload_event_timeout + 500;
					*/
				}
			}
		},
		
		attr:function(object, name, index) {
			object.setAttribute(name, index+name.charAt(0));
		},
		
		openPopUpDiv:function(url, config, method) {
			this.$(document).ready(function() {
				fireRequest();
			});
	
			return false;
			
			function fireRequest() {
				deffect.hasClosePopUpRequest = false;
				
				if ( deffect.divPopUpContainer == null ) {
					deffect.divPopUpContainer = deffect.createEl('div',
						{'class':"popUpLayer", id:deffect.popUpLayerId, name:deffect.popUpLayerId},
						{},
						'');
					document.body.appendChild(deffect.divPopUpContainer);
					/* *** IMPORTANT: This is a BUG FIX for Internet Explorer *** */
					//if ( self.frames[deffect.popUpLayerId].name != deffect.popUpLayerId )
						//self.frames[deffect.popUpLayerId].name = deffect.popUpLayerId;
				}
				if ( deffect.divPopUpBackground == null ) {
					deffect.divPopUpBackground = deffect.createEl('div',
						{'class':"popUpLayerBg", id:deffect.popUpLayerBackgroundId, name:deffect.popUpLayerBackgroundId},
						{},
						'');
					document.body.appendChild(deffect.divPopUpBackground);
				}
				
				if ( !deffect.hasClosePopUpRequest )
					if ( method != null && deffect.isString(method) )
						connect.asyncRequest(method.toUpperCase(), url, {success:callback, argument:config});
					else
						connect.asyncRequest('GET', url, {success:callback, argument:config});
			}
	
			function callback(o) {
				if ( deffect.hasClosePopUpRequest )
					return;
					
				if ( o.responseText != undefined ) {
					deffect.divPopUpContainer.style.visibility = "hidden";
					deffect.divPopUpContainer.style.backgroundColor = "#FFFFFF";
					deffect.divPopUpContainer.className = "overlayborder";
					
					deffect.divPopUpContainer.innerHTML = o.responseText;
					
					// Register javascript function embedded in popup
					var script = deffect.divPopUpContainer.getElementsByTagName("script");
					for ( var i=0; i<script.length; i++ ) {
						eval(script[i].text);
					}
				}
				
				if ( o.argument != undefined )
				{
					var configuration = o.argument;
					
					// Reset width and height for div first
					deffect.divPopUpContainer.style.width = "";
					deffect.divPopUpContainer.style.height = "";
					
					deffect.overlayForDivPopUp = new overlay(deffect.divPopUpContainer, configuration);
					if ( !deffect.hasClosePopUpRequest )
						deffect.overlayForDivPopUp.show();
					
					if ( parseInt(deffect.divPopUpContainer.style.left) < 0 )
						deffect.divPopUpContainer.style.left = "0px";
					if ( parseInt(deffect.divPopUpContainer.style.top) < 0 )
						deffect.divPopUpContainer.style.top = "0px";
						
					if ( configuration.modal ) {
						deffect.divPopUpBackground.style.width = deffect.getDocumentWidth() + 'px';
						deffect.divPopUpBackground.style.height = deffect.getDocumentHeight() + 'px';
						deffect.divPopUpBackground.style.visibility = "visible";
						deffect.divPopUpBackground.style.zIndex = 1;
						deffect.divPopUpBackground.style.opacity = 0.5;
						deffect.divPopUpBackground.style.filter = "alpha(opacity=50)";
						//deffect.divPopUpBackground.style.backgroundColor = "#000000"; // Black color
						deffect.divPopUpBackground.style.backgroundColor = "#FFFFFF";
						deffect.divPopUpBackground.style.left = "0px";
						deffect.divPopUpBackground.style.top = "0px";
						deffect.divPopUpBackground.style.overflow = "auto";
						deffect.divPopUpBackground.style.position = "absolute";
					}
				}
			}
		},
		
		createEl:function(tagName, arr_attributes, arr_style, innerText) {
			var element = document.createElement(tagName);
			if (arr_attributes) {
				for (var k in arr_attributes) {
					if (k == 'class')
						element.className = arr_attributes[k];
					else if (k == 'id')
						element.id = arr_attributes[k];
					else
						element.setAttribute(k, arr_attributes[k]);
				}
			}
			if (arr_style) {
				for (var k in arr_style)
					element.style[k] = arr_style[k];
			}
			if (innerText)
				element.appendChild(document.createTextNode(innerText));
			return element;
		},
		
		center:function(element) {
			// retrieve required dimensions
			var eltDims = this.getDimensions(element);
				
			// calculate the center of the page using the browser and element dimensions
			var x = parseInt((this.getViewportWidth() - eltDims.width) / 2 + this.getDocumentScrollLeft());
			var y = parseInt((this.getViewportHeight() - eltDims.height) / 2 + this.getDocumentScrollTop());
				
			element.style.left = x + "px";
			element.style.top = y + "px";
		},
		
		getDimensions:function(element) {
			/*
			var display = element.style.display;
			if (display != 'none' && display != null) // Safari bug
				return {width: element.offsetWidth, height: element.offsetHeight};

			var originalWidth = element.clientWidth;
			var originalHeight = element.clientHeight;
			return {width: originalWidth, height: originalHeight};
			*/
			var w, h = 0;
			var options = {visibility: "hidden", display: "block"};
			var display = element.style.display;
			if (display != 'none' && display != null) // Safari bug
				deffect.css.swap(element, options, function(){w=element.offsetWidth;h=element.offsetHeight});
			else
				deffect.css.swap(element, options, function(){w=element.clientWidth;h=element.clientHeight});
			return {width: w, height: h};
		},
		
		getViewportWidth:function() {
			var O = self.innerWidth;
			var P = document.compatMode;
			if ( P ) { O=(P=="CSS1Compat")?document.documentElement.clientWidth:document.body.clientWidth; }
			return O;
		},
					
		getViewportHeight:function() {
			var O = self.innerHeight;
			var P = document.compatMode;
			if ( P ) { O=(P=="CSS1Compat")?document.documentElement.clientHeight:document.body.clientHeight; }
			return O;
		},
		
		getDocumentHeight:function() {
			var P=(document.compatMode!="CSS1Compat")?document.body.scrollHeight:document.documentElement.scrollHeight;
			var O=Math.max(P, this.getViewportHeight());
			return O;
		},

		getDocumentWidth:function() {
			var P=(document.compatMode!="CSS1Compat")?document.body.scrollWidth:document.documentElement.scrollWidth;
			var O=Math.max(P, this.getViewportWidth());
			return O;
		},
		
		getDocumentScrollLeft:function(O) {
			O = O||document;
			return Math.max(O.documentElement.scrollLeft, O.body.scrollLeft);
		},
		
		getDocumentScrollTop:function(O) {
			O = O||document;
			return Math.max(O.documentElement.scrollTop, O.body.scrollTop);
		},
		
		findPos:function(obj) {
			var curleft = curtop = 0;
			if ( obj.offsetParent ) {
				do {
					curleft += obj.offsetLeft;
					curtop += obj.offsetTop;
				} while ( obj = obj.offsetParent );
			} else if ( obj.x && obj.y ) {
				curleft += obj.x;
				curtop += obj.y;
			}
			return {left: curleft, top: curtop};
		},
		
		closePopUpDiv:function() {
			deffect.hasClosePopUpRequest = true;
			if ( deffect.overlayForDivPopUp != null) {
				deffect.overlayForDivPopUp.hide();
			} else if ( deffect.divPopUpContainer != null ) {
				deffect.divPopUpContainer.style.visibility = "hidden";
				deffect.divPopUpContainer.innerHTML = "";
			}
			if ( deffect.divPopUpBackground != null )
				deffect.divPopUpBackground.style.visibility = "hidden";
			return false;
		},
		
		isImageReady:function(img) {
			// During the onload event, IE correctly identifies any images that
			// werenˇ¦t downloaded as not complete. Others should too. Gecko-based
			// browsers act like NS4 in that they report this incorrectly.
			if ( !img.complete )
				return false;
		
			// However, they do have two very useful properties:naturalWidth and
			// naturalHeight. These give the true size of the image. If it failed
			// to load, either of these should be zero.
			if ( typeof img.naturalWidth != "undefined" && img.naturalWidth == 0 )
				return false;
		
			return true;
		},
		
		areImagesReady:function(images) {
			for ( var i=0; i<images.length; i++ ) {
				if ( !this.isImageReady(images[i]) )
					return false;
			}
			return true;
		},
		
		handleImages:function(images, handler) {
			var S = this;
			if ( this.image_interval == null ) {
				if ( this.checking_images_timeOut ) {
					this.image_timeOut = window.setTimeout(
						function(){
							window.clearInterval(S.image_interval);
							S.image_interval = null;
							handler();
						}, this.checking_images_timeOut
					);
				}
				this.image_interval = window.setInterval(
					function() {
						if ( S.areImagesReady(images) ) {
							window.clearInterval(S.image_interval);
							S.image_interval = null;
							if ( S.checking_images_timeOut ) { window.clearTimeout(S.image_timeOut); }
							handler();
						}
					}, this.checking_images_interval
				);
			}
		},
		
		extend:function() {
			// copy reference to target object
			var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options;
		
			// Handle a deep copy situation
			if ( target.constructor == Boolean ) {
				deep = target;
				target = arguments[1] || {};
				// skip the boolean and the target
				i = 2;
			}
		
			// Handle case when target is a string or something (possible in deep copy)
			if ( typeof target != "object" && typeof target != "function" )
				target = {};
		
			// extend jQuery itself if only one argument is passed
			if ( length == i ) {
				target = this;
				--i;
			}
		
			for ( ; i < length; i++ )
				// Only deal with non-null/undefined values
				if ( (options = arguments[ i ]) != null )
					// Extend the base object
					for ( var name in options ) {
						var src = target[ name ], copy = options[ name ];
		
						// Prevent never-ending loop
						if ( target === copy )
							continue;
		
						// Recurse if we're merging object values
						if ( deep && copy && typeof copy == "object" && !copy.nodeType )
							target[ name ] = jQuery.extend( deep, 
								// Never move original objects, clone them
								src || ( copy.length != null ? [ ] : { } )
							, copy );
		
						// Don't bring in undefined values
						else if ( copy !== undefined )
							target[ name ] = copy;
		
					}
		
			// Return the modified object
			return target;
		},
		
		browser:function() {
			return {
				version: (this.userAgent.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [])[1],
				safari: /webkit/.test( this.userAgent ),
				opera: /opera/.test( this.userAgent ),
				msie: /msie/.test( this.userAgent ) && !/opera/.test( this.userAgent ),
				mozilla: /mozilla/.test( this.userAgent ) && !/(compatible|webkit)/.test( this.userAgent )
			};
		},
		
		each:function(object, callback) {
			var name, i = 0, length = object.length;
			
			if ( length == undefined ) {
				for ( name in object )
					if ( callback.call( object[ name ], name, object[ name ] ) === false )
						break;
			} else {
				for ( var value = object[0];
					i < length && callback.call( value, i, value ) !== false; value = object[++i] ){}
			}
			
			return object;
		},
		
		bind:function(elem, types, handler) {
			deffect.each(types.split(/\s+/), function(index, type) {
				if (elem.addEventListener)
					elem.addEventListener(type, handler, false);
				else if (elem.attachEvent)
					elem.attachEvent("on" + type, handler);
			});
		},
		
		ready:function() {
			if ( !this.isReady ) {
				this.isReady = true;
				if ( this.readyList ) {
					this.each(this.readyList, function(){this.call(document, deffect)});
					this.readyList = null;
				}
			}
		},
		
		getElementReference:function(elementOrId) {
			if ( deffect.isString(elementOrId) )
				return document.getElementById(elementOrId);
			else
				return elementOrId;
		},
		
		isPositiveInteger:function(val){
			if (val==null) { return false; }
			if (val.length==0) { return false; }
			for (var i = 0; i < val.length; i++)
			{
				var ch = val.charAt(i);
				if (ch < "0" || ch > "9") {
					return false
				}
			}
		
			return true;
		}
		
	}
	l.deffect.$(document).ready(function(){});
	
})();
/*
 *
 */
 
var connect = {

	transaction_id: 0,
	poll: {},
	polling_interval: 50,
	timeOut: {},
	//polling_timeOut: 10000,
	isFormSubmit: false,
	formData: null,
	
	setForm:function(formId) {
		var oForm, oElement, oName, oValue, oDisabled,
			hasSubmit = false,
			data = [], item = 0,
			i,len,j,jlen,opt;
		resetFormState();
		var oForm = deffect.getElementReference(formId);
		
		// Iterate over the form elements collection to construct the
		// label-value pairs.
		for (i=0,len=oForm.elements.length; i<len; ++i){
			oElement  = oForm.elements[i];
			oDisabled = oElement.disabled;
			oName     = oElement.name;

			// Do not submit fields that are disabled or
			// do not have a name attribute value.
			if(!oDisabled && oName)
			{
				oName  = encodeURIComponent(oName)+'=';
				oValue = encodeURIComponent(oElement.value);

				switch(oElement.type)
				{
					// Safari, Opera, FF all default opt.value from .text if
					// value attribute not specified in markup
					case 'select-one':
						if (oElement.selectedIndex > -1) {
							opt = oElement.options[oElement.selectedIndex];
							data[item++] = oName + encodeURIComponent(
								(opt.attributes.value && opt.attributes.value.specified) ? opt.value : opt.text);
						}
						break;
					case 'select-multiple':
						if (oElement.selectedIndex > -1) {
							for(j=oElement.selectedIndex, jlen=oElement.options.length; j<jlen; ++j){
								opt = oElement.options[j];
								if (opt.selected) {
									data[item++] = oName + encodeURIComponent(
										(opt.attributes.value && opt.attributes.value.specified) ? opt.value : opt.text);
								}
							}
						}
						break;
					case 'radio':
					case 'checkbox':
						if(oElement.checked){
							data[item++] = oName + oValue;
						}
						break;
					case 'file':
						// stub case as XMLHttpRequest will only send the file path as a string.
					case undefined:
						// stub case for fieldset element which returns undefined.
					case 'reset':
						// stub case for input type reset button.
					case 'button':
						// stub case for input type button elements.
						break;
					case 'submit':
						if(hasSubmit === false){
							if(this._hasSubmitListener && this._submitElementValue){
								data[item++] = this._submitElementValue;
							}
							hasSubmit = true;
						}
						break;
					default:
						data[item++] = oName + oValue;
				}
			}
		}
		connect.isFormSubmit = true;
		connect.formData = data.join('&');
		
		function resetFormState() {
			connect.isFormSubmit = false;
			connect.formData = "";
		}
	},

	asyncRequest:function(method, url, handler) {
		var postData = null;
		xmlhttp = null;
		if ( window.XMLHttpRequest ) {
			// code for Firefox, Opera, IE7, etc.
			xmlhttp = new XMLHttpRequest();
		} else if ( window.ActiveXObject ) {
			// code for IE6, IE5
			xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
		}
		if ( xmlhttp != null ) {
			if( method.toUpperCase() == 'POST' )
				postData = connect.formData;
				
			//xmlhttp.onreadystatechange = state_Change;
			xmlhttp.open(method.toUpperCase(), url, true);
			xmlhttp.setRequestHeader("X-Requested-With", "XMLHttpRequest");
			xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
			this.handleReadyState(xmlhttp, handler);
			//xmlhttp.send(null);
			xmlhttp.send(postData || '');
		} else {
			alert("Your browser does not support XMLHTTP.");
		}
		
		function state_Change() {
			if ( xmlhttp.readyState == 4 ) {
				// 4 = "loaded"
				if ( xmlhttp.status == 200 ) {
					// 200 = "OK"
					if ( handler.success )
						if ( !handler.scope )
							handler.success(xmlhttp);
				} else {
					alert("Problem retrieving data:" + xmlhttp.statusText);
				}
			}
		}
	},
	
	getTransactionId:function() {
		var tId = this.transaction_id;
		this.transaction_id++;
		return tId;
	},
	
	handleReadyState:function(q, R) {
		var S = this;
		var tId = this.getTransactionId();
		if ( this.polling_timeOut ) {
			this.timeOut[tId] = window.setTimeout(
				function() {
					if ( S.poll[tId] != null ) {
						window.clearInterval(S.poll[tId]);
						delete S.poll[tId];
					}
				},
				this.polling_timeOut
			);
		}
		this.poll[tId] = window.setInterval(
			function(){
				if ( q && q.readyState === 4 ){
					window.clearInterval(S.poll[tId]);
					delete S.poll[tId];
					S.handleTransactionResponse(q, R);
				}
			},
			this.polling_interval
		);
	},
	
	handleTransactionResponse:function(w, V) {
		var R, q;
		try {
			if ( w.status !== undefined && w.status !== 0 )
				R = w.status;
			else
				R = 13030;
		} catch(m) {
			R = 13030;
		}
		if ( R >= 200 && R < 300 || R === 1223 ) {
			q = this.createResponseObject(w, (V&&V.argument)?V.argument:undefined);
			if ( V ) {
				if ( V.success ) {
					if ( !V.scope )
						V.success(q);
					else
						V.success.apply(V.scope);
				}
			}
		} else {
			alert("Problem retrieving data:" + w.statusText);
		}
		this.releaseObject(w);
		q = null;
	},
	
	createResponseObject:function(S, d) {
		var m={};
		m.responseText = S.responseText;
		m.responseXML = S.responseXML;
		if ( typeof d !== undefined )
			m.argument = d;
		return m;
	},
	
	releaseObject:function(o) { o = null; }

}

function autocompleter(input, options) {
	
	//alert("auto"+input.id);
	var KEY = {
		UP: 38,
		DOWN: 40,
		DEL: 46,
		TAB: 9,
		RETURN: 13,
		ESC: 27,
		COMMA: 188,
		PAGEUP: 33,
		PAGEDOWN: 34,
		BACKSPACE: 8
	};
	var timeout;
	var previousValue = "";
	var dataCache = getCache(options);
	var hasFocus = 0;
	var lastKeyPressCode;
	var config = {
		mouseDownOnSelect: false
	};
	var select = getSelect(options, input, selectCurrent, config);
	var cache = {};
	var expando = "deffect" + new Date, uuid = 0;
	var handle = null;
	var searchValue = "";
	
	function selectCurrent() {
		var selected = select.selected();
		if( !selected )
			return false;
		
		var v = selected.result;
		previousValue = v;
		
		if ( options.multiple ) {
			var words = trimWords($input.val());
			if ( words.length > 1 ) {
				var seperator = options.multipleSeparator.length;
				var cursorAt = $(input).selection().start;
				var wordAt, progress = 0;
				$.each(words, function(i, word) {
					progress += word.length;
					if (cursorAt <= progress) {
						wordAt = i;
						return false;
					}
					progress += seperator;
				});
				words[wordAt] = v;
				// TODO this should set the cursor to the right position, but it gets overriden somewhere
				//$.Autocompleter.Selection(input, progress + seperator, progress + seperator);
				v = words.join( options.multipleSeparator );
			}
			v += options.multipleSeparator;
		}
		
		input.value = v;
		hideResultsNow();
		//$input.trigger("result", [selected.data, selected.value]);
		return true;
	}
	
	deffect.bind(input, "keydown", function(event) {
		// a keypress means the input has focus
		// avoids issue where input had focus before the autocomplete was applied
		hasFocus = 1;
		// track last key pressed
		lastKeyPressCode = event.keyCode;
		switch(event.keyCode) {
		
			case KEY.UP:
				if ( event.preventDefault )
					event.preventDefault();
				if ( select.visible() ) {
					select.prev();
				} else {
					onChange(0, true);
				}
				break;
				
			case KEY.DOWN:
				if ( event.preventDefault )
					event.preventDefault();
				if ( select.visible() ) {
					select.next();
				} else {
					onChange(0, true);
				}
				break;
				
			case KEY.PAGEUP:
				if ( event.preventDefault )
					event.preventDefault();
				if ( select.visible() ) {
					select.pageUp();
				} else {
					onChange(0, true);
				}
				break;
				
			case KEY.PAGEDOWN:
				if ( event.preventDefault )
					event.preventDefault();
				if ( select.visible() ) {
					select.pageDown();
				} else {
					onChange(0, true);
				}
				break;
			
			// matches also semicolon
			case options.multiple && $.trim(options.multipleSeparator) == "," && KEY.COMMA:
			case KEY.TAB:
			case KEY.RETURN:
				if( selectCurrent() ) {
					// stop default to prevent a form submit, Opera needs special handling
					if ( event.preventDefault )
						event.preventDefault();
					blockSubmit = true;
					return false;
				}
				break;
				
			case KEY.ESC:
				select.hide();
				break;
				
			default:
				clearTimeout(timeout);
				timeout = setTimeout(onChange, options.delay);
				break;
		}
	});
	deffect.bind(input, "focus", function(event) {
		// track whether the field has focus, we shouldn't process any
		// results if the field no longer has focus
		hasFocus++;
	});
	deffect.bind(input, "blur", function(event) {
		hasFocus = 0;
		if ( !config.mouseDownOnSelect )
			hideResults();
	});
	deffect.bind(input, "click", function(event) {
		// show select when clicking in a focused field
		if ( hasFocus++ > 1 && !select.visible() )
			onChange(0, true);
	});
	/*
	if ( input.addEventListener )
		input.addEventListener("keydown", handle, false);
	else if ( input.attachEvent )
		input.attachEvent("on" + "keydown", handle);
	*/
	
	function onChange(crap, skipPrevCheck) {
		if( lastKeyPressCode == KEY.DEL ) {
			select.hide();
			return;
		}
		
		var currentValue = input.value;
		
		if ( !skipPrevCheck && currentValue == previousValue )
			return;
		
		previousValue = currentValue;
		
		currentValue = lastWord(currentValue);
		if ( currentValue.length >= options.minChars ) {
			addClass(input, options.loadingClass);
			if (!options.matchCase)
				currentValue = currentValue.toLowerCase();
			request(currentValue, receiveData, hideResultsNow);
		} else {
			stopLoading();
			select.hide();
		}
	}
	
	function trimWords(value) {
		if (!value)
			return [""];
		if (!options.multiple)
			return [$.trim(value)];
		return $.map(value.split(options.multipleSeparator), function(word) {
			return $.trim(value).length ? $.trim(word) : null;
		});
	}
	
	function lastWord(value) {
		if ( !options.multiple )
			return value;
		var words = trimWords(value);
		if (words.length == 1) 
			return words[0];
		var cursorAt = $(input).selection().start;
		if (cursorAt == value.length) {
			words = trimWords(value)
		} else {
			words = trimWords(value.replace(value.substring(cursorAt), ""));
		}
		return words[words.length - 1];
	}
	
	function getSelect(options, input, select, config) {
		var CLASSES = {
			ACTIVE: "ac_over"
		};
		
		var listItems,
			active = -1,
			data,
			term = "",
			needsInit = true,
			element,
			list,
			headers = [];
		
		input.offset = function() {
			var left = 0, top = 0, elem = this, results;
		
			if ( elem ) with ( deffect.browser() ) {
				var parent       = elem.parentNode,
					offsetChild  = elem,
					offsetParent = elem.offsetParent,
					doc          = elem.ownerDocument,
					safari2      = safari && parseInt(version) < 522 && !/adobeair/i.test(userAgent),
					css          = deffect.css.get;
					fixed        = css(elem, "position") == "fixed";
		
				// Use getBoundingClientRect if available
				if ( !(mozilla && elem == document.body) && elem.getBoundingClientRect ) {
					var box = elem.getBoundingClientRect();
		
					// Add the document scroll offsets
					add(box.left + Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft),
						box.top  + Math.max(doc.documentElement.scrollTop,  doc.body.scrollTop));
		
					// IE adds the HTML element's border, by default it is medium which is 2px
					// IE 6 and 7 quirks mode the border width is overwritable by the following css html { border: 0; }
					// IE 7 standards mode, the border is always 2px
					// This border/offset is typically represented by the clientLeft and clientTop properties
					// However, in IE6 and 7 quirks mode the clientLeft and clientTop properties are not updated when overwriting it via CSS
					// Therefore this method will be off by 2px in IE while in quirksmode
					add( -doc.documentElement.clientLeft, -doc.documentElement.clientTop );
		
				// Otherwise loop through the offsetParents and parentNodes
				} else {
		
					// Initial element offsets
					add( elem.offsetLeft, elem.offsetTop );
		
					// Get parent offsets
					while ( offsetParent ) {
						// Add offsetParent offsets
						add( offsetParent.offsetLeft, offsetParent.offsetTop );
		
						// Mozilla and Safari > 2 does not include the border on offset parents
						// However Mozilla adds the border for table or table cells
						if ( mozilla && !/^t(able|d|h)$/i.test(offsetParent.tagName) || safari && !safari2 )
							border( offsetParent );
		
						// Add the document scroll offsets if position is fixed on any offsetParent
						if ( !fixed && css(offsetParent, "position") == "fixed" )
							fixed = true;
		
						// Set offsetChild to previous offsetParent unless it is the body element
						offsetChild  = /^body$/i.test(offsetParent.tagName) ? offsetChild : offsetParent;
						// Get next offsetParent
						offsetParent = offsetParent.offsetParent;
					}
		
					// Get parent scroll offsets
					while ( parent && parent.tagName && !/^body|html$/i.test(parent.tagName) ) {
						// Remove parent scroll UNLESS that parent is inline or a table to work around Opera inline/table scrollLeft/Top bug
						if ( !/^inline|table.*$/i.test(css(parent, "display")) )
							// Subtract parent scroll offsets
							add( -parent.scrollLeft, -parent.scrollTop );
		
						// Mozilla does not add the border for a parent that has overflow != visible
						if ( mozilla && css(parent, "overflow") != "visible" )
							border( parent );
		
						// Get next parent
						parent = parent.parentNode;
					}
		
					// Safari <= 2 doubles body offsets with a fixed position element/offsetParent or absolutely positioned offsetChild
					// Mozilla doubles body offsets with a non-absolutely positioned offsetChild
					if ( (safari2 && (fixed || css(offsetChild, "position") == "absolute")) ||
						(mozilla && css(offsetChild, "position") != "absolute") )
							add( -doc.body.offsetLeft, -doc.body.offsetTop );
		
					// Add the document scroll offsets if position is fixed
					if ( fixed )
						add(Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft),
							Math.max(doc.documentElement.scrollTop,  doc.body.scrollTop));
				}
		
				// Return an object with top and left properties
				results = { top: top, left: left };
			}
		
			function border(elem) {
				add(deffect.css.get(elem, "borderLeftWidth", true), deffect.css.get(elem, "borderTopWidth", true));
			}
		
			function add(l, t) {
				left += parseInt(l, 10) || 0;
				top += parseInt(t, 10) || 0;
			}
		
			return results;
		}
		
		// Create results
		function init() {
			if (!needsInit)
				return;
			/*
			element = $("<div/>")
			.hide()
			.addClass(options.resultsClass)
			.css("position", "absolute")
			.appendTo(document.body);
			*/
			element = document.createElement("div");
			addClass(element, options.resultsClass);
			//css(element, "position", "absolute");
			deffect.css.set(element, "position", "absolute");
			element.is = function(selector) {
				return (this.style.visibility.indexOf(selector.substring(1)) > -1);
			}
			element.hide = function() {
				this.style.visibility = "hidden";
			}
			element.show = function() {
				this.style.visibility = "visible";
			}
			element.hide();
			document.body.appendChild(element);
		
			list = document.createElement("ul");
			list.empty = function() {
				// Remove any remaining nodes
				while ( this.firstChild )
					this.removeChild(this.firstChild);
			}
			list.find = function(selector) {
				var result = [];
				for (var i=0; i<this.childNodes.length; i++) {
					if ( this.childNodes[i].tagName == "LI" )
						result.push(this.childNodes[i]);
				}
				result.slice = function() {
					var temp = Array.prototype.slice.apply(this, arguments);
					temp.addClass = function(classNames) {
						deffect.each(temp, function(index, elem) {
							addClass(elem, classNames);
						});
						return temp;
					}
					temp.removeClass = function(classNames) {
						deffect.each(temp, function(index, elem) {
							removeClass(elem, classNames);
						});
					}
					return temp;
				}
				result.filter = function() {
					var temp = [];
					if ( arguments.length > 0 ) {
						for (var i=0; i<list.childNodes.length; i++) {
							if ( list.childNodes[i].className.indexOf(arguments[0].substring(1)) > -1 )
								temp.push(list.childNodes[i]);
						}
					}
					return temp;
				}
				return result;
			}
			deffect.bind(list, "mouseover", function(event) {
				if ( target(event).nodeName && target(event).nodeName.toUpperCase() == 'LI' ) {
					for (var i=0; i<list.childNodes.length; i++) {
						if ( list.childNodes[i] == target(event) )
							active = i;
						removeClass(list.childNodes[i], CLASSES.ACTIVE);
					}
					if ( options.includeHeader ) {
						if ( !isActiveOnHeader() )
							addClass(target(event), CLASSES.ACTIVE);
					} else {
						addClass(target(event), CLASSES.ACTIVE);
					}
				}
			});
			/*
			list.onmouseover = function(event) {
				if ( target(event).nodeName && target(event).nodeName.toUpperCase() == 'LI' ) {
					for (var i=0; i<this.childNodes.length; i++) {
						removeClass(this.childNodes[i], CLASSES.ACTIVE);
					}
					active = target(event);
					addClass(active, CLASSES.ACTIVE);
				}
			}
			*/
			deffect.bind(list, "click", function(event) {
				if ( options.includeHeader && isActiveOnHeader() )
					return false;
				
				addClass(target(event), CLASSES.ACTIVE);
				select();
				// TODO provide option to avoid setting focus again after selection? useful for cleanup-on-focus
				input.focus();
				return false;
			});
			/*
			list.onclick = function(event) {
				addClass(target(event), CLASSES.ACTIVE);
				select();
				// TODO provide option to avoid setting focus again after selection? useful for cleanup-on-focus
				input.focus();
				return false;
			}
			*/
			deffect.bind(list, "mousedown", function(event) {
				config.mouseDownOnSelect = true;
			});
			deffect.bind(list, "mouseup", function(event) {
				config.mouseDownOnSelect = false;
			});
			element.appendChild(list);
			/*
			list = $("<ul/>").appendTo(element).mouseover( function(event) {
				if(target(event).nodeName && target(event).nodeName.toUpperCase() == 'LI') {
					active = $("li", list).removeClass(CLASSES.ACTIVE).index(target(event));
					$(target(event)).addClass(CLASSES.ACTIVE);            
				}
			}).click(function(event) {
				$(target(event)).addClass(CLASSES.ACTIVE);
				select();
				// TODO provide option to avoid setting focus again after selection? useful for cleanup-on-focus
				input.focus();
				return false;
			}).mousedown(function() {
				config.mouseDownOnSelect = true;
			}).mouseup(function() {
				config.mouseDownOnSelect = false;
			});
			*/
			
			if( options.width > 0 )
				element.style.width = options.width + "px";
				
			needsInit = false;
		} 
		
		function target(event) {
			var element = event.target;
			if ( !element )
				element = event.srcElement;
			while ( element && element.tagName != "LI" )
				element = element.parentNode;
			// more fun with IE, sometimes event.target is empty, just ignore it then
			if ( !element )
				return [];
			return element;
		}
	
		function moveSelect(step) {
			listItems.slice(active, active + 1).removeClass(CLASSES.ACTIVE);
			movePosition(step);
			var activeItem = listItems.slice(active, active + 1).addClass(CLASSES.ACTIVE);
			if ( options.scroll ) {
				var offset = 0;
				deffect.each(listItems.slice(0, active), function() {
					offset += this.offsetHeight;
				});
				if ( (offset + activeItem[0].offsetHeight - list.scrollTop) > list.clientHeight ) {
					list.scrollTop = offset + activeItem[0].offsetHeight - list.clientHeight;
				} else if ( offset < list.scrollTop ) {
					list.scrollTop = offset;
				}
			}
		}
		
		function movePosition(step) {
			active += step;
			if ( options.includeHeader ) {
				while ( isActiveOnHeader() ) {
					active += step;
				}
			}
			if (active < 0) {
				active = listItems.length;
				movePosition(-1);
			} else if (active >= listItems.length) {
				active = -1;
				movePosition(1);
			}
		}
		
		function isActiveOnHeader() {
			var result = false;
			for ( var i=0; i<headers.length; i++ ) {
				if ( headers[i] == active ) {
					result = true;
					break;
				}
			}
			return result;
		}
		
		function limitNumberOfItems(available) {
			return options.max && options.max < available
				? options.max
				: available;
		}
		
		function fillList() {
			list.empty();
			var max = limitNumberOfItems(data.length);
			var firstIndex = -1;
			for (var i=0; i < max; i++) {
				if (!data[i])
					continue;
				var isHeader = false;
				if ( options.includeHeader && options.isHeader(data[i].data, i+1, max, data[i].value, term) ) {
					headers.push(i);
					isHeader = true;
				}
				else if ( firstIndex == -1 )
					firstIndex = i;
				var formatted = options.formatItem(data[i].data, i+1, max, data[i].value, term);
				if ( isHeader ) { formatted = options.formatHeader(data[i].data, i+1, max, data[i].value, term); }
				if ( formatted === false )
					continue;
				//var li = $("<li/>").html( options.highlight(formatted, term) ).addClass(i%2 == 0 ? "ac_even" : "ac_odd").appendTo(list)[0];
				//$.data(li, "ac_data", data[i]);
				var li = document.createElement("li");
				if ( isHeader ) {
					// No need to highlight header
					li.innerHTML = formatted;
					addClass(li, options.headerClass);
				} else {
					li.innerHTML = options.highlight(formatted, term);
					addClass(li, (i%2 == 0 ? "ac_even" : "ac_odd"));
				}
				cacheData(li, "ac_data", data[i]);
				list.appendChild(li);
			}
			listItems = list.find("li");
			if ( options.selectFirst ) {
				//listItems.slice(0, 1).addClass(CLASSES.ACTIVE);
				listItems.slice(firstIndex, firstIndex+1).addClass(CLASSES.ACTIVE);
				active = firstIndex;
			}
			// apply bgiframe if available
			/*
			if ( $.fn.bgiframe )
				list.bgiframe();
			*/
		}
		
		return {
			display: function(d, q) {
				init();
				data = d;
				term = q;
				fillList();
			},
			next: function() {
				moveSelect(1);
			},
			prev: function() {
				moveSelect(-1);
			},
			pageUp: function() {
				if (active != 0 && active - 8 < 0) {
					moveSelect( -active );
				} else {
					moveSelect(-8);
				}
			},
			pageDown: function() {
				if (active != listItems.size() - 1 && active + 8 > listItems.size()) {
					moveSelect( listItems.size() - 1 - active );
				} else {
					moveSelect(8);
				}
			},
			hide: function() {
				element && element.hide();
				listItems && removeClass(listItems, CLASSES.ACTIVE);
				active = -1;
			},
			visible : function() {
				return element && element.is(":visible");
			},
			current: function() {
				return this.visible() && (listItems.filter("." + CLASSES.ACTIVE)[0] || options.selectFirst && listItems[0]);
			},
			show: function() {
				var offset = input.offset();
				deffect.css.set(element, {
					width: (typeof options.width == "string" || options.width > 0 ? options.width : input.clientWidth) + "px",
					top: (offset.top + input.offsetHeight) + "px",
					left: offset.left + "px"
				});
				element.show();
				if ( options.scroll ) {
					list.scrollTop = 0;
					deffect.css.set(list, {
						maxHeight: options.scrollHeight + "px",
						overflow: 'auto'
					});
					
					if ( deffect.browser().msie && typeof document.body.style.maxHeight === "undefined" ) {
						var listHeight = 0;
						listItems.each(function() {
							listHeight += this.offsetHeight;
						});
						var scrollbarsVisible = listHeight > options.scrollHeight;
						list.css('height', scrollbarsVisible ? options.scrollHeight : listHeight );
						if (!scrollbarsVisible) {
							// IE doesn't recalculate width when scrollbar disappears
							listItems.width( list.width() - parseInt(listItems.css("padding-left")) - parseInt(listItems.css("padding-right")) );
						}
					}
					
				}
			},
			selected: function() {
				var selected = listItems && listItems.filter("." + CLASSES.ACTIVE);
				removeClass(selected[0], CLASSES.ACTIVE);
				return selected && selected.length && cacheData(selected[0], "ac_data");
			},
			emptyList: function (){
				list && list.empty();
			},
			unbind: function() {
				element && element.remove();
			}
		};
	}
	
	function getCache(options) {

		var data = {};
		var length = 0;
		
		function matchSubset(s, sub) {
			if (!options.matchCase) 
				s = s.toLowerCase();
			var i = s.indexOf(sub);
			if (options.matchContains == "word"){
				i = s.toLowerCase().search("\\b" + sub.toLowerCase());
			}
			if (i == -1) return false;
			return i == 0 || options.matchContains;
		};
		
		function add(q, value) {
			if (length > options.cacheLength){
				flush();
			}
			if (!data[q]){ 
				length++;
			}
			data[q] = value;
		}
		
		function populate(){
			if( !options.data ) return false;
			alert("populate");
			// track the matches
			var stMatchSets = {},
				nullData = 0;
	
			// no url was specified, we need to adjust the cache length to make sure it fits the local data store
			if( !options.url ) options.cacheLength = 1;
			
			// track all options for minChars = 0
			stMatchSets[""] = [];
			
			// loop through the array and create a lookup structure
			for ( var i = 0, ol = options.data.length; i < ol; i++ ) {
				var rawValue = options.data[i];
				// if rawValue is a string, make an array otherwise just reference the array
				rawValue = (typeof rawValue == "string") ? [rawValue] : rawValue;
				
				var value = options.formatMatch(rawValue, i+1, options.data.length);
				if ( value === false )
					continue;
					
				var firstChar = value.charAt(0).toLowerCase();
				// if no lookup array for this character exists, look it up now
				if( !stMatchSets[firstChar] ) 
					stMatchSets[firstChar] = [];
	
				// if the match is a string
				var row = {
					value: value,
					data: rawValue,
					result: options.formatResult && options.formatResult(rawValue) || value
				};
				
				// push the current match into the set list
				stMatchSets[firstChar].push(row);
	
				// keep track of minChars zero items
				if ( nullData++ < options.max ) {
					stMatchSets[""].push(row);
				}
			};
			
			// add the data items to the cache
			deffect.each(stMatchSets, function(i, value) {
				// increase the cache size
				options.cacheLength++;
				// add to the cache
				add(i, value);
			});
		}
		
		// populate any existing data
		setTimeout(populate, 25);
		
		function flush(){
			data = {};
			length = 0;
		}
		
		return {
			flush: flush,
			add: add,
			populate: populate,
			load: function(q) {
				if (!options.cacheLength || !length)
					return null;
				/* 
				 * if dealing w/local data and matchContains than we must make sure
				 * to loop through all the data collections looking for matches
				 */
				if( !options.url && options.matchContains ){
					// track all matches
					var csub = [];
					// loop through all the data grids for matches
					for( var k in data ){
						// don't search through the stMatchSets[""] (minChars: 0) cache
						// this prevents duplicates
						if( k.length > 0 ){
							var c = data[k];
							$.each(c, function(i, x) {
								// if we've got a match, add it to the array
								if (matchSubset(x.value, q)) {
									csub.push(x);
								}
							});
						}
					}				
					return csub;
				} else 
				// if the exact item exists, use it
				if (data[q]){
					return data[q];
				} else
				if (options.matchSubset) {
					for (var i = q.length - 1; i >= options.minChars; i--) {
						var c = data[q.substr(0, i)];
						if (c) {
							var csub = [];
							deffect.each(c, function(i, x) {
								if (matchSubset(x.value, q)) {
									csub[csub.length] = x;
								}
							});
							return csub;
						}
					}
				}
				return null;
			}
		};
	}
	
	function hideResults() {
		clearTimeout(timeout);
		timeout = setTimeout(hideResultsNow, 200);
	}
	
	function hideResultsNow() {
		var wasVisible = select.visible();
		select.hide();
		clearTimeout(timeout);
		stopLoading();
		if (options.mustMatch) {
			// call search and run callback
			$input.search(
				function (result){
					// if no value found, clear the input box
					if( !result ) {
						if (options.multiple) {
							var words = trimWords($input.val()).slice(0, -1);
							$input.val( words.join(options.multipleSeparator) + (words.length ? options.multipleSeparator : "") );
						}
						else {
							$input.val( "" );
							$input.trigger("result", null);
						}
					}
				}
			);
		}
	}

	function receiveData(q, data) {
		if ( data && data.length && hasFocus ) {
			stopLoading();
			select.display(data, q);
			autoFill(q, data[0].value);
			select.show();
		} else {
			hideResultsNow();
		}
	}
	
	// fills in the input box w/the first match (assumed to be the best match)
	// q: the term entered
	// sValue: the first matching result
	function autoFill(q, sValue){
		// autofill in the complete box w/the first match as long as the user hasn't entered in more data
		// if the last user key pressed was backspace, don't autofill
		if( options.autoFill && (lastWord($input.val()).toLowerCase() == q.toLowerCase()) && lastKeyPressCode != KEY.BACKSPACE ) {
			// fill in the value (keep the case the user has typed)
			$input.val($input.val() + sValue.substring(lastWord(previousValue).length));
			// select the portion of the value not typed by the user (so the next character will erase)
			$(input).selection(previousValue.length, previousValue.length + sValue.length);
		}
	}
	
	function request(term, success, failure) {
		if ( !options.matchCase )
			term = term.toLowerCase();
		var data = dataCache.load(term);
		// recieve the cached data
		if ( data && data.length ) {
			success(term, data);
		// if an AJAX url has been supplied, try loading the data now
		} else if ( (typeof options.url == "string") && (options.url.length > 0) ) {
			var extraParams = {
				timestamp: +new Date()
			};
			$.each(options.extraParams, function(key, param) {
				extraParams[key] = typeof param == "function" ? param() : param;
			});
			
			$.ajax({
				// try to leverage ajaxQueue plugin to abort previous requests
				mode: "abort",
				// limit abortion to this input
				port: "autocomplete" + input.name,
				dataType: options.dataType,
				url: options.url,
				data: $.extend({
					q: lastWord(term),
					limit: options.max
				}, extraParams),
				success: function(data) {
					var parsed = options.parse && options.parse(data) || parse(data);
					dataCache.add(term, parsed);
					success(term, parsed);
				}
			});
		} else if ( typeof options.trigger == 'function' ) {
			searchValue = term;
			options.trigger.call(searchValue);
		} else {
			// if we have a failure, we need to empty the list -- this prevents the the [TAB] key from selecting the last successful match
			select.emptyList();
			failure(term);
		}
	}
	
	this.callback = function(data) {
		var parsed = options.parse && options.parse(data) || parse(data);
		receiveData(searchValue, parsed);
	}
	
	function parse(data) {
		var parsed = [];
		var rows = data;
		for (var i=0; i < rows.length; i++) {
			var row = trim(rows[i]);
			if ( row ) {
				row = row.split("|");
				parsed[parsed.length] = {
					data: row,
					value: row[0],
					result: options.formatResult && options.formatResult(row, row[0]) || row[0]
				};
			}
		}
		return parsed;
	}
	
	function trim(text) {
		return (text || "").replace( /^\s+|\s+$/g, "" );
	}
	
	function stopLoading() {
		removeClass(input, options.loadingClass);
	}
	
	function removeClass(elem, classNames) {		
		if (elem && elem.nodeType == 1)
			elem.className = classNames != undefined ?
				grep(elem.className.split(/\s+/), function(className){
					return !has(classNames, className);
				}).join(" ") :
				"";
		
		function grep(elems, callback, inv) {
			var ret = [];

			// Go through the array, only saving the items
			// that pass the validator function
			for ( var i = 0, length = elems.length; i < length; i++ )
				if ( !inv != !callback( elems[ i ], i ) )
					ret.push( elems[ i ] );

			return ret;
		}
	}
	
	function addClass(elem, classNames) {
		deffect.each((classNames || "").split(/\s+/), function(i, className){
			if ( elem.nodeType == 1 && !has(elem.className, className) )
				elem.className += (elem.className ? " " : "") + className;
		});
		return elem;
	}
	
	function has(elem, className) {
		return inArray( className, (elem.className || elem).toString().split(/\s+/) ) > -1;
	}
	
	function inArray(elem, array) {
		for ( var i = 0, length = array.length; i < length; i++ )
			// Use === because on IE, window == document
			if ( array[ i ] === elem )
				return i;

		return -1;
	}
	
	function cacheData(elem, name, data) {
		elem = elem == window ?
			windowData :
			elem;

		var id = elem[expando];

		// Compute a unique ID for the element
		if ( !id )
			id = elem[expando] = ++uuid;

		// Only generate the data cache if we're
		// trying to access or manipulate it
		if ( name && !cache[id] )
			cache[id] = {};

		// Prevent overriding the named cache with undefined values
		if ( data !== undefined )
			cache[id][name] = data;

		// Return the named cache data, or the ID for the element
		return name ?
			cache[id][name] :
			id;
	}
	
}

var accordion = {

	tempConfig: {},
	tempDefaultExpanded: [],

	expandit:function($targetHeader, $targetContent, config) {
		this.transformHeader($targetHeader, config, "expand");
		this.slideDown($targetHeader, $targetContent, this.getSpeed(config.animatespeed));
	},
	
	collapseit:function($targetHeader, $targetContent, config){
		this.transformHeader($targetHeader, config, "collapse");
		$targetContent.style.display = "none";
	},
	
	slideDown:function($targetHeader, $targetContent, speed) {
		/*
		var height = $targetContent.getAttribute("height");
		if ( height == null || height == "" ) {
			$targetContent.style.height = "100%";
			$targetContent.style.display = "block";
			height = deffect.$($targetContent).height();
			$targetContent.style.display = "none";
			$targetContent.setAttribute("height", height);
		}
		*/
		
		$targetContent.style.height = "100%";
		$targetContent.style.display = "block";
		var height = deffect.$($targetContent).height();
		$targetContent.style.display = "none";

		$targetContent.style.height = 0;
		$targetContent.style.overflow = "hidden";
		if ( $targetContent.style.display != "block" )
			$targetContent.style.display = "block";
		var startTime = new Date();
		var int = setInterval(function(){slideDown(height);}, 1);
		
		function slideDown(targetPos) {
			var currentPos = parseInt($targetContent.style.height);
			if ( currentPos < targetPos ) {
				currentPos += 1;
				$targetContent.style.height = correctPosition(currentPos, targetPos, speed) + "px";
				//alert($targetContent.style.height);
			} else {
				clearInterval(int);
				$targetContent.style.height = "100%";
			}
			/*
			$targetContent.style.height = (parseInt($targetContent.style.height) + speed) + "px";
			if ( parseInt($targetContent.style.height) + speed >= targetPos )
			{
				$targetContent.style.height = targetPos + "px";
				clearInterval(int);
			}
			*/
		}
		
		function correctPosition(currentPos, targetPos, duration) {
			var expected = (currentPos * duration * 1000 / targetPos);
			var elapsed = (new Date() - startTime);
			var tweak = 0;
			
			if ( elapsed < duration * 1000 ) { // check if falling behind
				tweak = Math.round((elapsed / expected - 1) * currentPos);
			} else { // went over duration, so jump to end
				tweak = targetPos - (currentPos + 1);
			}
			if ( tweak > 0 && isFinite(tweak) ) { // adjust if needed
				if ( currentPos + tweak >= targetPos ) {// dont go past last frame
					tweak = targetPos - (currentPos + 1);
				}
				
				currentPos += tweak;      
			}
			
			return currentPos;
		}
	},
	
	getSpeed:function(animatespeed) {
		switch (animatespeed)
		{
			/*
			case "fast":
				return 70;
			case "normal":
				return 35;
			case "slow":
				return 10;
			*/
			case "fast":
				return 0.1;
			case "normal":
				return 0.4;
			case "slow":
				return 1;
		}
	},
	
	transformHeader:function($targetHeader, config, state){
		if (config.htmlsetting.location=="prefix") //if change "prefix" HTML, locate dynamically added ".accordprefix" span tag and change it
			deffect.$($targetHeader, '*accordprefix')[0].innerHTML = ((state=="expand")? config.htmlsetting.expand: config.htmlsetting.collapse);
		else if (config.htmlsetting.location=="suffix")
			deffect.$($targetHeader, '*accordsuffix')[0].innerHTML = ((state=="expand")? config.htmlsetting.expand : config.htmlsetting.collapse);
	},

	init:function(config) {

		document.write('<style type="text/css">\n')
		if ( config.contentclass.indexOf('.') > -1 )
			document.write(config.contentclass+'{display: none}\n') //generate CSS to hide contents
		else
			document.write('.'+config.contentclass+'{display: none}\n') //generate CSS to hide contents
		document.write('<\/style>')
		
		deffect.addLoadEvent(function(){
			// Reload configuration if needed
			if ( accordion.tempConfig[accordion.getConfigId(config)] != undefined )
				config = deffect.extend({}, config, accordion.tempConfig[accordion.getConfigId(config)]);
		
			var $headers = null;
			var $subcontents = null;
			var lastexpanded={} //object to hold reference to last expanded header and content (jquery objects)
			var index = 0;
			var ID = -1;
			
			if ( config["rootclass"] != null && config["rootclass"] != "" ) {
				var temp = deffect.$(config["rootclass"]);
				if ( temp.length > 0 ) {
					$headers = deffect.$(temp[0], config["headerclass"]);
					$subcontents = deffect.$(temp[0], config["contentclass"]);
				}
			} else {
				$headers = deffect.$(config["headerclass"]);
			}
			if ( $headers != null && $headers.length > 0 && $subcontents == null )
				$subcontents = locateSubContents($headers[0], '*'+config["contentclass"]);
			
			if (typeof config.togglehtml=="undefined")
				config.htmlsetting={location: "none"}
			else
				config.htmlsetting={location: config.togglehtml[0], collapse: config.togglehtml[1], expand: config.togglehtml[2]} //store HTML settings as object properties
				
			config.oninit = (typeof config.oninit=="undefined")? function(){} : config.oninit //attach custom "oninit" event handler
			
			if ( config.defaultexpanded != null && config.defaultexpanded.length > 1 )
				config["collapseprev"] = false;
			
			var hidecontents = [];
			if ( config.hidecontent != null && config.hidecontent.length > 0 ) {
				for ( var i=0; i<config.hidecontent.length; i++ ) {
					hidecontents.push(config.hidecontent[i][0]);
				}
			}
			
			for ( var i=0; i<$headers.length; i++ ) {
				var $header = $headers[i];
				var $subcontent = $subcontents[index];
				var containsSubContent = isSameLevel($header, $subcontent);
				
				deffect.attr($header, "headerindex", i);
				if ( $subcontent != null && ($headers.length == $subcontents.length || containsSubContent) ) {
					//$subcontent.style.display = "block";
					//deffect.attr($header, "headerindex", index);
					//deffect.attr($subcontent, "contentindex", index);
					deffect.attr($header, "contentindex", index);
					
					// Hide items in sub content if needed
					while ( deffect.array.inArray(i, hidecontents) > -1 ) {
						for ( var j=0; j<hidecontents.length; j++ ) {
							if ( hidecontents[j] == i ) {
								var temp = deffect.$($subcontent, config.hidecontent[j][1]);
								if ( temp.length > 0 ) {
									if ( temp[config.hidecontent[j][2]] != null ) {
										temp[config.hidecontent[j][2]].style.display = "none";
									}
								}
								deffect.array.remove(hidecontents, j);
								deffect.array.remove(config.hidecontent, j);
								break;
							}
						}
					}
						
					$header.onclick=function(e){
						if ( $subcontents[parseInt(this.getAttribute("contentindex"))].style.display == "none" ) {
							if ( config["collapseprev"]
								&& lastexpanded.$header
								&& lastexpanded.$content != $subcontents[parseInt(this.getAttribute("contentindex"))] )
								accordion.collapseit(lastexpanded.$header, lastexpanded.$content, config)
								
							accordion.expandit($headers[parseInt(this.getAttribute("headerindex"))],
								$subcontents[parseInt(this.getAttribute("contentindex"))],
								config);
								
							lastexpanded = {$header:$headers[parseInt(this.getAttribute("headerindex"))], $content:$subcontents[parseInt(this.getAttribute("contentindex"))]}
						} else {
							accordion.collapseit($headers[parseInt(this.getAttribute("headerindex"))],
								$subcontents[parseInt(this.getAttribute("contentindex"))],
								config);
						}
						
						// Cancel default click behavior
						return false;
					};
					
					index++;
				}
				
				if ( config.htmlsetting.location == "prefix" || config.htmlsetting.location == "suffix" ) //add a SPAN element to header depending on user setting and if header is a container tag
					if ( deffect.browser().msie && parseFloat(deffect.browser().version) <= 7 )
						$header.innerHTML = "<div class='accordprefix' style='float:left'></div><div style='float:left;cursor:pointer'>"
							+ $header.innerHTML
							+ "</div><div class='accordsuffix' style='float:right;vertical-align:top'></div>";
					else
						$header.innerHTML = "<div style='display:table-row'><div class='accordprefix' style='display:table-cell;vertical-align:top'></div><div style='display:table-cell'>"
							+ $header.innerHTML
							+ "</div><div class='accordsuffix' style='display:table-cell'></div></div>";
					//$header.innerHTML = "<span class='accordprefix'></span>" + $header.innerHTML + "<span class='accordsuffix'></span>";
				
				if (
					(config.defaultexpanded != null
					&& config.defaultexpanded.length > 0
					&& deffect.array.inArray(i, config.defaultexpanded) > -1
					&& containsSubContent)
					||
					((ID = getTempExpandProfileID(config["contentclass"])) > -1 && isExpandedParent($subcontent, ID))
				) {
					accordion.transformHeader($header, config, "expand");
					if ( $subcontent != null ) {
						$subcontent.style.display = "block";
						if ( config["parentclass"] != null && config["parentclass"] != "" )
							accordion.tempDefaultExpanded.push({parentClass: config["parentclass"], childClass: config["headerclass"], child: $header});
					}
					lastexpanded = {$header:$headers[i], $content:$subcontents[i]};
				} else {
					accordion.transformHeader($header, config, "collapse");
					if ( $subcontent != null )
						$subcontent.style.display = "none";
				}
			}
			
			config.oninit();
		})
		
		function locateSubContents(node, cssClassName) {
			if ( node == null )
				return null;
				
			var stopFlag = false;
			var subcontents = null;
			var result = 0;
			while ( stopFlag == false ) {
				var parentNode = node.parentNode;
				if ( parentNode == null )
					stopFlag = true;
				else
					subcontents = deffect.$(parentNode, cssClassName);
				if ( subcontents != null && result == subcontents.length )
					stopFlag = true;
				else
					node = parentNode;
				result = subcontents.length;
			}
			return subcontents;
		}
		
		function isSameLevel(header, subContent) {			
			return ( getNextElement(header) == subContent );
		}
		
		function getNextElement(obj) {
			var temp = nextNode(obj);
			while ( temp && temp.nodeType != 1 ) {
				temp = nextNode(temp);
			}
			return temp;
		}
		
		// return next node in document order
		function nextNode(node) {
			if (!node) return null;
			if (node.firstChild)
				return node.firstChild;
			else
				return nextWide(node);
		}

		// helper function for nextNode()
		function nextWide(node) {
			if (!node) return null;
			if (node.nextSibling)
				return node.nextSibling;
			else
				return nextWide(node.parentNode);
		}
		
		function getStyle(x, styleProp) {
			//var x = document.getElementById(el);
			if (x.currentStyle)
				var y = x.currentStyle[styleProp];
			else if (window.getComputedStyle)
				var y = document.defaultView.getComputedStyle(x,null).getPropertyValue(styleProp);
			return y;
		}
		
		function getTempExpandProfileID(cssClassName) {
			if ( accordion.tempDefaultExpanded.length == 0 )
				return -1;
				
			for ( var j=0; j<accordion.tempDefaultExpanded.length; j++ ) {
				if ( accordion.tempDefaultExpanded[j].parentClass == cssClassName )
					return j;
			}
			
			return -1;
		}
		
		function isExpandedParent(node, expandedProfileID) {
			var temp = deffect.$(node, accordion.tempDefaultExpanded[expandedProfileID].childClass);
			var result = false;
			if ( temp.length > 0 ) {
				for ( var j=0; j<temp.length; j++ ) {
					if ( accordion.tempDefaultExpanded.length == 0 )
						break;
						
					if ( temp[j] == accordion.tempDefaultExpanded[expandedProfileID].child ) {
						// Remove profile
						deffect.array.remove(accordion.tempDefaultExpanded, expandedProfileID);

						result = true;
					}
				}
			}
			return result;
		}
		
	},
	
	reloadConfig:function(config) {
		var id = this.getConfigId(config);
		this.tempConfig[id] = config;
	},
	
	getConfigId:function(config) {
		return config["headerclass"] + "-" + config["contentclass"];
	},
	
	showItem:function(config) {
		if ( config.showcontent != null && config.showcontent.length > 0 ) {
			var $subcontents = null;
			if ( config["rootclass"] != null && config["rootclass"] != "" ) {
				var temp = deffect.$(config["rootclass"]);
				if ( temp.length > 0 )
					$subcontents = deffect.$(temp[0], config["contentclass"]);
			} else {
				$subcontents = deffect.$(config["contentclass"]);
			}
			if ( $subcontents != null && $subcontents.length > 0 ) {
				for ( var i=0; i<config.showcontent.length; i++ ) {
					var $subcontent = $subcontents[config.showcontent[i][0]];
					if ( $subcontent != null ) {
						var temp = deffect.$($subcontent, config.showcontent[i][1]);
						if ( temp.length > 0 ) {
							if ( temp[config.showcontent[i][2]] != null ) {
								temp[config.showcontent[i][2]].style.display = "block";
								if ( $subcontent.style.height != "" ) {
									//$subcontent.style.position="absolute";
									$subcontent.style.height = "100%";
									var temp = $subcontent.style.display;
									$subcontent.style.display = "block";
									//alert(deffect.$($subcontent).height());
									$subcontent.style.height = deffect.$($subcontent).height() + "px";
									$subcontent.style.display = temp;
								}
							}
						}
					}
				}
			}
		}
	}
	
}

var categoryBrowse = {
	
	expandCategory:function(btnObj, hideItemId, collapseMenuId, collapseImgPath, expandImgPath) {
		if (btnObj.src.indexOf("icon_expand.gif") != -1) {
			btnObj.src = collapseImgPath;
			var hideItemObj = document.getElementById(hideItemId);
			hideItemObj.style.display = 'none';
			var collapseMenuObj = document.getElementById(collapseMenuId);
			collapseMenuObj.style.position = 'relative';
			collapseMenuObj.style.visibility = 'visible';
			collapseMenuObj.style.height = collapseMenuObj.offsetHeight;
		} else {
			btnObj.src = expandImgPath;
			var hideItemObj = document.getElementById(hideItemId);
			hideItemObj.style.display = 'block';
			var collapseMenuObj = document.getElementById(collapseMenuId);
			collapseMenuObj.style.position = 'absolute';
			collapseMenuObj.style.visibility = 'hidden';
		}
	}
	
}

function overlay(element, config) {
	var el = deffect.getElementReference(element);
	var userConfig = null;
	var showEnabled = true;
	var showRequest = false;
	var instance = this;
	var effect = null;
		
	this.show = function() {
		if ( deffect.isElement(el) && showEnabled ) {
			if ( userConfig != null) {
				adjustPosition();
				if ( userConfig.shift )
					shiftElement(el, userConfig.shift.left, userConfig.shift.top);
			}
			
			if ( effect != null )
				effect.animateIn();
			else
				deffect.overlay.configVisible(el, true);
				
			showRequest = false;
		} else {
			showRequest = true;
		}
	}
	
	this.hide = function() {
		if ( deffect.isElement(el) )
			if ( effect != null )
				effect.animateOut();
			else
				deffect.overlay.configVisible(el, false);
	}
	
	this.setShowEnabled = function(value) {
		showEnabled = value;
	}
	
	this.hasShowRequest = function() {
		return showRequest;
	}
		
	if ( deffect.isElement(el) ) {
		el.style.overflow = "auto";
		el.style.zIndex = 2;
		
		// Apply user configuration, if provided
		if ( config ) {
			if ( config.effect )
				if ( config.effect.effect && deffect.isFunction(config.effect.effect) ) {
					if ( config.effect.duration > 0 )
						effect = config.effect.effect(el, config.effect.duration);
				}
				
			if ( config.height && parseInt(config.height) > 0 )
				el.style.height = getLength(config.height);
			
			if ( config.width && parseInt(config.width) > 0 )
				el.style.width = getLength(config.width);
				
			if ( config.layercentered ) {
				el.style.position = "absolute";
					
				var images = el.getElementsByTagName("img");
				if ( images.length > 0 ) {
					showEnabled = false;
					deffect.handleImages(images,
						function() {
							deffect.center(el);
							instance.setShowEnabled(true);
							if ( instance.hasShowRequest() )
								instance.show();
						}
					);
				} else
					deffect.center(el);
			} else if ( config.x != null || config.y != null ) {
				el.style.position = "absolute";

				if ( config.x != null )
					el.style.left = getLength(parseInt(config.x) + deffect.getDocumentScrollLeft());
				if ( config.y != null )
					el.style.top = getLength(parseInt(config.y) + deffect.getDocumentScrollTop());
			} else if ( config.context ) {
				el.style.position = "absolute";
				
				// Check context passed conatins enough parameters first
				if ( config.context.length > 0 ) {
					userConfig = config;
					if ( config.visible )
						adjustPosition();
				}
			}
			
			if ( config.shift && config.visible )
				shiftElement(el, config.shift.left, config.shift.top);
			
			if ( config.visible )
				this.show();
		}
	}
	
	function getLength(value) {
		var pixelPatt = new RegExp("px$", "i");
		if ( pixelPatt.test(value) )
			return value;
		else
			return value + "px";
	}
	
	function getMarginValue(element, side) {
		if ( element == null )
			return 0;
		
		var property = "margin";
		if ( side != null && deffect.isString(side) )
			property += "-" + side;
		
		if ( deffect.css.get(element, property) == "auto" )
			return 0;
		else
			return parseInt(deffect.css.get(element, property));
	}
	
	function adjustPosition() {
		var contextCorner = {x: 0, y: 0};
		var context = deffect.getElementReference(userConfig.context[0]);
		var contextPos = deffect.findPos(context);
		var contextDimensions = deffect.getDimensions(context);
		var overlayDimensions = deffect.getDimensions(el);
		var overlayMarginLeft = getMarginValue(el, "left");
		var overlayMarginTop = getMarginValue(el, "top");
		
		switch (config.context[2]) {

			case deffect.overlay.TOP_LEFT:
				contextCorner.x = contextPos.left;
				contextCorner.y = contextPos.top;
				break;

			case deffect.overlay.TOP_RIGHT:
				contextCorner.x = contextPos.left + contextDimensions.width;
				contextCorner.y = contextPos.top;
				break;

			case deffect.overlay.BOTTOM_LEFT:
				contextCorner.x = contextPos.left;
				contextCorner.y = contextPos.top + contextDimensions.height;
				break;

			case deffect.overlay.BOTTOM_RIGHT:
				contextCorner.x = contextPos.left + contextDimensions.width;
				contextCorner.y = contextPos.top + contextDimensions.height;
				break;
				
			default:
				contextCorner.x = contextPos.left + contextDimensions.width;
				contextCorner.y = contextPos.top + contextDimensions.height;
				break;
				
		}
		
		switch (config.context[1]) {

			case deffect.overlay.TOP_LEFT:
				el.style.left = getLength(contextCorner.x - overlayMarginLeft);
				el.style.top = getLength(contextCorner.y - overlayMarginTop);
				break;

			case deffect.overlay.TOP_RIGHT:
				el.style.left = getLength(contextCorner.x - overlayMarginLeft - overlayDimensions.width);
				el.style.top = getLength(contextCorner.y - overlayMarginTop);
				break;

			case deffect.overlay.BOTTOM_LEFT:
				el.style.left = getLength(contextCorner.x - overlayMarginLeft);
				el.style.top = getLength(contextCorner.y - overlayMarginTop - overlayDimensions.height);
				break;

			case deffect.overlay.BOTTOM_RIGHT:
				el.style.left = getLength(contextCorner.x - overlayMarginLeft - overlayDimensions.width);
				el.style.top = getLength(contextCorner.y - overlayMarginTop - overlayDimensions.height);
				break;
				
			default:
				el.style.left = getLength(contextCorner.x - overlayMarginLeft - overlayDimensions.width);
				el.style.top = getLength(contextCorner.y - overlayMarginTop);
				break;
				
		}
	}
	
	function shiftElement(element, left, top) {
		if ( element == null )
			return;

		if ( element.style.left == "" || element.style.top == "" ) {
			var pos = deffect.findPos(element);
			element.style.left = getLength(pos.left);
			element.style.top = getLength(pos.top);
		}
			
		if ( left )
			element.style.left = getLength(parseInt(element.style.left) + parseInt(left));
		
		if ( top )
			element.style.top = getLength(parseInt(element.style.top) + parseInt(top));
	}
}

function menu(element, config) {
	var el = deffect.getElementReference(element);
	var showRequest = false;
	var hideEnabled = true;
	var isMouseOverContext = false;
	if ( config.visible == null )
		config.visible = false;
	var overlay1 = new overlay(element, config);
	var events = {show: null, hide: null, click: null};
	
	this.subscribe = function(type, handler) {
		switch (type) {
			case "show":
				events.show = handler;
				break;
			case "hide":
				events.hide = handler;
				break;
			case "click":
				events.click = handler;
				break;
		}
	}
	
	if ( config.context && config.context.length > 0 ) {
		var context = deffect.getElementReference(config.context[0]);
		context.onclick=function(e){
			showRequest = true;
		}
		el.onmouseover=function(e){
			hideEnabled = false;
		}
		el.onmouseout=function(e){
			hideEnabled = true;
		}
		deffect.$(document).ready(function() {
			if ( document.addEventListener ) {
				document.addEventListener("click", handler, false);
			} else if (document.attachEvent) {
				document.attachEvent("onclick", handler);
			}
			
			function handler() {
				if ( showRequest && !config.visible ) {
					showRequest = false;
					config.visible = true;
					overlay1.show();
					if ( events.show != null )
						events.show();
					if ( events.click != null )
						events.click();
				} else if ( hideEnabled && config.visible ) {
					showRequest = false;
					config.visible = false;
					overlay1.hide();
					if ( events.hide != null )
						events.hide();
					if ( events.click != null )
						events.click();
				}
			}
		});
	}
}

function animation(element, attr) {
	var speed = 100;
	var running = false;
	var defaultLevel = 10;
	var level = 10;
	var effect = "";
	var from = 0;
	var to = 0;
	var currVal = 0;
	var operand = 0;
	var stopRequest = false;
	
	if ( attr != null )
		init(attr);
	
	this.start = function(){
		if ( !running ) {
			if ( stopRequest )
				stopRequest = false;
				
			deffect.overlay.configVisible(element, true);
		}
		
		if ( stopRequest ) {
			stopRequest = false;
			running = false;
			return;
		}
			
		var instance = this;
		if(running==true&&level==0){running=false;return;}
		running=true;
		level--;
		currVal+=operand;
		deffect.css.set(element, effect, deffect.isPositiveInteger(currVal.toString())?currVal:currVal=parseFloat(currVal.toFixed(2)));
		//document.getElementById("test").innerHTML = document.getElementById("test").innerHTML + "," + currVal
		
		switch (effect) {
			case "opacity":
				// Handle invisible case
				if ( currVal == 0 )
					deffect.overlay.configVisible(element, false);
				
				// Handle transparency in IE			
				deffect.css.set(element, "filter", "alpha(opacity="+(currVal*100)+")");
				break;
		}
		
		setTimeout(function(){instance.start();}, speed);
	}
	
	this.stop = function() {
		stopRequest = true;
		//running = false;
	}
	
	this.setAttr = function(attr) {
		this.stop();
		init(attr);
	}
	
	function init(attr) {
		if ( attr.level )
			level = attr.level;
		else
			level = defaultLevel;
		
		for ( var attribute in attr.attributes ) {
			effect = attribute;
			from = attr.attributes[attribute]["from"];
			if ( from == null ) {
				if ( deffect.browser().msie && element.filters.alpha != null && element.filters.alpha.opacity != null )
					from = element.filters.alpha.opacity/100;
				else
					from = parseFloat(deffect.css.get(element, "opacity"));
			}
			to = attr.attributes[attribute]["to"];
			currVal = from;
			operand = (to-from)/level;
		}
		
		if ( attr.duration )
			speed = 100 * attr.duration;
		
		switch (effect) {
			case "opacity":
				deffect.css.set(element, "opacity", from);
				deffect.css.set(element, "filter", "alpha(opacity="+(from*100)+")");
				break;
		}
	}
}
