/* PACKAGE site:
jquery/jquery
jquery/*
validation
main
map
json2
png
validation
widget
*/

/*
 * jQuery 1.2.3 - New Wave Javascript
 *
 * Copyright (c) 2008 John Resig (jquery.com)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * $Date: 2008-02-06 00:21:25 -0500 (Wed, 06 Feb 2008) $
 * $Rev: 4663 $
 */
(function(){if(window.jQuery)var _jQuery=window.jQuery;var jQuery=window.jQuery=function(selector,context){return new jQuery.prototype.init(selector,context);};if(window.$)var _$=window.$;window.$=jQuery;var quickExpr=/^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/;var isSimple=/^.[^:#\[\.]*$/;jQuery.fn=jQuery.prototype={init:function(selector,context){selector=selector||document;if(selector.nodeType){this[0]=selector;this.length=1;return this;}else if(typeof selector=="string"){var match=quickExpr.exec(selector);if(match&&(match[1]||!context)){if(match[1])selector=jQuery.clean([match[1]],context);else{var elem=document.getElementById(match[3]);if(elem)if(elem.id!=match[3])return jQuery().find(selector);else{this[0]=elem;this.length=1;return this;}else
selector=[];}}else
return new jQuery(context).find(selector);}else if(jQuery.isFunction(selector))return new jQuery(document)[jQuery.fn.ready?"ready":"load"](selector);return this.setArray(selector.constructor==Array&&selector||(selector.jquery||selector.length&&selector!=window&&!selector.nodeType&&selector[0]!=undefined&&selector[0].nodeType)&&jQuery.makeArray(selector)||[selector]);},jquery:"1.2.3",size:function(){return this.length;},length:0,get:function(num){return num==undefined?jQuery.makeArray(this):this[num];},pushStack:function(elems){var ret=jQuery(elems);ret.prevObject=this;return ret;},setArray:function(elems){this.length=0;Array.prototype.push.apply(this,elems);return this;},each:function(callback,args){return jQuery.each(this,callback,args);},index:function(elem){var ret=-1;this.each(function(i){if(this==elem)ret=i;});return ret;},attr:function(name,value,type){var options=name;if(name.constructor==String)if(value==undefined)return this.length&&jQuery[type||"attr"](this[0],name)||undefined;else{options={};options[name]=value;}return this.each(function(i){for(name in options)jQuery.attr(type?this.style:this,name,jQuery.prop(this,options[name],type,i,name));});},css:function(key,value){if((key=='width'||key=='height')&&parseFloat(value)<0)value=undefined;return this.attr(key,value,"curCSS");},text:function(text){if(typeof text!="object"&&text!=null)return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(text));var ret="";jQuery.each(text||this,function(){jQuery.each(this.childNodes,function(){if(this.nodeType!=8)ret+=this.nodeType!=1?this.nodeValue:jQuery.fn.text([this]);});});return ret;},wrapAll:function(html){if(this[0])jQuery(html,this[0].ownerDocument).clone().insertBefore(this[0]).map(function(){var elem=this;while(elem.firstChild)elem=elem.firstChild;return elem;}).append(this);return this;},wrapInner:function(html){return this.each(function(){jQuery(this).contents().wrapAll(html);});},wrap:function(html){return this.each(function(){jQuery(this).wrapAll(html);});},append:function(){return this.domManip(arguments,true,false,function(elem){if(this.nodeType==1)this.appendChild(elem);});},prepend:function(){return this.domManip(arguments,true,true,function(elem){if(this.nodeType==1)this.insertBefore(elem,this.firstChild);});},before:function(){return this.domManip(arguments,false,false,function(elem){this.parentNode.insertBefore(elem,this);});},after:function(){return this.domManip(arguments,false,true,function(elem){this.parentNode.insertBefore(elem,this.nextSibling);});},end:function(){return this.prevObject||jQuery([]);},find:function(selector){var elems=jQuery.map(this,function(elem){return jQuery.find(selector,elem);});return this.pushStack(/[^+>] [^+>]/.test(selector)||selector.indexOf("..")>-1?jQuery.unique(elems):elems);},clone:function(events){var ret=this.map(function(){if(jQuery.browser.msie&&!jQuery.isXMLDoc(this)){var clone=this.cloneNode(true),container=document.createElement("div");container.appendChild(clone);return jQuery.clean([container.innerHTML])[0];}else
return this.cloneNode(true);});var clone=ret.find("*").andSelf().each(function(){if(this[expando]!=undefined)this[expando]=null;});if(events===true)this.find("*").andSelf().each(function(i){if(this.nodeType==3)return;var events=jQuery.data(this,"events");for(var type in events)for(var handler in events[type])jQuery.event.add(clone[i],type,events[type][handler],events[type][handler].data);});return ret;},filter:function(selector){return this.pushStack(jQuery.isFunction(selector)&&jQuery.grep(this,function(elem,i){return selector.call(elem,i);})||jQuery.multiFilter(selector,this));},not:function(selector){if(selector.constructor==String)if(isSimple.test(selector))return this.pushStack(jQuery.multiFilter(selector,this,true));else
selector=jQuery.multiFilter(selector,this);var isArrayLike=selector.length&&selector[selector.length-1]!==undefined&&!selector.nodeType;return this.filter(function(){return isArrayLike?jQuery.inArray(this,selector)<0:this!=selector;});},add:function(selector){return!selector?this:this.pushStack(jQuery.merge(this.get(),selector.constructor==String?jQuery(selector).get():selector.length!=undefined&&(!selector.nodeName||jQuery.nodeName(selector,"form"))?selector:[selector]));},is:function(selector){return selector?jQuery.multiFilter(selector,this).length>0:false;},hasClass:function(selector){return this.is("."+selector);},val:function(value){if(value==undefined){if(this.length){var elem=this[0];if(jQuery.nodeName(elem,"select")){var index=elem.selectedIndex,values=[],options=elem.options,one=elem.type=="select-one";if(index<0)return null;for(var i=one?index:0,max=one?index+1:options.length;i<max;i++){var option=options[i];if(option.selected){value=jQuery.browser.msie&&!option.attributes.value.specified?option.text:option.value;if(one)return value;values.push(value);}}return values;}else
return(this[0].value||"").replace(/\r/g,"");}return undefined;}return this.each(function(){if(this.nodeType!=1)return;if(value.constructor==Array&&/radio|checkbox/.test(this.type))this.checked=(jQuery.inArray(this.value,value)>=0||jQuery.inArray(this.name,value)>=0);else if(jQuery.nodeName(this,"select")){var values=value.constructor==Array?value:[value];jQuery("option",this).each(function(){this.selected=(jQuery.inArray(this.value,values)>=0||jQuery.inArray(this.text,values)>=0);});if(!values.length)this.selectedIndex=-1;}else
this.value=value;});},html:function(value){return value==undefined?(this.length?this[0].innerHTML:null):this.empty().append(value);},replaceWith:function(value){return this.after(value).remove();},eq:function(i){return this.slice(i,i+1);},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments));},map:function(callback){return this.pushStack(jQuery.map(this,function(elem,i){return callback.call(elem,i,elem);}));},andSelf:function(){return this.add(this.prevObject);},data:function(key,value){var parts=key.split(".");parts[1]=parts[1]?"."+parts[1]:"";if(value==null){var data=this.triggerHandler("getData"+parts[1]+"!",[parts[0]]);if(data==undefined&&this.length)data=jQuery.data(this[0],key);return data==null&&parts[1]?this.data(parts[0]):data;}else
return this.trigger("setData"+parts[1]+"!",[parts[0],value]).each(function(){jQuery.data(this,key,value);});},removeData:function(key){return this.each(function(){jQuery.removeData(this,key);});},domManip:function(args,table,reverse,callback){var clone=this.length>1,elems;return this.each(function(){if(!elems){elems=jQuery.clean(args,this.ownerDocument);if(reverse)elems.reverse();}var obj=this;if(table&&jQuery.nodeName(this,"table")&&jQuery.nodeName(elems[0],"tr"))obj=this.getElementsByTagName("tbody")[0]||this.appendChild(this.ownerDocument.createElement("tbody"));var scripts=jQuery([]);jQuery.each(elems,function(){var elem=clone?jQuery(this).clone(true)[0]:this;if(jQuery.nodeName(elem,"script")){scripts=scripts.add(elem);}else{if(elem.nodeType==1)scripts=scripts.add(jQuery("script",elem).remove());callback.call(obj,elem);}});scripts.each(evalScript);});}};jQuery.prototype.init.prototype=jQuery.prototype;function evalScript(i,elem){if(elem.src)jQuery.ajax({url:elem.src,async:false,dataType:"script"});else
jQuery.globalEval(elem.text||elem.textContent||elem.innerHTML||"");if(elem.parentNode)elem.parentNode.removeChild(elem);}jQuery.extend=jQuery.fn.extend=function(){var target=arguments[0]||{},i=1,length=arguments.length,deep=false,options;if(target.constructor==Boolean){deep=target;target=arguments[1]||{};i=2;}if(typeof target!="object"&&typeof target!="function")target={};if(length==1){target=this;i=0;}for(;i<length;i++)if((options=arguments[i])!=null)for(var name in options){if(target===options[name])continue;if(deep&&options[name]&&typeof options[name]=="object"&&target[name]&&!options[name].nodeType)target[name]=jQuery.extend(target[name],options[name]);else if(options[name]!=undefined)target[name]=options[name];}return target;};var expando="jQuery"+(new Date()).getTime(),uuid=0,windowData={};var exclude=/z-?index|font-?weight|opacity|zoom|line-?height/i;jQuery.extend({noConflict:function(deep){window.$=_$;if(deep)window.jQuery=_jQuery;return jQuery;},isFunction:function(fn){return!!fn&&typeof fn!="string"&&!fn.nodeName&&fn.constructor!=Array&&/function/i.test(fn+"");},isXMLDoc:function(elem){return elem.documentElement&&!elem.body||elem.tagName&&elem.ownerDocument&&!elem.ownerDocument.body;},globalEval:function(data){data=jQuery.trim(data);if(data){var head=document.getElementsByTagName("head")[0]||document.documentElement,script=document.createElement("script");script.type="text/javascript";if(jQuery.browser.msie)script.text=data;else
script.appendChild(document.createTextNode(data));head.appendChild(script);head.removeChild(script);}},nodeName:function(elem,name){return elem.nodeName&&elem.nodeName.toUpperCase()==name.toUpperCase();},cache:{},data:function(elem,name,data){elem=elem==window?windowData:elem;var id=elem[expando];if(!id)id=elem[expando]=++uuid;if(name&&!jQuery.cache[id])jQuery.cache[id]={};if(data!=undefined)jQuery.cache[id][name]=data;return name?jQuery.cache[id][name]:id;},removeData:function(elem,name){elem=elem==window?windowData:elem;var id=elem[expando];if(name){if(jQuery.cache[id]){delete jQuery.cache[id][name];name="";for(name in jQuery.cache[id])break;if(!name)jQuery.removeData(elem);}}else{try{delete elem[expando];}catch(e){if(elem.removeAttribute)elem.removeAttribute(expando);}delete jQuery.cache[id];}},each:function(object,callback,args){if(args){if(object.length==undefined){for(var name in object)if(callback.apply(object[name],args)===false)break;}else
for(var i=0,length=object.length;i<length;i++)if(callback.apply(object[i],args)===false)break;}else{if(object.length==undefined){for(var name in object)if(callback.call(object[name],name,object[name])===false)break;}else
for(var i=0,length=object.length,value=object[0];i<length&&callback.call(value,i,value)!==false;value=object[++i]){}}return object;},prop:function(elem,value,type,i,name){if(jQuery.isFunction(value))value=value.call(elem,i);return value&&value.constructor==Number&&type=="curCSS"&&!exclude.test(name)?value+"px":value;},className:{add:function(elem,classNames){jQuery.each((classNames||"").split(/\s+/),function(i,className){if(elem.nodeType==1&&!jQuery.className.has(elem.className,className))elem.className+=(elem.className?" ":"")+className;});},remove:function(elem,classNames){if(elem.nodeType==1)elem.className=classNames!=undefined?jQuery.grep(elem.className.split(/\s+/),function(className){return!jQuery.className.has(classNames,className);}).join(" "):"";},has:function(elem,className){return jQuery.inArray(className,(elem.className||elem).toString().split(/\s+/))>-1;}},swap:function(elem,options,callback){var old={};for(var name in options){old[name]=elem.style[name];elem.style[name]=options[name];}callback.call(elem);for(var name in options)elem.style[name]=old[name];},css:function(elem,name,force){if(name=="width"||name=="height"){var val,props={position:"absolute",visibility:"hidden",display:"block"},which=name=="width"?["Left","Right"]:["Top","Bottom"];function getWH(){val=name=="width"?elem.offsetWidth:elem.offsetHeight;var padding=0,border=0;jQuery.each(which,function(){padding+=parseFloat(jQuery.curCSS(elem,"padding"+this,true))||0;border+=parseFloat(jQuery.curCSS(elem,"border"+this+"Width",true))||0;});val-=Math.round(padding+border);}if(jQuery(elem).is(":visible"))getWH();else
jQuery.swap(elem,props,getWH);return Math.max(0,val);}return jQuery.curCSS(elem,name,force);},curCSS:function(elem,name,force){var ret;function color(elem){if(!jQuery.browser.safari)return false;var ret=document.defaultView.getComputedStyle(elem,null);return!ret||ret.getPropertyValue("color")=="";}if(name=="opacity"&&jQuery.browser.msie){ret=jQuery.attr(elem.style,"opacity");return ret==""?"1":ret;}if(jQuery.browser.opera&&name=="display"){var save=elem.style.outline;elem.style.outline="0 solid black";elem.style.outline=save;}if(name.match(/float/i))name=styleFloat;if(!force&&elem.style&&elem.style[name])ret=elem.style[name];else if(document.defaultView&&document.defaultView.getComputedStyle){if(name.match(/float/i))name="float";name=name.replace(/([A-Z])/g,"-$1").toLowerCase();var getComputedStyle=document.defaultView.getComputedStyle(elem,null);if(getComputedStyle&&!color(elem))ret=getComputedStyle.getPropertyValue(name);else{var swap=[],stack=[];for(var a=elem;a&&color(a);a=a.parentNode)stack.unshift(a);for(var i=0;i<stack.length;i++)if(color(stack[i])){swap[i]=stack[i].style.display;stack[i].style.display="block";}ret=name=="display"&&swap[stack.length-1]!=null?"none":(getComputedStyle&&getComputedStyle.getPropertyValue(name))||"";for(var i=0;i<swap.length;i++)if(swap[i]!=null)stack[i].style.display=swap[i];}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];if(!/^\d+(px)?$/i.test(ret)&&/^\d/.test(ret)){var style=elem.style.left,runtimeStyle=elem.runtimeStyle.left;elem.runtimeStyle.left=elem.currentStyle.left;elem.style.left=ret||0;ret=elem.style.pixelLeft+"px";elem.style.left=style;elem.runtimeStyle.left=runtimeStyle;}}return ret;},clean:function(elems,context){var ret=[];context=context||document;if(typeof context.createElement=='undefined')context=context.ownerDocument||context[0]&&context[0].ownerDocument||document;jQuery.each(elems,function(i,elem){if(!elem)return;if(elem.constructor==Number)elem=elem.toString();if(typeof elem=="string"){elem=elem.replace(/(<(\w+)[^>]*?)\/>/g,function(all,front,tag){return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?all:front+"></"+tag+">";});var tags=jQuery.trim(elem).toLowerCase(),div=context.createElement("div");var wrap=!tags.indexOf("<opt")&&[1,"<select multiple='multiple'>","</select>"]||!tags.indexOf("<leg")&&[1,"<fieldset>","</fieldset>"]||tags.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"<table>","</table>"]||!tags.indexOf("<tr")&&[2,"<table><tbody>","</tbody></table>"]||(!tags.indexOf("<td")||!tags.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||!tags.indexOf("<col")&&[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"]||jQuery.browser.msie&&[1,"div<div>","</div>"]||[0,"",""];div.innerHTML=wrap[1]+elem+wrap[2];while(wrap[0]--)div=div.lastChild;if(jQuery.browser.msie){var tbody=!tags.indexOf("<table")&&tags.indexOf("<tbody")<0?div.firstChild&&div.firstChild.childNodes:wrap[1]=="<table>"&&tags.indexOf("<tbody")<0?div.childNodes:[];for(var j=tbody.length-1;j>=0;--j)if(jQuery.nodeName(tbody[j],"tbody")&&!tbody[j].childNodes.length)tbody[j].parentNode.removeChild(tbody[j]);if(/^\s/.test(elem))div.insertBefore(context.createTextNode(elem.match(/^\s*/)[0]),div.firstChild);}elem=jQuery.makeArray(div.childNodes);}if(elem.length===0&&(!jQuery.nodeName(elem,"form")&&!jQuery.nodeName(elem,"select")))return;if(elem[0]==undefined||jQuery.nodeName(elem,"form")||elem.options)ret.push(elem);else
ret=jQuery.merge(ret,elem);});return ret;},attr:function(elem,name,value){if(!elem||elem.nodeType==3||elem.nodeType==8)return undefined;var fix=jQuery.isXMLDoc(elem)?{}:jQuery.props;if(name=="selected"&&jQuery.browser.safari)elem.parentNode.selectedIndex;if(fix[name]){if(value!=undefined)elem[fix[name]]=value;return elem[fix[name]];}else if(jQuery.browser.msie&&name=="style")return jQuery.attr(elem.style,"cssText",value);else if(value==undefined&&jQuery.browser.msie&&jQuery.nodeName(elem,"form")&&(name=="action"||name=="method"))return elem.getAttributeNode(name).nodeValue;else if(elem.tagName){if(value!=undefined){if(name=="type"&&jQuery.nodeName(elem,"input")&&elem.parentNode)throw"type property can't be changed";elem.setAttribute(name,""+value);}if(jQuery.browser.msie&&/href|src/.test(name)&&!jQuery.isXMLDoc(elem))return elem.getAttribute(name,2);return elem.getAttribute(name);}else{if(name=="opacity"&&jQuery.browser.msie){if(value!=undefined){elem.zoom=1;elem.filter=(elem.filter||"").replace(/alpha\([^)]*\)/,"")+(parseFloat(value).toString()=="NaN"?"":"alpha(opacity="+value*100+")");}return elem.filter&&elem.filter.indexOf("opacity=")>=0?(parseFloat(elem.filter.match(/opacity=([^)]*)/)[1])/100).toString():"";}name=name.replace(/-([a-z])/ig,function(all,letter){return letter.toUpperCase();});if(value!=undefined)elem[name]=value;return elem[name];}},trim:function(text){return(text||"").replace(/^\s+|\s+$/g,"");},makeArray:function(array){var ret=[];if(typeof array!="array")for(var i=0,length=array.length;i<length;i++)ret.push(array[i]);else
ret=array.slice(0);return ret;},inArray:function(elem,array){for(var i=0,length=array.length;i<length;i++)if(array[i]==elem)return i;return-1;},merge:function(first,second){if(jQuery.browser.msie){for(var i=0;second[i];i++)if(second[i].nodeType!=8)first.push(second[i]);}else
for(var i=0;second[i];i++)first.push(second[i]);return first;},unique:function(array){var ret=[],done={};try{for(var i=0,length=array.length;i<length;i++){var id=jQuery.data(array[i]);if(!done[id]){done[id]=true;ret.push(array[i]);}}}catch(e){ret=array;}return ret;},grep:function(elems,callback,inv){var ret=[];for(var i=0,length=elems.length;i<length;i++)if(!inv&&callback(elems[i],i)||inv&&!callback(elems[i],i))ret.push(elems[i]);return ret;},map:function(elems,callback){var ret=[];for(var i=0,length=elems.length;i<length;i++){var value=callback(elems[i],i);if(value!==null&&value!=undefined){if(value.constructor!=Array)value=[value];ret=ret.concat(value);}}return ret;}});var userAgent=navigator.userAgent.toLowerCase();jQuery.browser={version:(userAgent.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[])[1],safari:/webkit/.test(userAgent),opera:/opera/.test(userAgent),msie:/msie/.test(userAgent)&&!/opera/.test(userAgent),mozilla:/mozilla/.test(userAgent)&&!/(compatible|webkit)/.test(userAgent)};var styleFloat=jQuery.browser.msie?"styleFloat":"cssFloat";jQuery.extend({boxModel:!jQuery.browser.msie||document.compatMode=="CSS1Compat",props:{"for":"htmlFor","class":"className","float":styleFloat,cssFloat:styleFloat,styleFloat:styleFloat,innerHTML:"innerHTML",className:"className",value:"value",disabled:"disabled",checked:"checked",readonly:"readOnly",selected:"selected",maxlength:"maxLength",selectedIndex:"selectedIndex",defaultValue:"defaultValue",tagName:"tagName",nodeName:"nodeName"}});jQuery.each({parent:function(elem){return elem.parentNode;},parents:function(elem){return jQuery.dir(elem,"parentNode");},next:function(elem){return jQuery.nth(elem,2,"nextSibling");},prev:function(elem){return jQuery.nth(elem,2,"previousSibling");},nextAll:function(elem){return jQuery.dir(elem,"nextSibling");},prevAll:function(elem){return jQuery.dir(elem,"previousSibling");},siblings:function(elem){return jQuery.sibling(elem.parentNode.firstChild,elem);},children:function(elem){return jQuery.sibling(elem.firstChild);},contents:function(elem){return jQuery.nodeName(elem,"iframe")?elem.contentDocument||elem.contentWindow.document:jQuery.makeArray(elem.childNodes);}},function(name,fn){jQuery.fn[name]=function(selector){var ret=jQuery.map(this,fn);if(selector&&typeof selector=="string")ret=jQuery.multiFilter(selector,ret);return this.pushStack(jQuery.unique(ret));};});jQuery.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(name,original){jQuery.fn[name]=function(){var args=arguments;return this.each(function(){for(var i=0,length=args.length;i<length;i++)jQuery(args[i])[original](this);});};});jQuery.each({removeAttr:function(name){jQuery.attr(this,name,"");if(this.nodeType==1)this.removeAttribute(name);},addClass:function(classNames){jQuery.className.add(this,classNames);},removeClass:function(classNames){jQuery.className.remove(this,classNames);},toggleClass:function(classNames){jQuery.className[jQuery.className.has(this,classNames)?"remove":"add"](this,classNames);},remove:function(selector){if(!selector||jQuery.filter(selector,[this]).r.length){jQuery("*",this).add(this).each(function(){jQuery.event.remove(this);jQuery.removeData(this);});if(this.parentNode)this.parentNode.removeChild(this);}},empty:function(){jQuery(">*",this).remove();while(this.firstChild)this.removeChild(this.firstChild);}},function(name,fn){jQuery.fn[name]=function(){return this.each(fn,arguments);};});jQuery.each(["Height","Width"],function(i,name){var type=name.toLowerCase();jQuery.fn[type]=function(size){return this[0]==window?jQuery.browser.opera&&document.body["client"+name]||jQuery.browser.safari&&window["inner"+name]||document.compatMode=="CSS1Compat"&&document.documentElement["client"+name]||document.body["client"+name]:this[0]==document?Math.max(Math.max(document.body["scroll"+name],document.documentElement["scroll"+name]),Math.max(document.body["offset"+name],document.documentElement["offset"+name])):size==undefined?(this.length?jQuery.css(this[0],type):null):this.css(type,size.constructor==String?size:size+"px");};});var chars=jQuery.browser.safari&&parseInt(jQuery.browser.version)<417?"(?:[\\w*_-]|\\\\.)":"(?:[\\w\u0128-\uFFFF*_-]|\\\\.)",quickChild=new RegExp("^>\\s*("+chars+"+)"),quickID=new RegExp("^("+chars+"+)(#)("+chars+"+)"),quickClass=new RegExp("^([#.]?)("+chars+"*)");jQuery.extend({expr:{"":function(a,i,m){return m[2]=="*"||jQuery.nodeName(a,m[2]);},"#":function(a,i,m){return a.getAttribute("id")==m[2];},":":{lt:function(a,i,m){return i<m[3]-0;},gt:function(a,i,m){return i>m[3]-0;},nth:function(a,i,m){return m[3]-0==i;},eq:function(a,i,m){return m[3]-0==i;},first:function(a,i){return i==0;},last:function(a,i,m,r){return i==r.length-1;},even:function(a,i){return i%2==0;},odd:function(a,i){return i%2;},"first-child":function(a){return a.parentNode.getElementsByTagName("*")[0]==a;},"last-child":function(a){return jQuery.nth(a.parentNode.lastChild,1,"previousSibling")==a;},"only-child":function(a){return!jQuery.nth(a.parentNode.lastChild,2,"previousSibling");},parent:function(a){return a.firstChild;},empty:function(a){return!a.firstChild;},contains:function(a,i,m){return(a.textContent||a.innerText||jQuery(a).text()||"").indexOf(m[3])>=0;},visible:function(a){return"hidden"!=a.type&&jQuery.css(a,"display")!="none"&&jQuery.css(a,"visibility")!="hidden";},hidden:function(a){return"hidden"==a.type||jQuery.css(a,"display")=="none"||jQuery.css(a,"visibility")=="hidden";},enabled:function(a){return!a.disabled;},disabled:function(a){return a.disabled;},checked:function(a){return a.checked;},selected:function(a){return a.selected||jQuery.attr(a,"selected");},text:function(a){return"text"==a.type;},radio:function(a){return"radio"==a.type;},checkbox:function(a){return"checkbox"==a.type;},file:function(a){return"file"==a.type;},password:function(a){return"password"==a.type;},submit:function(a){return"submit"==a.type;},image:function(a){return"image"==a.type;},reset:function(a){return"reset"==a.type;},button:function(a){return"button"==a.type||jQuery.nodeName(a,"button");},input:function(a){return/input|select|textarea|button/i.test(a.nodeName);},has:function(a,i,m){return jQuery.find(m[3],a).length;},header:function(a){return/h\d/i.test(a.nodeName);},animated:function(a){return jQuery.grep(jQuery.timers,function(fn){return a==fn.elem;}).length;}}},parse:[/^(\[) *@?([\w-]+) *([!*$^~=]*) *('?"?)(.*?)\4 *\]/,/^(:)([\w-]+)\("?'?(.*?(\(.*?\))?[^(]*?)"?'?\)/,new RegExp("^([:.#]*)("+chars+"+)")],multiFilter:function(expr,elems,not){var old,cur=[];while(expr&&expr!=old){old=expr;var f=jQuery.filter(expr,elems,not);expr=f.t.replace(/^\s*,\s*/,"");cur=not?elems=f.r:jQuery.merge(cur,f.r);}return cur;},find:function(t,context){if(typeof t!="string")return[t];if(context&&context.nodeType!=1&&context.nodeType!=9)return[];context=context||document;var ret=[context],done=[],last,nodeName;while(t&&last!=t){var r=[];last=t;t=jQuery.trim(t);var foundToken=false;var re=quickChild;var m=re.exec(t);if(m){nodeName=m[1].toUpperCase();for(var i=0;ret[i];i++)for(var c=ret[i].firstChild;c;c=c.nextSibling)if(c.nodeType==1&&(nodeName=="*"||c.nodeName.toUpperCase()==nodeName))r.push(c);ret=r;t=t.replace(re,"");if(t.indexOf(" ")==0)continue;foundToken=true;}else{re=/^([>+~])\s*(\w*)/i;if((m=re.exec(t))!=null){r=[];var merge={};nodeName=m[2].toUpperCase();m=m[1];for(var j=0,rl=ret.length;j<rl;j++){var n=m=="~"||m=="+"?ret[j].nextSibling:ret[j].firstChild;for(;n;n=n.nextSibling)if(n.nodeType==1){var id=jQuery.data(n);if(m=="~"&&merge[id])break;if(!nodeName||n.nodeName.toUpperCase()==nodeName){if(m=="~")merge[id]=true;r.push(n);}if(m=="+")break;}}ret=r;t=jQuery.trim(t.replace(re,""));foundToken=true;}}if(t&&!foundToken){if(!t.indexOf(",")){if(context==ret[0])ret.shift();done=jQuery.merge(done,ret);r=ret=[context];t=" "+t.substr(1,t.length);}else{var re2=quickID;var m=re2.exec(t);if(m){m=[0,m[2],m[3],m[1]];}else{re2=quickClass;m=re2.exec(t);}m[2]=m[2].replace(/\\/g,"");var elem=ret[ret.length-1];if(m[1]=="#"&&elem&&elem.getElementById&&!jQuery.isXMLDoc(elem)){var oid=elem.getElementById(m[2]);if((jQuery.browser.msie||jQuery.browser.opera)&&oid&&typeof oid.id=="string"&&oid.id!=m[2])oid=jQuery('[@id="'+m[2]+'"]',elem)[0];ret=r=oid&&(!m[3]||jQuery.nodeName(oid,m[3]))?[oid]:[];}else{for(var i=0;ret[i];i++){var tag=m[1]=="#"&&m[3]?m[3]:m[1]!=""||m[0]==""?"*":m[2];if(tag=="*"&&ret[i].nodeName.toLowerCase()=="object")tag="param";r=jQuery.merge(r,ret[i].getElementsByTagName(tag));}if(m[1]==".")r=jQuery.classFilter(r,m[2]);if(m[1]=="#"){var tmp=[];for(var i=0;r[i];i++)if(r[i].getAttribute("id")==m[2]){tmp=[r[i]];break;}r=tmp;}ret=r;}t=t.replace(re2,"");}}if(t){var val=jQuery.filter(t,r);ret=r=val.r;t=jQuery.trim(val.t);}}if(t)ret=[];if(ret&&context==ret[0])ret.shift();done=jQuery.merge(done,ret);return done;},classFilter:function(r,m,not){m=" "+m+" ";var tmp=[];for(var i=0;r[i];i++){var pass=(" "+r[i].className+" ").indexOf(m)>=0;if(!not&&pass||not&&!pass)tmp.push(r[i]);}return tmp;},filter:function(t,r,not){var last;while(t&&t!=last){last=t;var p=jQuery.parse,m;for(var i=0;p[i];i++){m=p[i].exec(t);if(m){t=t.substring(m[0].length);m[2]=m[2].replace(/\\/g,"");break;}}if(!m)break;if(m[1]==":"&&m[2]=="not")r=isSimple.test(m[3])?jQuery.filter(m[3],r,true).r:jQuery(r).not(m[3]);else if(m[1]==".")r=jQuery.classFilter(r,m[2],not);else if(m[1]=="["){var tmp=[],type=m[3];for(var i=0,rl=r.length;i<rl;i++){var a=r[i],z=a[jQuery.props[m[2]]||m[2]];if(z==null||/href|src|selected/.test(m[2]))z=jQuery.attr(a,m[2])||'';if((type==""&&!!z||type=="="&&z==m[5]||type=="!="&&z!=m[5]||type=="^="&&z&&!z.indexOf(m[5])||type=="$="&&z.substr(z.length-m[5].length)==m[5]||(type=="*="||type=="~=")&&z.indexOf(m[5])>=0)^not)tmp.push(a);}r=tmp;}else if(m[1]==":"&&m[2]=="nth-child"){var merge={},tmp=[],test=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(m[3]=="even"&&"2n"||m[3]=="odd"&&"2n+1"||!/\D/.test(m[3])&&"0n+"+m[3]||m[3]),first=(test[1]+(test[2]||1))-0,last=test[3]-0;for(var i=0,rl=r.length;i<rl;i++){var node=r[i],parentNode=node.parentNode,id=jQuery.data(parentNode);if(!merge[id]){var c=1;for(var n=parentNode.firstChild;n;n=n.nextSibling)if(n.nodeType==1)n.nodeIndex=c++;merge[id]=true;}var add=false;if(first==0){if(node.nodeIndex==last)add=true;}else if((node.nodeIndex-last)%first==0&&(node.nodeIndex-last)/first>=0)add=true;if(add^not)tmp.push(node);}r=tmp;}else{var fn=jQuery.expr[m[1]];if(typeof fn=="object")fn=fn[m[2]];if(typeof fn=="string")fn=eval("false||function(a,i){return "+fn+";}");r=jQuery.grep(r,function(elem,i){return fn(elem,i,m,r);},not);}}return{r:r,t:t};},dir:function(elem,dir){var matched=[];var cur=elem[dir];while(cur&&cur!=document){if(cur.nodeType==1)matched.push(cur);cur=cur[dir];}return matched;},nth:function(cur,result,dir,elem){result=result||1;var num=0;for(;cur;cur=cur[dir])if(cur.nodeType==1&&++num==result)break;return cur;},sibling:function(n,elem){var r=[];for(;n;n=n.nextSibling){if(n.nodeType==1&&(!elem||n!=elem))r.push(n);}return r;}});jQuery.event={add:function(elem,types,handler,data){if(elem.nodeType==3||elem.nodeType==8)return;if(jQuery.browser.msie&&elem.setInterval!=undefined)elem=window;if(!handler.guid)handler.guid=this.guid++;if(data!=undefined){var fn=handler;handler=function(){return fn.apply(this,arguments);};handler.data=data;handler.guid=fn.guid;}var events=jQuery.data(elem,"events")||jQuery.data(elem,"events",{}),handle=jQuery.data(elem,"handle")||jQuery.data(elem,"handle",function(){var val;if(typeof jQuery=="undefined"||jQuery.event.triggered)return val;val=jQuery.event.handle.apply(arguments.callee.elem,arguments);return val;});handle.elem=elem;jQuery.each(types.split(/\s+/),function(index,type){var parts=type.split(".");type=parts[0];handler.type=parts[1];var handlers=events[type];if(!handlers){handlers=events[type]={};if(!jQuery.event.special[type]||jQuery.event.special[type].setup.call(elem)===false){if(elem.addEventListener)elem.addEventListener(type,handle,false);else if(elem.attachEvent)elem.attachEvent("on"+type,handle);}}handlers[handler.guid]=handler;jQuery.event.global[type]=true;});elem=null;},guid:1,global:{},remove:function(elem,types,handler){if(elem.nodeType==3||elem.nodeType==8)return;var events=jQuery.data(elem,"events"),ret,index;if(events){if(types==undefined||(typeof types=="string"&&types.charAt(0)=="."))for(var type in events)this.remove(elem,type+(types||""));else{if(types.type){handler=types.handler;types=types.type;}jQuery.each(types.split(/\s+/),function(index,type){var parts=type.split(".");type=parts[0];if(events[type]){if(handler)delete events[type][handler.guid];else
for(handler in events[type])if(!parts[1]||events[type][handler].type==parts[1])delete events[type][handler];for(ret in events[type])break;if(!ret){if(!jQuery.event.special[type]||jQuery.event.special[type].teardown.call(elem)===false){if(elem.removeEventListener)elem.removeEventListener(type,jQuery.data(elem,"handle"),false);else if(elem.detachEvent)elem.detachEvent("on"+type,jQuery.data(elem,"handle"));}ret=null;delete events[type];}}});}for(ret in events)break;if(!ret){var handle=jQuery.data(elem,"handle");if(handle)handle.elem=null;jQuery.removeData(elem,"events");jQuery.removeData(elem,"handle");}}},trigger:function(type,data,elem,donative,extra){data=jQuery.makeArray(data||[]);if(type.indexOf("!")>=0){type=type.slice(0,-1);var exclusive=true;}if(!elem){if(this.global[type])jQuery("*").add([window,document]).trigger(type,data);}else{if(elem.nodeType==3||elem.nodeType==8)return undefined;var val,ret,fn=jQuery.isFunction(elem[type]||null),event=!data[0]||!data[0].preventDefault;if(event)data.unshift(this.fix({type:type,target:elem}));data[0].type=type;if(exclusive)data[0].exclusive=true;if(jQuery.isFunction(jQuery.data(elem,"handle")))val=jQuery.data(elem,"handle").apply(elem,data);if(!fn&&elem["on"+type]&&elem["on"+type].apply(elem,data)===false)val=false;if(event)data.shift();if(extra&&jQuery.isFunction(extra)){ret=extra.apply(elem,val==null?data:data.concat(val));if(ret!==undefined)val=ret;}if(fn&&donative!==false&&val!==false&&!(jQuery.nodeName(elem,'a')&&type=="click")){this.triggered=true;try{elem[type]();}catch(e){}}this.triggered=false;}return val;},handle:function(event){var val;event=jQuery.event.fix(event||window.event||{});var parts=event.type.split(".");event.type=parts[0];var handlers=jQuery.data(this,"events")&&jQuery.data(this,"events")[event.type],args=Array.prototype.slice.call(arguments,1);args.unshift(event);for(var j in handlers){var handler=handlers[j];args[0].handler=handler;args[0].data=handler.data;if(!parts[1]&&!event.exclusive||handler.type==parts[1]){var ret=handler.apply(this,args);if(val!==false)val=ret;if(ret===false){event.preventDefault();event.stopPropagation();}}}if(jQuery.browser.msie)event.target=event.preventDefault=event.stopPropagation=event.handler=event.data=null;return val;},fix:function(event){var originalEvent=event;event=jQuery.extend({},originalEvent);event.preventDefault=function(){if(originalEvent.preventDefault)originalEvent.preventDefault();originalEvent.returnValue=false;};event.stopPropagation=function(){if(originalEvent.stopPropagation)originalEvent.stopPropagation();originalEvent.cancelBubble=true;};if(!event.target)event.target=event.srcElement||document;if(event.target.nodeType==3)event.target=originalEvent.target.parentNode;if(!event.relatedTarget&&event.fromElement)event.relatedTarget=event.fromElement==event.target?event.toElement:event.fromElement;if(event.pageX==null&&event.clientX!=null){var doc=document.documentElement,body=document.body;event.pageX=event.clientX+(doc&&doc.scrollLeft||body&&body.scrollLeft||0)-(doc.clientLeft||0);event.pageY=event.clientY+(doc&&doc.scrollTop||body&&body.scrollTop||0)-(doc.clientTop||0);}if(!event.which&&((event.charCode||event.charCode===0)?event.charCode:event.keyCode))event.which=event.charCode||event.keyCode;if(!event.metaKey&&event.ctrlKey)event.metaKey=event.ctrlKey;if(!event.which&&event.button)event.which=(event.button&1?1:(event.button&2?3:(event.button&4?2:0)));return event;},special:{ready:{setup:function(){bindReady();return;},teardown:function(){return;}},mouseenter:{setup:function(){if(jQuery.browser.msie)return false;jQuery(this).bind("mouseover",jQuery.event.special.mouseenter.handler);return true;},teardown:function(){if(jQuery.browser.msie)return false;jQuery(this).unbind("mouseover",jQuery.event.special.mouseenter.handler);return true;},handler:function(event){if(withinElement(event,this))return true;arguments[0].type="mouseenter";return jQuery.event.handle.apply(this,arguments);}},mouseleave:{setup:function(){if(jQuery.browser.msie)return false;jQuery(this).bind("mouseout",jQuery.event.special.mouseleave.handler);return true;},teardown:function(){if(jQuery.browser.msie)return false;jQuery(this).unbind("mouseout",jQuery.event.special.mouseleave.handler);return true;},handler:function(event){if(withinElement(event,this))return true;arguments[0].type="mouseleave";return jQuery.event.handle.apply(this,arguments);}}}};jQuery.fn.extend({bind:function(type,data,fn){return type=="unload"?this.one(type,data,fn):this.each(function(){jQuery.event.add(this,type,fn||data,fn&&data);});},one:function(type,data,fn){return this.each(function(){jQuery.event.add(this,type,function(event){jQuery(this).unbind(event);return(fn||data).apply(this,arguments);},fn&&data);});},unbind:function(type,fn){return this.each(function(){jQuery.event.remove(this,type,fn);});},trigger:function(type,data,fn){return this.each(function(){jQuery.event.trigger(type,data,this,true,fn);});},triggerHandler:function(type,data,fn){if(this[0])return jQuery.event.trigger(type,data,this[0],false,fn);return undefined;},toggle:function(){var args=arguments;return this.click(function(event){this.lastToggle=0==this.lastToggle?1:0;event.preventDefault();return args[this.lastToggle].apply(this,arguments)||false;});},hover:function(fnOver,fnOut){return this.bind('mouseenter',fnOver).bind('mouseleave',fnOut);},ready:function(fn){bindReady();if(jQuery.isReady)fn.call(document,jQuery);else
jQuery.readyList.push(function(){return fn.call(this,jQuery);});return this;}});jQuery.extend({isReady:false,readyList:[],ready:function(){if(!jQuery.isReady){jQuery.isReady=true;if(jQuery.readyList){jQuery.each(jQuery.readyList,function(){this.apply(document);});jQuery.readyList=null;}jQuery(document).triggerHandler("ready");}}});var readyBound=false;function bindReady(){if(readyBound)return;readyBound=true;if(document.addEventListener&&!jQuery.browser.opera)document.addEventListener("DOMContentLoaded",jQuery.ready,false);if(jQuery.browser.msie&&window==top)(function(){if(jQuery.isReady)return;try{document.documentElement.doScroll("left");}catch(error){setTimeout(arguments.callee,0);return;}jQuery.ready();})();if(jQuery.browser.opera)document.addEventListener("DOMContentLoaded",function(){if(jQuery.isReady)return;for(var i=0;i<document.styleSheets.length;i++)if(document.styleSheets[i].disabled){setTimeout(arguments.callee,0);return;}jQuery.ready();},false);if(jQuery.browser.safari){var numStyles;(function(){if(jQuery.isReady)return;if(document.readyState!="loaded"&&document.readyState!="complete"){setTimeout(arguments.callee,0);return;}if(numStyles===undefined)numStyles=jQuery("style, link[rel=stylesheet]").length;if(document.styleSheets.length!=numStyles){setTimeout(arguments.callee,0);return;}jQuery.ready();})();}jQuery.event.add(window,"load",jQuery.ready);}jQuery.each(("blur,focus,load,resize,scroll,unload,click,dblclick,"+"mousedown,mouseup,mousemove,mouseover,mouseout,change,select,"+"submit,keydown,keypress,keyup,error").split(","),function(i,name){jQuery.fn[name]=function(fn){return fn?this.bind(name,fn):this.trigger(name);};});var withinElement=function(event,elem){var parent=event.relatedTarget;while(parent&&parent!=elem)try{parent=parent.parentNode;}catch(error){parent=elem;}return parent==elem;};jQuery(window).bind("unload",function(){jQuery("*").add(document).unbind();});jQuery.fn.extend({load:function(url,params,callback){if(jQuery.isFunction(url))return this.bind("load",url);var off=url.indexOf(" ");if(off>=0){var selector=url.slice(off,url.length);url=url.slice(0,off);}callback=callback||function(){};var type="GET";if(params)if(jQuery.isFunction(params)){callback=params;params=null;}else{params=jQuery.param(params);type="POST";}var self=this;jQuery.ajax({url:url,type:type,dataType:"html",data:params,complete:function(res,status){if(status=="success"||status=="notmodified")self.html(selector?jQuery("<div/>").append(res.responseText.replace(/<script(.|\s)*?\/script>/g,"")).find(selector):res.responseText);self.each(callback,[res.responseText,status,res]);}});return this;},serialize:function(){return jQuery.param(this.serializeArray());},serializeArray:function(){return this.map(function(){return jQuery.nodeName(this,"form")?jQuery.makeArray(this.elements):this;}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password/i.test(this.type));}).map(function(i,elem){var val=jQuery(this).val();return val==null?null:val.constructor==Array?jQuery.map(val,function(val,i){return{name:elem.name,value:val};}):{name:elem.name,value:val};}).get();}});jQuery.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(i,o){jQuery.fn[o]=function(f){return this.bind(o,f);};});var jsc=(new Date).getTime();jQuery.extend({get:function(url,data,callback,type){if(jQuery.isFunction(data)){callback=data;data=null;}return jQuery.ajax({type:"GET",url:url,data:data,success:callback,dataType:type});},getScript:function(url,callback){return jQuery.get(url,null,callback,"script");},getJSON:function(url,data,callback){return jQuery.get(url,data,callback,"json");},post:function(url,data,callback,type){if(jQuery.isFunction(data)){callback=data;data={};}return jQuery.ajax({type:"POST",url:url,data:data,success:callback,dataType:type});},ajaxSetup:function(settings){jQuery.extend(jQuery.ajaxSettings,settings);},ajaxSettings:{global:true,type:"GET",timeout:0,contentType:"application/x-www-form-urlencoded",processData:true,async:true,data:null,username:null,password:null,accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(s){var jsonp,jsre=/=\?(&|$)/g,status,data;s=jQuery.extend(true,s,jQuery.extend(true,{},jQuery.ajaxSettings,s));if(s.data&&s.processData&&typeof s.data!="string")s.data=jQuery.param(s.data);if(s.dataType=="jsonp"){if(s.type.toLowerCase()=="get"){if(!s.url.match(jsre))s.url+=(s.url.match(/\?/)?"&":"?")+(s.jsonp||"callback")+"=?";}else if(!s.data||!s.data.match(jsre))s.data=(s.data?s.data+"&":"")+(s.jsonp||"callback")+"=?";s.dataType="json";}if(s.dataType=="json"&&(s.data&&s.data.match(jsre)||s.url.match(jsre))){jsonp="jsonp"+jsc++;if(s.data)s.data=(s.data+"").replace(jsre,"="+jsonp+"$1");s.url=s.url.replace(jsre,"="+jsonp+"$1");s.dataType="script";window[jsonp]=function(tmp){data=tmp;success();complete();window[jsonp]=undefined;try{delete window[jsonp];}catch(e){}if(head)head.removeChild(script);};}if(s.dataType=="script"&&s.cache==null)s.cache=false;if(s.cache===false&&s.type.toLowerCase()=="get"){var ts=(new Date()).getTime();var ret=s.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+ts+"$2");s.url=ret+((ret==s.url)?(s.url.match(/\?/)?"&":"?")+"_="+ts:"");}if(s.data&&s.type.toLowerCase()=="get"){s.url+=(s.url.match(/\?/)?"&":"?")+s.data;s.data=null;}if(s.global&&!jQuery.active++)jQuery.event.trigger("ajaxStart");if((!s.url.indexOf("http")||!s.url.indexOf("//"))&&s.dataType=="script"&&s.type.toLowerCase()=="get"){var head=document.getElementsByTagName("head")[0];var script=document.createElement("script");script.src=s.url;if(s.scriptCharset)script.charset=s.scriptCharset;if(!jsonp){var done=false;script.onload=script.onreadystatechange=function(){if(!done&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){done=true;success();complete();head.removeChild(script);}};}head.appendChild(script);return undefined;}var requestDone=false;var xml=window.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest();xml.open(s.type,s.url,s.async,s.username,s.password);try{if(s.data)xml.setRequestHeader("Content-Type",s.contentType);if(s.ifModified)xml.setRequestHeader("If-Modified-Since",jQuery.lastModified[s.url]||"Thu, 01 Jan 1970 00:00:00 GMT");xml.setRequestHeader("X-Requested-With","XMLHttpRequest");xml.setRequestHeader("Accept",s.dataType&&s.accepts[s.dataType]?s.accepts[s.dataType]+", */*":s.accepts._default);}catch(e){}if(s.beforeSend)s.beforeSend(xml);if(s.global)jQuery.event.trigger("ajaxSend",[xml,s]);var onreadystatechange=function(isTimeout){if(!requestDone&&xml&&(xml.readyState==4||isTimeout=="timeout")){requestDone=true;if(ival){clearInterval(ival);ival=null;}status=isTimeout=="timeout"&&"timeout"||!jQuery.httpSuccess(xml)&&"error"||s.ifModified&&jQuery.httpNotModified(xml,s.url)&&"notmodified"||"success";if(status=="success"){try{data=jQuery.httpData(xml,s.dataType);}catch(e){status="parsererror";}}if(status=="success"){var modRes;try{modRes=xml.getResponseHeader("Last-Modified");}catch(e){}if(s.ifModified&&modRes)jQuery.lastModified[s.url]=modRes;if(!jsonp)success();}else
jQuery.handleError(s,xml,status);complete();if(s.async)xml=null;}};if(s.async){var ival=setInterval(onreadystatechange,13);if(s.timeout>0)setTimeout(function(){if(xml){xml.abort();if(!requestDone)onreadystatechange("timeout");}},s.timeout);}try{xml.send(s.data);}catch(e){jQuery.handleError(s,xml,null,e);}if(!s.async)onreadystatechange();function success(){if(s.success)s.success(data,status);if(s.global)jQuery.event.trigger("ajaxSuccess",[xml,s]);}function complete(){if(s.complete)s.complete(xml,status);if(s.global)jQuery.event.trigger("ajaxComplete",[xml,s]);if(s.global&&!--jQuery.active)jQuery.event.trigger("ajaxStop");}return xml;},handleError:function(s,xml,status,e){if(s.error)s.error(xml,status,e);if(s.global)jQuery.event.trigger("ajaxError",[xml,s,e]);},active:0,httpSuccess:function(r){try{return!r.status&&location.protocol=="file:"||(r.status>=200&&r.status<300)||r.status==304||r.status==1223||jQuery.browser.safari&&r.status==undefined;}catch(e){}return false;},httpNotModified:function(xml,url){try{var xmlRes=xml.getResponseHeader("Last-Modified");return xml.status==304||xmlRes==jQuery.lastModified[url]||jQuery.browser.safari&&xml.status==undefined;}catch(e){}return false;},httpData:function(r,type){var ct=r.getResponseHeader("content-type");var xml=type=="xml"||!type&&ct&&ct.indexOf("xml")>=0;var data=xml?r.responseXML:r.responseText;if(xml&&data.documentElement.tagName=="parsererror")throw"parsererror";if(type=="script")jQuery.globalEval(data);if(type=="json")data=eval("("+data+")");return data;},param:function(a){var s=[];if(a.constructor==Array||a.jquery)jQuery.each(a,function(){s.push(encodeURIComponent(this.name)+"="+encodeURIComponent(this.value));});else
for(var j in a)if(a[j]&&a[j].constructor==Array)jQuery.each(a[j],function(){s.push(encodeURIComponent(j)+"="+encodeURIComponent(this));});else
s.push(encodeURIComponent(j)+"="+encodeURIComponent(a[j]));return s.join("&").replace(/%20/g,"+");}});jQuery.fn.extend({show:function(speed,callback){return speed?this.animate({height:"show",width:"show",opacity:"show"},speed,callback):this.filter(":hidden").each(function(){this.style.display=this.oldblock||"";if(jQuery.css(this,"display")=="none"){var elem=jQuery("<"+this.tagName+" />").appendTo("body");this.style.display=elem.css("display");if(this.style.display=="none")this.style.display="block";elem.remove();}}).end();},hide:function(speed,callback){return speed?this.animate({height:"hide",width:"hide",opacity:"hide"},speed,callback):this.filter(":visible").each(function(){this.oldblock=this.oldblock||jQuery.css(this,"display");this.style.display="none";}).end();},_toggle:jQuery.fn.toggle,toggle:function(fn,fn2){return jQuery.isFunction(fn)&&jQuery.isFunction(fn2)?this._toggle(fn,fn2):fn?this.animate({height:"toggle",width:"toggle",opacity:"toggle"},fn,fn2):this.each(function(){jQuery(this)[jQuery(this).is(":hidden")?"show":"hide"]();});},slideDown:function(speed,callback){return this.animate({height:"show"},speed,callback);},slideUp:function(speed,callback){return this.animate({height:"hide"},speed,callback);},slideToggle:function(speed,callback){return this.animate({height:"toggle"},speed,callback);},fadeIn:function(speed,callback){return this.animate({opacity:"show"},speed,callback);},fadeOut:function(speed,callback){return this.animate({opacity:"hide"},speed,callback);},fadeTo:function(speed,to,callback){return this.animate({opacity:to},speed,callback);},animate:function(prop,speed,easing,callback){var optall=jQuery.speed(speed,easing,callback);return this[optall.queue===false?"each":"queue"](function(){if(this.nodeType!=1)return false;var opt=jQuery.extend({},optall);var hidden=jQuery(this).is(":hidden"),self=this;for(var p in prop){if(prop[p]=="hide"&&hidden||prop[p]=="show"&&!hidden)return jQuery.isFunction(opt.complete)&&opt.complete.apply(this);if(p=="height"||p=="width"){opt.display=jQuery.css(this,"display");opt.overflow=this.style.overflow;}}if(opt.overflow!=null)this.style.overflow="hidden";opt.curAnim=jQuery.extend({},prop);jQuery.each(prop,function(name,val){var e=new jQuery.fx(self,opt,name);if(/toggle|show|hide/.test(val))e[val=="toggle"?hidden?"show":"hide":val](prop);else{var parts=val.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),start=e.cur(true)||0;if(parts){var end=parseFloat(parts[2]),unit=parts[3]||"px";if(unit!="px"){self.style[name]=(end||1)+unit;start=((end||1)/e.cur(true))*start;self.style[name]=start+unit;}if(parts[1])end=((parts[1]=="-="?-1:1)*end)+start;e.custom(start,end,unit);}else
e.custom(start,val,"");}});return true;});},queue:function(type,fn){if(jQuery.isFunction(type)||(type&&type.constructor==Array)){fn=type;type="fx";}if(!type||(typeof type=="string"&&!fn))return queue(this[0],type);return this.each(function(){if(fn.constructor==Array)queue(this,type,fn);else{queue(this,type).push(fn);if(queue(this,type).length==1)fn.apply(this);}});},stop:function(clearQueue,gotoEnd){var timers=jQuery.timers;if(clearQueue)this.queue([]);this.each(function(){for(var i=timers.length-1;i>=0;i--)if(timers[i].elem==this){if(gotoEnd)timers[i](true);timers.splice(i,1);}});if(!gotoEnd)this.dequeue();return this;}});var queue=function(elem,type,array){if(!elem)return undefined;type=type||"fx";var q=jQuery.data(elem,type+"queue");if(!q||array)q=jQuery.data(elem,type+"queue",array?jQuery.makeArray(array):[]);return q;};jQuery.fn.dequeue=function(type){type=type||"fx";return this.each(function(){var q=queue(this,type);q.shift();if(q.length)q[0].apply(this);});};jQuery.extend({speed:function(speed,easing,fn){var opt=speed&&speed.constructor==Object?speed:{complete:fn||!fn&&easing||jQuery.isFunction(speed)&&speed,duration:speed,easing:fn&&easing||easing&&easing.constructor!=Function&&easing};opt.duration=(opt.duration&&opt.duration.constructor==Number?opt.duration:{slow:600,fast:200}[opt.duration])||400;opt.old=opt.complete;opt.complete=function(){if(opt.queue!==false)jQuery(this).dequeue();if(jQuery.isFunction(opt.old))opt.old.apply(this);};return opt;},easing:{linear:function(p,n,firstNum,diff){return firstNum+diff*p;},swing:function(p,n,firstNum,diff){return((-Math.cos(p*Math.PI)/2)+0.5)*diff+firstNum;}},timers:[],timerId:null,fx:function(elem,options,prop){this.options=options;this.elem=elem;this.prop=prop;if(!options.orig)options.orig={};}});jQuery.fx.prototype={update:function(){if(this.options.step)this.options.step.apply(this.elem,[this.now,this]);(jQuery.fx.step[this.prop]||jQuery.fx.step._default)(this);if(this.prop=="height"||this.prop=="width")this.elem.style.display="block";},cur:function(force){if(this.elem[this.prop]!=null&&this.elem.style[this.prop]==null)return this.elem[this.prop];var r=parseFloat(jQuery.css(this.elem,this.prop,force));return r&&r>-10000?r:parseFloat(jQuery.curCSS(this.elem,this.prop))||0;},custom:function(from,to,unit){this.startTime=(new Date()).getTime();this.start=from;this.end=to;this.unit=unit||this.unit||"px";this.now=this.start;this.pos=this.state=0;this.update();var self=this;function t(gotoEnd){return self.step(gotoEnd);}t.elem=this.elem;jQuery.timers.push(t);if(jQuery.timerId==null){jQuery.timerId=setInterval(function(){var timers=jQuery.timers;for(var i=0;i<timers.length;i++)if(!timers[i]())timers.splice(i--,1);if(!timers.length){clearInterval(jQuery.timerId);jQuery.timerId=null;}},13);}},show:function(){this.options.orig[this.prop]=jQuery.attr(this.elem.style,this.prop);this.options.show=true;this.custom(0,this.cur());if(this.prop=="width"||this.prop=="height")this.elem.style[this.prop]="1px";jQuery(this.elem).show();},hide:function(){this.options.orig[this.prop]=jQuery.attr(this.elem.style,this.prop);this.options.hide=true;this.custom(this.cur(),0);},step:function(gotoEnd){var t=(new Date()).getTime();if(gotoEnd||t>this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var done=true;for(var i in this.options.curAnim)if(this.options.curAnim[i]!==true)done=false;if(done){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(jQuery.css(this.elem,"display")=="none")this.elem.style.display="block";}if(this.options.hide)this.elem.style.display="none";if(this.options.hide||this.options.show)for(var p in this.options.curAnim)jQuery.attr(this.elem.style,p,this.options.orig[p]);}if(done&&jQuery.isFunction(this.options.complete))this.options.complete.apply(this.elem);return false;}else{var n=t-this.startTime;this.state=n/this.options.duration;this.pos=jQuery.easing[this.options.easing||(jQuery.easing.swing?"swing":"linear")](this.state,n,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update();}return true;}};jQuery.fx.step={scrollLeft:function(fx){fx.elem.scrollLeft=fx.now;},scrollTop:function(fx){fx.elem.scrollTop=fx.now;},opacity:function(fx){jQuery.attr(fx.elem.style,"opacity",fx.now);},_default:function(fx){fx.elem.style[fx.prop]=fx.now+fx.unit;}};jQuery.fn.offset=function(){var left=0,top=0,elem=this[0],results;if(elem)with(jQuery.browser){var parent=elem.parentNode,offsetChild=elem,offsetParent=elem.offsetParent,doc=elem.ownerDocument,safari2=safari&&parseInt(version)<522&&!/adobeair/i.test(userAgent),fixed=jQuery.css(elem,"position")=="fixed";if(elem.getBoundingClientRect){var box=elem.getBoundingClientRect();add(box.left+Math.max(doc.documentElement.scrollLeft,doc.body.scrollLeft),box.top+Math.max(doc.documentElement.scrollTop,doc.body.scrollTop));add(-doc.documentElement.clientLeft,-doc.documentElement.clientTop);}else{add(elem.offsetLeft,elem.offsetTop);while(offsetParent){add(offsetParent.offsetLeft,offsetParent.offsetTop);if(mozilla&&!/^t(able|d|h)$/i.test(offsetParent.tagName)||safari&&!safari2)border(offsetParent);if(!fixed&&jQuery.css(offsetParent,"position")=="fixed")fixed=true;offsetChild=/^body$/i.test(offsetParent.tagName)?offsetChild:offsetParent;offsetParent=offsetParent.offsetParent;}while(parent&&parent.tagName&&!/^body|html$/i.test(parent.tagName)){if(!/^inline|table.*$/i.test(jQuery.css(parent,"display")))add(-parent.scrollLeft,-parent.scrollTop);if(mozilla&&jQuery.css(parent,"overflow")!="visible")border(parent);parent=parent.parentNode;}if((safari2&&(fixed||jQuery.css(offsetChild,"position")=="absolute"))||(mozilla&&jQuery.css(offsetChild,"position")!="absolute"))add(-doc.body.offsetLeft,-doc.body.offsetTop);if(fixed)add(Math.max(doc.documentElement.scrollLeft,doc.body.scrollLeft),Math.max(doc.documentElement.scrollTop,doc.body.scrollTop));}results={top:top,left:left};}function border(elem){add(jQuery.curCSS(elem,"borderLeftWidth",true),jQuery.curCSS(elem,"borderTopWidth",true));}function add(l,t){left+=parseInt(l)||0;top+=parseInt(t)||0;}return results;};})();

/**
 * Extending jQuery with autocomplete
 * Version: 1.4.2
 * Author: Yanik Gleyzer (clonyara)
 */
(function($) {

// some key codes
 var RETURN = 13;
 var TAB = 9;
 var ESC = 27;
 var ARRLEFT = 37;
 var ARRUP = 38;
 var ARRRIGHT = 39;
 var ARRDOWN = 40;
 var BACKSPACE = 8;
 var DELETE = 46;
 
function debug(s){
  $('#info').append(htmlspecialchars(s)+'<br>');
}
// getting caret position obj: {start,end}
function getCaretPosition(obj){
  var start = -1;
  var end = -1;
  if(typeof obj.selectionStart != "undefined"){
    start = obj.selectionStart;
    end = obj.selectionEnd;
  }
  else if(document.selection&&document.selection.createRange){
    var M=document.selection.createRange();
    var Lp;
    try{
      Lp = M.duplicate();
      Lp.moveToElementText(obj);
    }catch(e){
      Lp=obj.createTextRange();
    }
    Lp.setEndPoint("EndToStart",M);
    start=Lp.text.length;
    if(start>obj.value.length)
      start = -1;
    
    Lp.setEndPoint("EndToStart",M);
    end=Lp.text.length;
    if(end>obj.value.length)
      end = -1;
  }
  return {'start':start,'end':end};
}
// set caret to
function setCaret(obj,l){
  obj.focus();
  if (obj.setSelectionRange){
    obj.setSelectionRange(l,l);
  }
  else if(obj.createTextRange){
    m = obj.createTextRange();      
    m.moveStart('character',l);
    m.collapse();
    m.select();
  }
}
// prepare array with velued objects
// required properties are id and value
// rest of properties remaines
function prepareArray(jsondata){
  var new_arr = [];
  for(var i=0;i<jsondata.length;i++){
    if(jsondata[i].id != undefined && jsondata[i].value != undefined){
      jsondata[i].id = jsondata[i].id+"";
      jsondata[i].value = jsondata[i].value+"";
      if(jsondata[i].info != undefined)
        jsondata[i].info = jsondata[i].info+"";
      new_arr.push(jsondata[i]);
    }
  }
  return new_arr;
}
// php analogs
function escapearg(s){
  if(s == undefined || !s) return '';
  return s.replace('\\','\\\\').
           replace('*','\\*').
           replace('.','\\.').
           replace('/','\\/');
}
function htmlspecialchars(s){
  if(s == undefined || !s) return '';
  return s.replace('&','&amp;').
           replace('<','&lt;').
           replace('>','&gt;');
}
function ltrim(s){
  if(s == undefined || !s) return '';
  return s.replace(/^\s+/g,'');
}

// extending jQuery
$.fn.autocomplete = function(options){ return this.each(function(){
  // take me
  var me = $(this);
  var me_this = $(this).get(0);

  // test for supported text elements
  if(!me.is('input:text,input:password,textarea'))
  return;

  // get or ajax_get required!
  if(!options && (!$.isFunction(options.get) || !options.ajax_get)){
  return;
  }
  // check plugin enabled
  if(me.attr('jqac') == 'on') return;

  // plugin on!
  me.attr('jqac','on');
  me.attr('suggest_menu','');
  me.attr('clicked_down','false');
  // no browser's autocomplete!
  me.attr('autocomplete','off');

  // default options
  options = $.extend({ 
                      delay     : 500 ,
                      timeout   : 5000 ,
                      minchars  : 3 ,
                      multi     : false ,
                      cache     : true , 
                      height    : 150 ,
                      autowidth : false ,
                      noresults : 'No results'
                      },
                      options);

   me.blur(function(ev){
        if (me.attr('clicked_down') == 'false') {
		  clearSuggestions();
		}
		return false;
   }); 
  // bind key events
  // handle special keys here
  me.keydown(function(ev){
     switch(ev.which){
      // return choose highlighted item or default propogate
      case TAB:
            if(!suggestions_menu) return true;
            else {
                if (current_highlight == 0) {
                    changeHighlight(ARRDOWN);
                }
                else {
                    setHighlightedValue();
                }
            }
            return false;
      case RETURN:
        if(!suggestions_menu) return true;
        else setHighlightedValue();
        return false;
      // escape clears menu
      case ESC:
        clearSuggestions();
        return false;
    }
    return true;
  });

  // handle normal characters here
  me.keyup(function(ev) {
  		var val = getUserInput();
		switch(ev.which) {
			case RETURN: case TAB: case ESC:
			  return false;
			// up changes highlight
			case ARRUP:
			  changeHighlight(ev.keyCode);
			  return false;
			// down changes highlight or open new menu
			case ARRDOWN:
			  if(!suggestions_menu) getSuggestions(val);
			  else changeHighlight(ev.keyCode);
			  return false;
			default:
				if (prev_val !== val || me.attr('wrong') == 'on'){
			    	getSuggestions(val);
					prev_val = val;			    	
			   	}
		}
      return true;
  });

  // init variables
  var user_input = "";
  var prev_val = "";
  var input_chars_size  = 0;
  var suggestions = [];
  var current_highlight = 0;
  var suggestions_menu = false;
  var suggestions_list = false;
  var loading_indicator = false;
  var clearSuggestionsTimer = false;
  var clearBlurSuggestionsTimer = false;
  var getSuggestionsTimer = false;
  var showLoadingTimer = false;
  var zIndex = me.css('z-index');

  // get user input
  function getUserInput(){
    var val = me.val();
    if(options.multi){
      var pos = getCaretPosition(me_this);
      var start = pos.start;
      for(;start>0 && val.charAt(start-1) != ',';start--){}
      var end = pos.start;
      for(;end<val.length && val.charAt(end) != ',';end++){}
      var val = val.substr(start,end-start);
    }
    return user_input = ltrim(val);
  }
  // set suggestion
  function setSuggestion(val){
    user_input = val;
    prev_val = val;
    if(options.multi){
      var orig = me.val();
      var pos = getCaretPosition(me_this);
      var start = pos.start;
      for(;start>0 && orig.charAt(start-1) != ',';start--){}
      var end = pos.start;
      for(;end<orig.length && orig.charAt(end) != ',';end++){}
      var new_val = orig.substr(0,start) + (start>0?' ':'') + val + orig.substr(end);
      me.val(new_val);
      setCaret(me_this,start + val.length + (start>0?1:0));
    }
    else{
      me_this.focus();
      me.val(val);
    }
  }
  
  // get suggestions
  function getSuggestions(val){
  	clearTimeout(getSuggestionsTimer);
  	hide_loading();
  	
    // input length is less than the min required to trigger a request
    // reset input string
    // do nothing
    if (val.length < options.minchars){
      clearSuggestions();
      suggestions = [];
      return false;
    }
    if (val.indexOf(prev_val) !== 0) {
    	clearSuggestions();
    	suggestions = [];
    }
    
    // if caching enabled, and user is typing (ie. length of input is increasing)
    // filter results out of suggestions from last request
    if (options.cache && val.length >= input_chars_size && suggestions.length){
      var arr = [];
      for (var i=0;i<suggestions.length;i++){
        var re = new RegExp("("+escapearg(val)+")",'ig');
        if(re.exec(suggestions[i].value))
          arr.push( suggestions[i] );
      }
      user_input = val;
      input_chars_size = val.length;
      suggestions = arr;
      createList(suggestions);
      return false;
    }
    else{// do new request
      suggestions = [];
      user_input = val;
      input_chars_size = val.length;
      show_loading();
      getSuggestionsTimer = setTimeout( 
        function(){ 
          suggestions = [];
          // call pre callback, if exists
          if($.isFunction(options.pre_callback))
            options.pre_callback();
          // call get
          if($.isFunction(options.get)){
            suggestions = prepareArray(options.get(val));
            createList(suggestions);
          }
          // call AJAX get
          else if($.isFunction(options.ajax_get)){
            clearSuggestions();
            options.ajax_get(val,ajax_continuation);
          }
        },
        options.delay );
    }
    return false;
  };
  // AJAX continuation
  function ajax_continuation(jsondata){
    hide_loading();
    suggestions = prepareArray(jsondata);
    createList(suggestions);
  }
  // shows loading indicator
  function show_loading(){
    if(!loading_indicator){
      loading_indicator = $('<div class="jqac-menu"><div class="jqac-loading">Loading...</div></div>').get(0);
      $(loading_indicator).css('position','absolute');
      var pos = me.offset();
      $(loading_indicator).css('left', pos.left + "px");
      $(loading_indicator).css('top', ( pos.top + me.height() + 2 ) + "px");
      if(!options.autowidth)
        $(loading_indicator).width(me.width());
      $('body').append(loading_indicator);
    }
    $(loading_indicator).show();
    setTimeout(hide_loading,10000);
  }
  // hides loading indicator 
  function hide_loading(){
    if(loading_indicator)
      $(loading_indicator).hide();
    clearTimeout(showLoadingTimer);
  }
  // create suggestions list
  function createList(arr){
    if(suggestions_menu)
      $(suggestions_menu).remove();
    hide_loading();
    killTimeout();
    
    // create holding div
    me.attr('suggest_menu','on');
    
    suggestions_menu = $('<div id="'+me.attr('id')+'-suggest-menu" class="jqac-menu"></div>').get(0);
    $(suggestions_menu).mousedown(function(){
        me.attr('clicked_down', 'true');
    });
    $(suggestions_menu).mouseup(function(){
        me.attr('clicked_down', 'false');
    });
    
    // ovveride some necessary CSS properties 
    $(suggestions_menu).css({'position':'absolute',
                             'z-index':zIndex,
                             'max-height':options.height+'px',
                             'overflow-y':'auto',
                             'overflow-x':'hidden'});
                             
    // create and populate ul
    suggestions_list = $('<ul></ul>').get(0);
    // set some CSS's
    $(suggestions_list).
      css('list-style','none').
      css('margin','0px').
      css('padding','2px').
      css('overflow','hidden');
      
    // regexp for replace 
    var re = new RegExp("((^|\\s)"+escapearg(htmlspecialchars(user_input))+")",'ig');
    // loop throught arr of suggestions creating an LI element for each suggestion
    for (var i=0;i<arr.length;i++){
      var val = new String(arr[i].value);
      // using RE
      var output = htmlspecialchars(val).replace(re,'<b>$1</b>');
      // using substr
      //var st = val.toLowerCase().indexOf( user_input.toLowerCase() );
      //var len = user_input.length;
      //var output = val.substring(0,st)+"<em>"+val.substring(st,st+len)+"</em>"+val.substring(st+len);

      var span = $('<span class="jqac-link">'+output+'</span>').get(0);
      if (arr[i].info != undefined && arr[i].info != ""){
        $(span).append($('<div class="jqac-info">'+arr[i].info+'</div>'));
      }

      $(span).attr('name',i+1);
      $(span).click(function (ev) {setHighlightedValue(); });
      $(span).mouseover(function () { setHighlight($(this).attr('name'),true); });

      var li = $('<li></li>').get(0);
      $(li).append(span);

      $(suggestions_list).append(li);
    }

    // no results
    if (arr.length == 0){
        clearSuggestions();
      //$(suggestions_list).append('<li class="jqac-warning">'+options.noresults+'</li>');
    }

    $(suggestions_menu).append(suggestions_list);

    // get position of target textfield
    // position holding div below it
    // set width of holding div to width of field
    var pos = me.offset();

    $(suggestions_menu).css('left', pos.left + "px");
    $(suggestions_menu).css('top', ( pos.top + me.height() + 2 ) + "px");
    if(!options.autowidth)
      $(suggestions_menu).width(me.width());

    // set mouseover functions for div
    // when mouse pointer leaves div, set a timeout to remove the list after an interval
    // when mouse enters div, kill the timeout so the list won't be removed
    $(suggestions_menu).mouseup(function(){ killTimeout() });
    $(suggestions_menu).mouseover(function(){ killTimeout() });
    $(suggestions_menu).mouseout(function(){ resetTimeout() });

    // add DIV to document
    $('body').append(suggestions_menu);

    // bgIFRAME support
    if($.fn.bgiframe)
      $(suggestions_menu).bgiframe({height: suggestions_menu.scrollHeight});


    // adjust height: add +20 for scrollbar
    if(suggestions_menu.scrollHeight > options.height){
      $(suggestions_menu).height(options.height);
      $(suggestions_menu).width($(suggestions_menu).width()+2);
    }
	
    // currently no item is highlighted
    current_highlight = 0;

    // remove list after an interval
    clearSuggestionsTimer = setTimeout(function () { clearSuggestions() }, options.timeout);
  };
  // set highlighted value
  function setHighlightedValue(){
    if(current_highlight && suggestions[current_highlight-1]){
      var sugg = suggestions[ current_highlight-1 ];
      if(sugg.affected_value != undefined && sugg.affected_value != '')
        setSuggestion(sugg.affected_value);
      else
        setSuggestion(sugg.value);
        
      // pass selected object to callback function, if exists
      var obj = suggestions[current_highlight-1];
      clearSuggestions();
      if ($.isFunction(options.callback))
        options.callback.call(me_this, obj);
    }
  };
  // change highlight according to key
  function changeHighlight(key){	
    if(!suggestions_list || suggestions.length == 0) return false;
    var n;
    if (key == ARRDOWN)
      n = current_highlight + 1;
    else if (key == ARRUP)
      n = current_highlight - 1;

    if (n > $(suggestions_list).children().size())
      n = 1;
    if (n < 1)
      n = $(suggestions_list).children().size();
    setHighlight(n);
  };
  // change highlight
  function setHighlight(n,mouse_mode){
    if (!suggestions_list) return false;
    if (current_highlight > 0) clearHighlight();
    current_highlight = Number(n);
    var li = $(suggestions_list).children().get(current_highlight-1);
    li.className = 'jqac-highlight';
    // for mouse mode don't adjust scroll! prevent scrolling jumps
    if(!mouse_mode) adjustScroll(li);
    killTimeout();
  };
  // clear highlight
  function clearHighlight(){
    if (!suggestions_list)return false;
    if (current_highlight > 0){
      $(suggestions_list).children().get(current_highlight-1).className = '';
      current_highlight = 0;
    }
  };
  // clear suggestions list
  function clearSuggestions(){
    me.attr('suggest_menu','');
    killTimeout();
    if(suggestions_menu){
      $(suggestions_menu).remove();
      suggestions_menu = false;
      suggestions_list = false;
      current_highlight = 0;
    }
  };
  // set scroll
  function adjustScroll(el){
    if(!suggestions_menu) return false;
    var viewportHeight = suggestions_menu.clientHeight;        
    var wholeHeight = suggestions_menu.scrollHeight;
    var scrolled = suggestions_menu.scrollTop;
    var elTop = el.offsetTop;
    var elBottom = elTop + el.offsetHeight;
    if(elBottom > scrolled + viewportHeight){
      suggestions_menu.scrollTop = elBottom - viewportHeight;
    }
    else if(elTop < scrolled){
      suggestions_menu.scrollTop = elTop;
    }
    return true; 
  }
  // timeout funcs
  function killTimeout(){
    clearTimeout(clearSuggestionsTimer);
  };
  function resetTimeout(){
    clearTimeout(clearSuggestionsTimer);
    clearSuggestionsTimer = setTimeout(function () { clearSuggestions() }, 1000);
  };
  
})};

})($);


/* Copyright (c) 2006 Brandon Aaron (http://brandonaaron.net)
 * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) 
 * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
 *
 * $LastChangedDate: 2007-07-11 23:14:51 -0500 (Wed, 11 Jul 2007) $
 * $Rev: 2323 $
 *
 * Version 2.1
 */

(function($){

/**
 * The bgiframe is chainable and applies the iframe hack to get 
 * around zIndex issues in IE6. It will only apply itself in IE 
 * and adds a class to the iframe called 'bgiframe'. The iframe
 * is appeneded as the first child of the matched element(s) 
 * with a tabIndex and zIndex of -1.
 * 
 * By default the plugin will take borders, sized with pixel units,
 * into account. If a different unit is used for the border's width,
 * then you will need to use the top and left settings as explained below.
 *
 * NOTICE: This plugin has been reported to cause perfromance problems
 * when used on elements that change properties (like width, height and
 * opacity) a lot in IE6. Most of these problems have been caused by 
 * the expressions used to calculate the elements width, height and 
 * borders. Some have reported it is due to the opacity filter. All 
 * these settings can be changed if needed as explained below.
 *
 * @example $('div').bgiframe();
 * @before <div><p>Paragraph</p></div>
 * @result <div><iframe class="bgiframe".../><p>Paragraph</p></div>
 *
 * @param Map settings Optional settings to configure the iframe.
 * @option String|Number top The iframe must be offset to the top
 * 		by the width of the top border. This should be a negative 
 *      number representing the border-top-width. If a number is 
 * 		is used here, pixels will be assumed. Otherwise, be sure
 *		to specify a unit. An expression could also be used. 
 * 		By default the value is "auto" which will use an expression 
 * 		to get the border-top-width if it is in pixels.
 * @option String|Number left The iframe must be offset to the left
 * 		by the width of the left border. This should be a negative 
 *      number representing the border-left-width. If a number is 
 * 		is used here, pixels will be assumed. Otherwise, be sure
 *		to specify a unit. An expression could also be used. 
 * 		By default the value is "auto" which will use an expression 
 * 		to get the border-left-width if it is in pixels.
 * @option String|Number width This is the width of the iframe. If
 *		a number is used here, pixels will be assume. Otherwise, be sure
 * 		to specify a unit. An experssion could also be used.
 *		By default the value is "auto" which will use an experssion
 * 		to get the offsetWidth.
 * @option String|Number height This is the height of the iframe. If
 *		a number is used here, pixels will be assume. Otherwise, be sure
 * 		to specify a unit. An experssion could also be used.
 *		By default the value is "auto" which will use an experssion
 * 		to get the offsetHeight.
 * @option Boolean opacity This is a boolean representing whether or not
 * 		to use opacity. If set to true, the opacity of 0 is applied. If
 *		set to false, the opacity filter is not applied. Default: true.
 * @option String src This setting is provided so that one could change 
 *		the src of the iframe to whatever they need.
 *		Default: "javascript:false;"
 *
 * @name bgiframe
 * @type jQuery
 * @cat Plugins/bgiframe
 * @author Brandon Aaron (brandon.aaron@gmail.com || http://brandonaaron.net)
 */
$.fn.bgIframe = $.fn.bgiframe = function(s) {
	// This is only for IE6
	if ( $.browser.msie && /6.0/.test(navigator.userAgent) ) {
		s = $.extend({
			top     : 'auto', // auto == .currentStyle.borderTopWidth
			left    : 'auto', // auto == .currentStyle.borderLeftWidth
			width   : 'auto', // auto == offsetWidth
			height  : 'auto', // auto == offsetHeight
			opacity : true,
			src     : 'javascript:false;'
		}, s || {});
		var prop = function(n){return n&&n.constructor==Number?n+'px':n;},
		    html = '<iframe class="bgiframe"frameborder="0"tabindex="-1"src="'+s.src+'"'+
		               'style="display:block;position:absolute;z-index:-1;'+
			               (s.opacity !== false?'filter:Alpha(Opacity=\'0\');':'')+
					       'top:'+(s.top=='auto'?'expression(((parseInt(this.parentNode.currentStyle.borderTopWidth)||0)*-1)+\'px\')':prop(s.top))+';'+
					       'left:'+(s.left=='auto'?'expression(((parseInt(this.parentNode.currentStyle.borderLeftWidth)||0)*-1)+\'px\')':prop(s.left))+';'+
					       'width:'+(s.width=='auto'?'expression(this.parentNode.offsetWidth+\'px\')':prop(s.width))+';'+
					       'height:'+(s.height=='auto'?'expression(this.parentNode.offsetHeight+\'px\')':prop(s.height))+';'+
					'"/>';
		return this.each(function() {
			if ( $('> iframe.bgiframe', this).length == 0 )
				this.insertBefore( document.createElement(html), this.firstChild );
		});
	}
	return this;
};

})(jQuery);

/*
 * jQuery delegate plug-in v1.0
 *
 * Copyright (c) 2007 Jörn Zaefferer
 *
 * $Id: jquery.delegate.js 4328 2007-12-28 16:39:00Z joern.zaefferer $
 *
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 */

// provides cross-browser focusin and focusout events
// IE has native support, in other browsers, use event caputuring (neither bubbles)

// provides delegate(type: String, delegate: Selector, handler: Callback) plugin for easier event delegation
// handler is only called when $(event.target).is(delegate), in the scope of the jQuery-object for event.target 

// provides triggerEvent(type: String, target: Element) to trigger delegated events
;(function($) {
	$.extend($.event.special, {
		focusin: {
			setup: function() {
				if ($.browser.msie)
					return false;
				this.addEventListener("focus", $.event.special.focusin.handler, true);
			},
			teardown: function() {
				if ($.browser.msie)
					return false;
				this.removeEventListener("focus", $.event.special.focusin.handler, true);
			},
			handler: function(event) {
				var args = Array.prototype.slice.call( arguments, 1 );
				args.unshift($.extend($.event.fix(event), { type: "focusin" }));
				return $.event.handle.apply(this, args);
			}
		},
		focusout: {
			setup: function() {
				if ($.browser.msie)
					return false;
				this.addEventListener("blur", $.event.special.focusout.handler, true);
			},
			teardown: function() {
				if ($.browser.msie)
					return false;
				this.removeEventListener("blur", $.event.special.focusout.handler, true);
			},
			handler: function(event) {
				var args = Array.prototype.slice.call( arguments, 1 );
				args.unshift($.extend($.event.fix(event), { type: "focusout" }));
				return $.event.handle.apply(this, args);
			}
		}
	});
	$.extend($.fn, {
		delegate: function(type, delegate, handler) {
			return this.bind(type, function(event) {
				var target = $(event.target);
				if (target.is(delegate)) {
					return handler.apply(target, arguments);
				}
			});
		},
		triggerEvent: function(type, target) {
			return this.triggerHandler(type, [jQuery.event.fix({ type: type, target: target })]);
		}
	})
})(jQuery);


/*
 * jQuery Example Plugin 1.3.1
 * Populate form inputs with example text that disappears on focus.
 *
 * e.g.
 *  $('input#name').example('Bob Smith');
 *  $('input[@title]').example(function() {
 *    return $(this).attr('title');
 *  });
 *  $('textarea#message').example('Type your message here', {
 *    class_name: 'example_text',
 *    hide_label: true
 *  });
 *
 * Copyright (c) Paul Mucur (http://mucur.name), 2007-2008.
 * Dual-licensed under the BSD (BSD-LICENSE.txt) and GPL License
 * (GPL-LICENSE.txt).
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */
(function($) {
      
  $.fn.example = function(text, args) {
    
    /* Load the default options. */
    var options = $.extend({}, $.fn.example.defaults, args);
    
    /* The following event handlers only need to be bound once
     * per class name. In order to do this, an array of used
     * class names is stored and checked on each use of the plugin. 
     * If the class name is in the array then this whole section 
     * is skipped. If not, the events are bound and the class name 
     * added to the array.
     */
    var bound_class_names = $.fn.example.bound_class_names;
    
    /* If the class name is *not* in the array. */
    if ($.inArray(options.class_name, bound_class_names) == -1) {
      
      /* Because Gecko-based browsers "helpfully" cache form values
       * but ignore all other attributes such as class, all example
       * values must be cleared on page unload to prevent them from
       * being saved.
       */
      $(window).unload(function() {
        $('.' + options.class_name).val('');
      });
      
      /* Clear fields that are still examples before any form is submitted
       * otherwise those examples will be sent along as well.
       * 
       * Previous to 1.3, this would only be bound to forms that were
       * parents of example fields but this meant that a page with
       * multiple forms would not work correctly.
       */
      $('form').submit(function() {
        
        /* Clear only the fields inside this particular form. */
        $(this).find('.' + options.class_name).val($(this).innerValue);
      });
      
      /* Add the class name to the array. */
      bound_class_names.push(options.class_name);
      $.fn.example.bound_class_names = bound_class_names;
    }
    
    return this.each(function() {
	  
	  
      var $this = $(this);
	  
	  $this.innerValue = $this.val();
      
      /* Initially place the example text in the field if it is empty. */
      if ($this.val() == '') {
        $this.addClass(options.class_name);
        
        /* The text argument can now be a function; if this is the case,
         * call it, passing the current jQuery object as `this`.
         */
        $this.val($.isFunction(text) ? text.call(this) : text);
      }
    
      /* If the option is set, hide the associated label (and its line-break
        * if it has one).
        */
      if (options.hide_label) {
        var label = $('label[@for=' + $this.attr('id') + ']');
        label.next('br').hide();
        label.hide();
      }
    
      /* Make the example text disappear when someone focuses.
       *
       * To determine whether the value of the field is an example or not,
       * check for the example class name only; comparing the actual value
       * seems wasteful and can stop people from using example values as real 
       * input.
       */
      $this.focus(function() {
        if ($(this).is('.' + options.class_name)) {
          $(this).val('');
          $(this).removeClass(options.class_name);
        }
      });
    
      /* Make the example text reappear if the input is blank on blurring. */
      $this.blur(function() {
        if ($(this).val() == '') {
          $(this).addClass(options.class_name);
          
          /* Re-evaluate the callback function every time the user
           * blurs the field without entering anything. While this
           * is not as efficient as caching the value, it allows for
           * more dynamic applications of the plugin.
           */
          $(this).val($.isFunction(text) ? text.call(this) : text);
        }
      });
    });
  };
  
  /* Users can override the defaults for the plugin like so:
   *
   *   $.fn.example.defaults.class_name = 'not_example';
   *   $.fn.example.defaults.hide_label = true;
   */
  $.fn.example.defaults = {
    class_name: 'example',
    hide_label: false
  };
  
  /* All the class names used are stored in the following array. */
  $.fn.example.bound_class_names = [];
  
})(jQuery);


jQuery.fn.extend({
	everyTime: function(interval, label, fn, times, belay) {
		return this.each(function() {
			jQuery.timer.add(this, interval, label, fn, times, belay);
		});
	},
	oneTime: function(interval, label, fn) {
		return this.each(function() {
			jQuery.timer.add(this, interval, label, fn, 1);
		});
	},
	stopTime: function(label, fn) {
		return this.each(function() {
			jQuery.timer.remove(this, label, fn);
		});
	}
});

jQuery.extend({
	timer: {
		guid: 1,
		global: {},
		regex: /^([0-9]+)\s*(.*s)?$/,
		powers: {
			// Yeah this is major overkill...
			'ms': 1,
			'cs': 10,
			'ds': 100,
			's': 1000,
			'das': 10000,
			'hs': 100000,
			'ks': 1000000
		},
		timeParse: function(value) {
			if (value == undefined || value == null)
				return null;
			var result = this.regex.exec(jQuery.trim(value.toString()));
			if (result[2]) {
				var num = parseInt(result[1], 10);
				var mult = this.powers[result[2]] || 1;
				return num * mult;
			} else {
				return value;
			}
		},
		add: function(element, interval, label, fn, times, belay) {
			var counter = 0;
			
			if (jQuery.isFunction(label)) {
				if (!times) 
					times = fn;
				fn = label;
				label = interval;
			}
			
			interval = jQuery.timer.timeParse(interval);

			if (typeof interval != 'number' || isNaN(interval) || interval <= 0)
				return;

			if (times && times.constructor != Number) {
				belay = !!times;
				times = 0;
			}
			
			times = times || 0;
			belay = belay || false;
			
			if (!element.$timers) 
				element.$timers = {};
			
			if (!element.$timers[label])
				element.$timers[label] = {};
			
			fn.$timerID = fn.$timerID || this.guid++;
			
			var handler = function() {
				if (belay && this.inProgress) 
					return;
				this.inProgress = true;
				if ((++counter > times && times !== 0) || fn.call(element, counter) === false)
					jQuery.timer.remove(element, label, fn);
				this.inProgress = false;
			};
			
			handler.$timerID = fn.$timerID;
			
			if (!element.$timers[label][fn.$timerID]) 
				element.$timers[label][fn.$timerID] = window.setInterval(handler,interval);
			
			if ( !this.global[label] )
				this.global[label] = [];
			this.global[label].push( element );
			
		},
		remove: function(element, label, fn) {
			var timers = element.$timers, ret;
			
			if ( timers ) {
				
				if (!label) {
					for ( label in timers )
						this.remove(element, label, fn);
				} else if ( timers[label] ) {
					if ( fn ) {
						if ( fn.$timerID ) {
							window.clearInterval(timers[label][fn.$timerID]);
							delete timers[label][fn.$timerID];
						}
					} else {
						for ( var fn in timers[label] ) {
							window.clearInterval(timers[label][fn]);
							delete timers[label][fn];
						}
					}
					
					for ( ret in timers[label] ) break;
					if ( !ret ) {
						ret = null;
						delete timers[label];
					}
				}
				
				for ( ret in timers ) break;
				if ( !ret ) 
					element.$timers = null;
			}
		}
	}
});

if (jQuery.browser.msie)
	jQuery(window).one("unload", function() {
		var global = jQuery.timer.global;
		for ( var label in global ) {
			var els = global[label], i = els.length;
			while ( --i )
				jQuery.timer.remove(els[i], label);
		}
	});




/*
 * jQuery validation plug-in v1.2
 *
 * http://bassistance.de/jquery-plugins/jquery-plugin-validation/
 * http://docs.jquery.com/Plugins/Validation
 *
 * Copyright (c) 2006 - 2008 Jörn Zaefferer
 *
 * $Id: jquery.validate.js 4484 2008-01-20 13:52:02Z joern.zaefferer $
 *
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 */

jQuery.extend(jQuery.fn, {
	// http://docs.jquery.com/Plugins/Validation/validate
	validate: function( options ) {
		
		// check if a validator for this form was already created
		var validator = jQuery.data(this[0], 'validator');
		if ( validator ) {
			return validator;
		}
		
		validator = new jQuery.validator( options, this[0] );
		jQuery.data(this[0], 'validator', validator); 
		
		if ( validator.settings.onsubmit ) {
		
			// allow suppresing validation by adding a cancel class to the submit button
			this.find("input.cancel:submit").click(function() {
				validator.cancelSubmit = true;
			});
		
			// validate the form on submit
			this.submit( function( event ) {
				if ( validator.settings.debug )
					// prevent form submit to be able to see console output
					event.preventDefault();
					
				function handle() {
					if ( validator.settings.submitHandler ) {
						validator.settings.submitHandler.call( validator, validator.currentForm );
						return false;
					}
					return true;
				}
					
				// prevent submit for invalid forms or custom submit handlers
				if ( validator.cancelSubmit ) {
					validator.cancelSubmit = false;
					return handle();
				}
				if ( validator.form() ) {
					if ( validator.pendingRequest ) {
						validator.formSubmitted = true;
						return false;
					}
					return handle();
				} else {
					validator.focusInvalid();
					return false;
				}
			});
		}
		
		return validator;
	},
	// http://docs.jquery.com/Plugins/Validation/valid
	valid: function() {
        if ( jQuery(this[0]).is('form')) {
            return this.validate().form();
        } else {
            var valid = true;
            var validator = jQuery(this[0].form).validate();
            this.each(function() {
                valid = validator.element(this) && valid;
            });
            return valid;
        }
    },
	// http://docs.jquery.com/Plugins/Validation/rules
	rules: function() {
		var element = this[0];
		var data = jQuery.validator.normalizeRules(
		jQuery.extend(
			jQuery.validator.metadataRules(element),
			jQuery.validator.classRules(element),
			jQuery.validator.attributeRules(element),
			jQuery.validator.staticRules(element)
		), element);
	
	// convert from object to array
	var rules = [];
	jQuery.each(data, function(method, value) {
		rules.push({
			method: method,
			parameters: value
		});
	});
	return rules;
	},
	// destructive add
	push: function( t ) {
		return this.setArray( this.add(t).get() );
	}
});

// Custom selectors
jQuery.extend(jQuery.expr[":"], {
	// http://docs.jquery.com/Plugins/Validation/blank
	blank: "!jQuery.trim(a.value)",
	// http://docs.jquery.com/Plugins/Validation/filled
	filled: "!!jQuery.trim(a.value)",
	// http://docs.jquery.com/Plugins/Validation/unchecked
	unchecked: "!a.checked"
});

jQuery.format = function(source, params) {
	if ( arguments.length == 1 ) 
		return function() {
			var args = jQuery.makeArray(arguments);
			args.unshift(source);
			return jQuery.format.apply( this, args );
		};
	if ( arguments.length > 2 && params.constructor != Array  ) {
		params = jQuery.makeArray(arguments).slice(1);
	}
	if ( params.constructor != Array ) {
		params = [ params ];
	}
	jQuery.each(params, function(i, n) {
		source = source.replace(new RegExp("\\{" + i + "\\}", "g"), n);
	});
	return source;
};

// constructor for validator
jQuery.validator = function( options, form ) {
	this.settings = jQuery.extend( {}, jQuery.validator.defaults, options );
	this.currentForm = form;
	this.init();
};

jQuery.extend(jQuery.validator, {

	defaults: {
		messages: {},
		errorClass: "error",
		errorElement: "label",
		focusInvalid: true,
		errorContainer: jQuery( [] ),
		errorLabelContainer: jQuery( [] ),
		onsubmit: true,
		ignore: [],
		onfocusin: function(element) {
			this.lastActive = element;
				
			// hide error label and remove error class on focus if enabled
			if ( this.settings.focusCleanup && !this.blockFocusCleanup ) {
				this.settings.unhighlight.call( this, element, this.settings.errorClass );
				this.errorsFor(element).hide();
			}
		},
		onfocusout: function(element) {
			if ( !this.checkable(element) && (element.name in this.submitted || !this.optional(element)) ) {
				this.element(element);
			}
		},
		onkeyup: function(element) {
			if ( element.name in this.submitted || element == this.lastElement ) {
				this.element(element);
			}
		},
		onclick: function(element) {
			if ( element.name in this.submitted )
				this.element(element);
		},
		highlight: function( element, errorClass ) {
			jQuery( element ).addClass( errorClass );
		},
		unhighlight: function( element, errorClass ) {
			jQuery( element ).removeClass( errorClass );
		}
	},

	// http://docs.jquery.com/Plugins/Validation/Validator/setDefaults
	setDefaults: function(settings) {
		jQuery.extend( jQuery.validator.defaults, settings );
	},

	messages: {
		required: "This field is required.",
		remote: "Please fix this field.",
		email: "Please enter a valid email address.",
		url: "Please enter a valid URL.",
		date: "Please enter a valid date.",
		dateISO: "Please enter a valid date (ISO).",
		dateDE: "Bitte geben Sie ein gültiges Datum ein.",
		number: "Please enter a valid number.",
		numberDE: "Bitte geben Sie eine Nummer ein.",
		digits: "Please enter only digits",
		creditcard: "Please enter a valid credit card.",
		equalTo: "Please enter the same value again.",
		accept: "Please enter a value with a valid extension.",
		maxlength: jQuery.format("Please enter no more than {0} characters."),
		maxLength: jQuery.format("Please enter no more than {0} characters."),
		minlength: jQuery.format("Please enter at least {0} characters."),
		minLength: jQuery.format("Please enter at least {0} characters."),
		rangelength: jQuery.format("Please enter a value between {0} and {1} characters long."),
		rangeLength: jQuery.format("Please enter a value between {0} and {1} characters long."),
		rangeValue: jQuery.format("Please enter a value between {0} and {1}."),
		range: jQuery.format("Please enter a value between {0} and {1}."),
		maxValue: jQuery.format("Please enter a value less than or equal to {0}."),
		max: jQuery.format("Please enter a value less than or equal to {0}."),
		minValue: jQuery.format("Please enter a value greater than or equal to {0}."),
		min: jQuery.format("Please enter a value greater than or equal to {0}.")
	},
	
	prototype: {
		
		init: function() {
			this.labelContainer = jQuery(this.settings.errorLabelContainer);
			this.errorContext = this.labelContainer.length && this.labelContainer || jQuery(this.currentForm);
			this.containers = jQuery(this.settings.errorContainer).add( this.settings.errorLabelContainer );
			this.submitted = {};
			this.valueCache = {};
			this.pendingRequest = 0;
			this.pending = {};
			this.invalid = {};
			this.reset();
			
			function delegate(event) {
				var validator = jQuery.data(this[0].form, "validator");
				validator.settings["on" + event.type] && validator.settings["on" + event.type].call(validator, this[0] );
			}
			jQuery(this.currentForm)
				.delegate("focusin focusout keyup", ":text, :password, :file, select, textarea", delegate)
				.delegate("click", ":radio, :checkbox", delegate);
		},

		// http://docs.jquery.com/Plugins/Validation/Validator/form
		form: function() {
			this.prepareForm();
			var elements = this.elements();
			for ( var i = 0; elements[i]; i++ ) {
				this.check( elements[i] );
			}
			jQuery.extend(this.submitted, this.errorMap);
			this.invalid = jQuery.extend({}, this.errorMap);
			jQuery(this.currentForm).triggerHandler("invalid-form.validate", [this]);
			this.showErrors();
			return this.valid();
		},
		
		// http://docs.jquery.com/Plugins/Validation/Validator/element
		element: function( element ) {
			element = this.clean( element );
			this.lastElement = element;
			this.prepareElement( element );
			var result = this.check( element );
			if ( result ) {
				delete this.invalid[element.name];
			} else {
				this.invalid[element.name] = true;
			}
			if ( !this.numberOfInvalids() ) {
				// Hide error containers on last error
				this.toHide.push( this.containers );
			}
			this.showErrors();
			return result;
		},

		// http://docs.jquery.com/Plugins/Validation/Validator/showErrors
		showErrors: function(errors) {
			if(errors) {
				// add items to error list and map
				jQuery.extend( this.errorMap, errors );
				this.errorList = [];
				for ( var name in errors ) {
					this.errorList.push({
						message: errors[name],
						element: this.findByName(name)[0]
					});
				}
				// remove items from success list
				this.successList = jQuery.grep( this.successList, function(element) {
					return !(element.name in errors);
				});
			}
			this.settings.showErrors
				? this.settings.showErrors.call( this, this.errorMap, this.errorList )
				: this.defaultShowErrors();
		},
		
		// http://docs.jquery.com/Plugins/Validation/Validator/resetForm
		resetForm: function() {
			if ( jQuery.fn.resetForm )
				jQuery( this.currentForm ).resetForm();
			this.prepareForm();
			this.hideErrors();
			this.elements().removeClass( this.settings.errorClass );
		},
		
		numberOfInvalids: function() {
			var count = 0;
			for ( var i in this.invalid )
				count++;
			return count;
		},
		
		hideErrors: function() {
			this.addWrapper( this.toHide ).hide();
		},
		
		valid: function() {
			return this.size() == 0;
		},
		
		size: function() {
			return this.errorList.length;
		},
		
		focusInvalid: function() {
			if( this.settings.focusInvalid ) {
				try {
					jQuery(this.findLastActive() || this.errorList.length && this.errorList[0].element || []).filter(":visible").focus();
				} catch(e) { /* ignore IE throwing errors when focusing hidden elements */ }
			}
		},
		
		findLastActive: function() {
			var lastActive = this.lastActive;
			return lastActive && jQuery.grep(this.errorList, function(n) {
				return n.element.name == lastActive.name;
			}).length == 1 && lastActive;
		},
		
		elements: function() {
			var validator = this;
			
			
			var rulesCache = {};
			
			// select all valid inputs inside the form (no submit or reset buttons)
			// workaround with jQuery([]).add until http://dev.jquery.com/ticket/2114 is solved
			return jQuery([]).add(this.currentForm.elements)
			.filter("input, select, textarea")
			.not(":submit, :reset, [disabled]")
			.not( this.settings.ignore )
			.filter(function() {
				!this.name && validator.settings.debug && window.console && console.error( "%o has no name assigned", this);
			
				// select only the first element for each name, and only those with rules specified
				if ( this.name in rulesCache || !jQuery(this).rules().length )
					return false;
				
				rulesCache[this.name] = true;
				return true;
			});
		},
		
		clean: function( selector ) {
			return jQuery( selector )[0];
		},
		
		errors: function() {
			return jQuery( this.settings.errorElement + "." + this.settings.errorClass, this.errorContext );
		},
		
		reset: function() {
			this.successList = [];
			this.errorList = [];
			this.errorMap = {};
			this.toShow = jQuery( [] );
			this.toHide = jQuery( [] );
			this.formSubmitted = false;
		},
		
		prepareForm: function() {
			this.reset();
			this.toHide = this.errors().push( this.containers );
		},
		
		prepareElement: function( element ) {
			this.reset();
			this.toHide = this.errorsFor( this.clean(element) );
		},
	
		check: function( element ) {
			element = this.clean( element );
			this.settings.unhighlight.call( this, element, this.settings.errorClass );
			var rules = jQuery(element).rules();
			for( var i = 0; rules[i]; i++) {
				var rule = rules[i];
				try {
					var result = jQuery.validator.methods[rule.method].call( this, jQuery.trim(element.value), element, rule.parameters );
					if ( result == "dependency-mismatch" )
						break;
					if ( result == "pending" ) {
						this.toHide = this.toHide.not( this.errorsFor(element) );
						return;
					}
					if( !result ) {
						this.formatAndAdd( element, rule );
						return false;
					}
				} catch(e) {
					this.settings.debug && window.console && console.warn("exception occured when checking element " + element.id
						 + ", check the '" + rule.method + "' method");
					throw e;
				}
			}
			if ( rules.length )
				this.successList.push(element);
			return true;
		},
		
		// return the custom message for the given element name and validation method
		customMessage: function( name, method ) {
			var m = this.settings.messages[name];
			return m && (m.constructor == String
				? m
				: m[method]);
		},
		
		// return the first defined argument, allowing empty strings
		findDefined: function() {
			for(var i = 0; i < arguments.length; i++) {
				if (arguments[i] !== undefined)
					return arguments[i];
			}
			return undefined;
		},
		
		defaultMessage: function( element, method) {
			return this.findDefined(
				this.customMessage( element.name, method ),
				// title is never undefined, so handle empty string as undefined
				element.title || undefined,
				jQuery.validator.messages[method],
				"<strong>Warning: No message defined for " + element.name + "</strong>"
			);
		},
		
		formatAndAdd: function( element, rule ) {
			var message = this.defaultMessage( element, rule.method );
			if ( typeof message == "function" ) 
				message = message.call(this, rule.parameters, element);
			this.errorList.push({
				message: message,
				element: element
			});
			this.errorMap[element.name] = message;
			this.submitted[element.name] = message;
		},
		
		addWrapper: function(toToggle) {
			if ( this.settings.wrapper )
				toToggle.push( toToggle.parents( this.settings.wrapper ) );
			return toToggle;
		},
		
		defaultShowErrors: function() {
			for ( var i = 0; this.errorList[i]; i++ ) {
				var error = this.errorList[i];
				this.settings.highlight.call( this, error.element, this.settings.errorClass );
				this.showLabel( error.element, error.message );
			}
			if( this.errorList.length ) {
				this.toShow.push( this.containers );
			}
			if (this.settings.success) {
				for ( var i = 0; this.successList[i]; i++ ) {
					this.showLabel( this.successList[i] );
				}
			}
			this.toHide = this.toHide.not( this.toShow );
			this.hideErrors();
			this.addWrapper( this.toShow ).show();
		},
		
		showLabel: function(element, message) {
			var label = this.errorsFor( element );
			if ( label.length ) {
				// refresh error/success class
				label.removeClass().addClass( this.settings.errorClass );
			
				// check if we have a generated label, replace the message then
				if( this.settings.overrideErrors || label.attr("generated") ) {
					label.html(message);
				}
			} else {
				// create label
				label = jQuery("<" + this.settings.errorElement + "/>")
					.attr({"for":  this.idOrName(element), generated: true})
					.addClass(this.settings.errorClass)
					.html(message || "");
				if ( this.settings.wrapper ) {
					// make sure the element is visible, even in IE
					// actually showing the wrapped element is handled elsewhere
					label = label.hide().show().wrap("<" + this.settings.wrapper + ">").parent();
				}
				if ( !this.labelContainer.append(label).length )
					this.settings.errorPlacement
						? this.settings.errorPlacement(label, jQuery(element) )
						: label.insertAfter(element);
			}
			if ( !message && this.settings.success ) {
				label.text("");
				typeof this.settings.success == "string"
					? label.addClass( this.settings.success )
					: this.settings.success( label );
			}
			this.toShow.push(label);
		},
		
		errorsFor: function(element) {
			return this.errors().filter("[@for='" + this.idOrName(element) + "']");
		},
		
		idOrName: function(element) {
			return this.checkable(element) ? element.name : element.id || element.name;
		},

		rules: function( element ) {
			return jQuery(element).rules();
		},

		checkable: function( element ) {
			return /radio|checkbox/i.test(element.type);
		},
		
		findByName: function( name ) {
			// select by name and filter by form for performance over form.find("[name=...]")
			var form = this.currentForm;
			return jQuery(document.getElementsByName(name)).map(function(index, element) {
				return element.form == form && element || null;
				//  && element.name == name
			});
		},
		
		getLength: function(value, element) {
			switch( element.nodeName.toLowerCase() ) {
			case 'select':
				return jQuery("option:selected", element).length;
			case 'input':
				if( this.checkable( element) )
					return this.findByName(element.name).filter(':checked').length;
			}
			return value.length;
		},
	
		depend: function(param, element) {
			return this.dependTypes[typeof param]
				? this.dependTypes[typeof param](param, element)
				: true;
		},
	
		dependTypes: {
			"boolean": function(param, element) {
				return param;
			},
			"string": function(param, element) {
				return !!jQuery(param, element.form).length;
			},
			"function": function(param, element) {
				return param(element);
			}
		},
		
		optional: function(element) {
			return !jQuery.validator.methods.required.call(this, jQuery.trim(element.value), element);
		},
		
		startRequest: function(element) {
			if (!this.pending[element.name]) {
				this.pendingRequest++;
				this.pending[element.name] = true;
			}
		},
		
		stopRequest: function(element, valid) {
			this.pendingRequest--;
			delete this.pending[element.name];
			if ( valid && this.pendingRequest == 0 && this.formSubmitted && this.form() ) {
				jQuery(this.currentForm).submit();
			}
		},
		
		previousValue: function(element) {
			return jQuery.data(element, "previousValue") || jQuery.data(element, "previousValue", previous = {
				old: null,
				valid: true,
				message: this.defaultMessage( element, "remote" )
			});
		}
		
	},
	
	classRuleSettings: {
		required: {required: true},
		email: {email: true},
		url: {url: true},
		date: {date: true},
		dateISO: {dateISO: true},
		dateDE: {dateDE: true},
		number: {number: true},
		numberDE: {numberDE: true},
		digits: {digits: true},
		creditcard: {creditcard: true}
	},
	
	addClassRules: function(className, rules) {
		className.constructor == String ?
			this.classRuleSettings[className] = rules :
			jQuery.extend(this.classRuleSettings, className);
	},
	
	classRules: function(element) {
		var rules = {};
		var classes = jQuery(element).attr('class');
		classes && jQuery.each(classes.split(' '), function() {
			if (this in jQuery.validator.classRuleSettings) {
				jQuery.extend(rules, jQuery.validator.classRuleSettings[this]);
			}
		});
		return rules;
	},
	
	attributeRules: function(element) {
		var rules = {};
		var $element = jQuery(element);
		
		for (method in jQuery.validator.methods) {
			var value = $element.attr(method);
			// allow 0 but neither undefined nor empty string
			if (value !== undefined && value !== '') {
				rules[method] = value;
			}
		}
		
		// maxlength may be returned as -1, 2147483647 (IE) and 1024 (safari) for text inputs
		if (rules.maxlength && /-1|2147483647|1024/.test(rules.maxlength)) {
			delete rules.maxlength;
			// deprecated
			delete rules.maxLength;
		}
		
		return rules;
	},
	
	metadataRules: function(element) {
		if (!jQuery.metadata) return {};
		
		var meta = jQuery.data(element.form, 'validator').settings.meta;
		return meta ?
			jQuery(element).metadata()[meta] :
			jQuery(element).metadata();
	},
	
	staticRules: function(element) {
		var rules = {};
		var validator = jQuery.data(element.form, 'validator');
		if (validator.settings.rules) {
			rules = jQuery.validator.normalizeRule(validator.settings.rules[element.name]) || {};
		}
		return rules;
	},
	
	normalizeRules: function(rules, element) {
		// convert deprecated rules
		jQuery.each({
			minLength: 'minlength',
			maxLength: 'maxlength',
			rangeLength: 'rangelength',
			minValue: 'min',
			maxValue: 'max',
			rangeValue: 'range'
		}, function(dep, curr) {
			if (rules[dep]) {
				rules[curr] = rules[dep];
				delete rules[dep];
			}
		});
		
		// evaluate parameters
		jQuery.each(rules, function(rule, parameter) {
			rules[rule] = jQuery.isFunction(parameter) ? parameter(element) : parameter;
		});
		
		// clean number parameters
		jQuery.each(['minlength', 'maxlength', 'min', 'max'], function() {
			if (rules[this]) {
				rules[this] = Number(rules[this]);
			}
		});
		jQuery.each(['rangelength', 'range'], function() {
			if (rules[this]) {
				rules[this] = [Number(rules[this][0]), Number(rules[this][1])];
			}
		});
		
		// auto-create ranges
		if (rules.min && rules.max) {
			rules.range = [rules.min, rules.max];
			delete rules.min;
			delete rules.max;
		}
		if (rules.minlength && rules.maxlength) {
			rules.rangelength = [rules.minlength, rules.maxlength];
			delete rules.minlength;
			delete rules.maxlength;
		}
		
		return rules;
	},
	
	// Converts a simple string to a {string: true} rule, e.g., "required" to {required:true}
	normalizeRule: function(data) {
		if( typeof data == "string" ) {
			var transformed = {};
			transformed[data] = true;
			data = transformed;
		}
		return data;
	},
	
	// http://docs.jquery.com/Plugins/Validation/Validator/addMethod
	addMethod: function(name, method, message) {
		jQuery.validator.methods[name] = method;
		jQuery.validator.messages[name] = message;
		if (method.length < 3) {
			jQuery.validator.addClassRules(name, jQuery.validator.normalizeRule(name));
		}
	},

	methods: {

		// http://docs.jquery.com/Plugins/Validation/Methods/required
		required: function(value, element, param) {
			// check if dependency is met
			if ( !this.depend(param, element) )
				return "dependency-mismatch";
			switch( element.nodeName.toLowerCase() ) {
			case 'select':
				var options = jQuery("option:selected", element);
				return options.length > 0 && ( element.type == "select-multiple" || (jQuery.browser.msie && !(options[0].attributes['value'].specified) ? options[0].text : options[0].value).length > 0);
			case 'input':
				if ( this.checkable(element) )
					return this.getLength(value, element) > 0;
			default:
				return value.length > 0;
			}
		},
		
		// http://docs.jquery.com/Plugins/Validation/Methods/remote
		remote: function(value, element, param) {
			if ( this.optional(element) )
				return true;
				
			var previous = this.previousValue(element);
			this.settings.messages[element.name].remote = typeof previous.message == "function" ? previous.message(value) : previous.message;
			if ( previous.old !== value ) {
				previous.old = value;
				var validator = this;
				this.startRequest(element);
				var data = {};
				data[element.name] = value;
				jQuery.ajax({
					url: param,
					mode: "abort",
					port: "validate" + element.name,
					dataType: "json",
					data: data,
					success: function(response) {
						if ( !response ) {
							var errors = {};
							errors[element.name] =  response || validator.defaultMessage( element, "remote" );
							validator.showErrors(errors);
						} else {
							var submitted = validator.formSubmitted;
							validator.prepareElement(element);
							validator.formSubmitted = submitted;
							validator.successList.push(element);
							validator.showErrors();
						}
						previous.valid = response;
						validator.stopRequest(element, response);
					}
				});
				return "pending";
			} else if( this.pending[element.name] ) {
				return "pending";
			}
			return previous.valid;
		},

		// http://docs.jquery.com/Plugins/Validation/Methods/minlength
		minlength: function(value, element, param) {
			return this.optional(element) || this.getLength(value, element) >= param;
		},
		
		// deprecated, to be removed in 1.3
		minLength: function(value, element, param) {
			return jQuery.validator.methods.minlength.apply(this, arguments);
		},
	
		// http://docs.jquery.com/Plugins/Validation/Methods/maxlength
		maxlength: function(value, element, param) {
			return this.optional(element) || this.getLength(value, element) <= param;
		},
		
		// deprecated, to be removed in 1.3
		maxLength: function(value, element, param) {
			return jQuery.validator.methods.maxlength.apply(this, arguments);
		},
		
		// http://docs.jquery.com/Plugins/Validation/Methods/rangelength
		rangelength: function(value, element, param) {
			var length = this.getLength(value, element);
			return this.optional(element) || ( length >= param[0] && length <= param[1] );
		},
		
		// deprecated, to be removed in 1.3
		rangeLength: function(value, element, param) {
			return jQuery.validator.methods.rangelength.apply(this, arguments);
		},
	
		// http://docs.jquery.com/Plugins/Validation/Methods/min
		min: function( value, element, param ) {
			return this.optional(element) || value >= param;
		},
		
		// deprecated, to be removed in 1.3
		minValue: function() {
			return jQuery.validator.methods.min.apply(this, arguments);
		},
		
		// http://docs.jquery.com/Plugins/Validation/Methods/max
		max: function( value, element, param ) {
			return this.optional(element) || value <= param;
		},
		
		// deprecated, to be removed in 1.3
		maxValue: function() {
			return jQuery.validator.methods.max.apply(this, arguments);
		},
		
		// http://docs.jquery.com/Plugins/Validation/Methods/range
		range: function( value, element, param ) {
			return this.optional(element) || ( value >= param[0] && value <= param[1] );
		},
		
		// deprecated, to be removed in 1.3
		rangeValue: function() {
			return jQuery.validator.methods.range.apply(this, arguments);
		},
		
		// http://docs.jquery.com/Plugins/Validation/Methods/email
		email: function(value, element) {
			// contributed by Scott Gonzalez: http://projects.scottsplayground.com/email_address_validation/
			return this.optional(element) || /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)*(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i.test(value);
		},
	
		// http://docs.jquery.com/Plugins/Validation/Methods/url
		url: function(value, element) {
			// contributed by Scott Gonzalez: http://projects.scottsplayground.com/iri/
			return this.optional(element) || /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)*(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(value);
		},
        
		// http://docs.jquery.com/Plugins/Validation/Methods/date
		date: function(value, element) {
			return this.optional(element) || !/Invalid|NaN/.test(new Date(value));
		},
	
		// http://docs.jquery.com/Plugins/Validation/Methods/dateISO
		dateISO: function(value, element) {
			return this.optional(element) || /^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(value);
		},
	
		// http://docs.jquery.com/Plugins/Validation/Methods/dateDE
		dateDE: function(value, element) {
			return this.optional(element) || /^\d\d?\.\d\d?\.\d\d\d?\d?$/.test(value);
		},
	
		// http://docs.jquery.com/Plugins/Validation/Methods/number
		number: function(value, element) {
			return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d+)?$/.test(value);
		},
	
		// http://docs.jquery.com/Plugins/Validation/Methods/numberDE
		numberDE: function(value, element) {
			return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:\.\d{3})+)(?:,\d+)?$/.test(value);
		},
		
		// http://docs.jquery.com/Plugins/Validation/Methods/digits
		digits: function(value, element) {
			return this.optional(element) || /^\d+$/.test(value);
		},
		
		// http://docs.jquery.com/Plugins/Validation/Methods/creditcard
		// based on http://en.wikipedia.org/wiki/Luhn
		creditcard: function(value, element) {
			if ( this.optional(element) )
				return true;
			var nCheck = 0,
				nDigit = 0,
				bEven = false;

			value = value.replace(/\D/g, "");

			for (n = value.length - 1; n >= 0; n--) {
				var cDigit = value.charAt(n);
				var nDigit = parseInt(cDigit, 10);
				if (bEven) {
					if ((nDigit *= 2) > 9)
						nDigit -= 9;
				}
				nCheck += nDigit;
				bEven = !bEven;
			}

			return (nCheck % 10) == 0;
		},
		
		// http://docs.jquery.com/Plugins/Validation/Methods/accept
		accept: function(value, element, param) {
			param = typeof param == "string" ? param : "png|jpe?g|gif";
			return this.optional(element) || value.match(new RegExp(".(" + param + ")$", "i")); 
		},
		
		// http://docs.jquery.com/Plugins/Validation/Methods/equalTo
		equalTo: function(value, element, param) {
			return value == jQuery(param).val();
		}
		
	}
	
});


/*
 * jQuery Impromptu
 * By: Trent Richardson [http://trentrichardson.com]
 * Version 1.1
 * Last Modified: 11/11/2007
 * 
 * Copyright 2007 Trent Richardson
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
jQuery.extend({	
	ImpromptuDefaults: { prefix:'jqi', buttons:{ Ok:true }, loaded:function(){}, submit:function(){return true;}, callback:function(){}, container:'body', opacity:0.6, overlayspeed:'slow', promptspeed:'fast', show:'show', msgHeight: 0, zindex: 999, bothPosition: true},
	SetImpromptuDefaults: function(o){ 
		jQuery.ImpromptuDefaults = jQuery.extend({},jQuery.ImpromptuDefaults,o);
	},
	prompt: function(m,o){
		o = jQuery.extend({},jQuery.ImpromptuDefaults,o);
		
		var hasFade = !o.notFade;
		
		var fadezindex = o.zindex - 1;
		
		var ie6 = (jQuery.browser.msie && jQuery.browser.version < 7);	
		var b = jQuery(o.container);
		
		var fade = null;
		if((jQuery.browser.msie && jQuery('object, applet').length > 0) || ie6)
			fade = '<iframe src="'+ (o.iframesrc ? o.iframesrc : '/prompt-fade.php') +'" class="'+ o.prefix +'fade" id="'+ o.prefix +'fade" style="display:none" frameborder="no"></iframe>';
	    else
	        fade = '<div class="'+ o.prefix +'fade" id="'+ o.prefix +'fade"></div>'; 
		var msgbox = '<div style="display:none" class="'+ o.prefix +'" id="'+ o.prefix +'"><div class="'+ o.prefix +'container"><div class="'+ o.prefix +'message">'+ m +'</div><div class="'+ o.prefix +'buttons" id="'+ o.prefix +'buttons">';
		jQuery.each(o.buttons,function(k,v){ msgbox += '<button name="'+ o.prefix +'button'+ k +'" id="'+ o.prefix +'button'+ k +'" value="'+ v +'">'+ k +'</button>'}) ;
		msgbox += '</div></div></div>';
		
		var jqi = b.prepend(msgbox).children('#'+ o.prefix);
		var jqif = b.prepend(fade).children('#'+ o.prefix +'fade');				
		if(ie6) b.css({ overflow: "hidden" });//ie6

		jqif.css({ height: b.height(), width: "100%", position: "absolute", top: 0, left: 0, right: 0, bottom: 0, zIndex: fadezindex, display: "none", opacity: o.opacity });
		if (o.bothPosition) {
			jqi.css({ position: (ie6 ? "absolute" : "fixed")});
		}
		else {
			jqi.css({ position: "absolute"});
		}
        jqi.css({top: "50%", left: "50%", display: "none", zIndex: o.zindex, marginLeft: ((((jqi.css("paddingLeft").split("px")[0]*1) + jqi.width())/2)*-1), marginTop: (((jqi.height())/2)*-1) });
		if (ie6) {
			jqi.css({marginTop: $.getScrollOffset()[1]});
		}
        
        jqi.fade = jqif;
        
        jqi.open = function() {
        	if (o.bothPosition) {
				jqi.css({ position: (ie6 ? "absolute" : "fixed")});
			}
			else {
				jqi.css({ position: "absolute"});
			}
            jqi.css({ top: "50%", left: "50%", display: "none", zIndex: o.zindex, marginLeft: ((((jqi.css("paddingLeft").split("px")[0]*1) + jqi.width())/2)*-1), marginTop: (((jqi.height())/2)*-1) });
            if (o.msgHeight) {
                var msg = $('.jqimessage', jqi);
                msg.height(o.msgHeight);
                msg.css('overflow-y', 'scroll');
            }
            if (hasFade) {
                jqif.fadeIn(o.overlayspeed);
            }
            jqi[o.show](o.promptspeed,function(){o.loaded(jqi)});
        }
		
		jqi.center = function(div){
			if (o.bothPosition) {
				jqi.css({ position: (ie6 ? "absolute" : "fixed")});
			}
			else {
				jqi.css({ position: "absolute"});
			}
		
			jqi.css({top: "50%", left: "50%", display: "none", zIndex: o.zindex, marginLeft: ((((div.css("paddingLeft").split("px")[0]*1) + div.width())/2)*-1), marginTop: (((div.height())/2)*-1) });
		}
		
		jqi.close = function(clicked,msg) {
			//jqi.remove();
			jqi.hide();
			if (hasFade) { 
				jqif.fadeOut(o.overlayspeed,function(){
					//jqif.remove();
					if(ie6) b.css({ overflow: "auto" });//ie6
					o.callback(clicked,msg);
				});
			}
		}
		
		jQuery('#'+ o.prefix +'buttons').children('button').click(function(){ 
			var msg = jqi.children('.'+ o.prefix +'container').children('.'+ o.prefix +'message');
			var clicked = o.buttons[jQuery(this).text()];	
			if(o.submit(clicked,msg)){		
				jqi.close(clicked,msg);
			}
		});
		
		//jqif.fadeIn(o.overlayspeed);
		//jqi[o.show](o.promptspeed,function(){o.loaded(jqi)});
		
		return jqi;
	}	
});
$.getScrollOffset = function(){
  	var x,y;
	if (self.pageYOffset) // all except Explorer
	{
		x = self.pageXOffset;
		y = self.pageYOffset;
	}
	else if (document.documentElement && document.documentElement.scrollTop)
		// Explorer 6 Strict
	{
		x = document.documentElement.scrollLeft;
		y = document.documentElement.scrollTop;
	}
	else if (document.body) // all other Explorers
	{
		x = document.body.scrollLeft;
		y = document.body.scrollTop;
	}
	return [x,y];
}

// Form Validating
$.validator.addMethod("match", function(value, message, params) {
        eval("reg = " + params);
        if (!value) return true;
        return reg.test(value);
    },"Regexp Error");

$.validator.addMethod("airport", function(value, message, param) {
        var input = $(this.lastElement);
        var inputAirportId = $('#'+input.attr('id')+'-airport-id');
        if (!value) {
            inputAirportId.val('');
            return true;
        }
        
        var airportId = inputAirportId.val();
        
        if (Global.airports[airportId] == value) {
            return true;
        }
        else {
            if (Global.airportsValidateCache[value] !== undefined) {
                return Global.airportsValidateCache[value];
            }
        
            //input.remote( + value);
            element = this.lastElement;
            
            if ( this.optional(element) )
                return true;
                
            var previous = this.previousValue(element);
            if ( previous.old !== value ) {
                previous.old = value;
                var validator = this;
                this.startRequest(element);
                var data = {};
                data[element.name] = value;
                jQuery.ajax({
                    url: param,
                    mode: "abort",
                    port: "validate" + element.name,
                    dataType: "json",
                    data: data,
                    success: function(response) {
                        Global.airportsValidateCache[value] = (response) ? true : false;
                        if ( !response ) {
                            input.attr('wrong', 'on');
                            var errors = {};
                            errors[element.name] =  response || validator.defaultMessage( element, "airport" );
                            validator.showErrors(errors);
                        } else {
                            var submitted = validator.formSubmitted;
                            validator.prepareElement(element);
                            validator.formSubmitted = submitted;
                            validator.successList.push(element);
                            validator.showErrors();
                            inputAirportId.val(response);
                            Global.airports[response] = value;
                            input.attr('wrong', '');
                        }
                        previous.valid = response;
                        validator.stopRequest(element, response);
                    }
                });
                return true;
            } else if( this.pending[element.name] ) {
                return true;
            }
            return previous.valid;              
        }
    },"Invalid Airport");

FormValidate = function(options) {
    
    this.form = $('#'+options.formId);
    if (!this.form.length) {
        alert('Validation form not found');
    }
    this.elements = {};
    this.requireElements = options.requireElements || {}
    this.rules = options.defaultRules || {};
    this.messages = options.defaultMessages || {};
    this.validated = {};
    this.views = options.views || {};
    this.formValues = this.form.getFormValues(true, true);
    this.errorMessages = options.errorMessages || {};
    this.jsrules = options.jsrules;
    this.examples = options.examples || {};
    
    this.prompt = null;
    
    //this.sumbitHandler = options.sumbitHandler;
    for(var name in this.examples) {
        if (!this.errorMessages[name]) {
            this.toExternal(name);
        }
    }
    
    // set tabIndex
    if (window.Global) { 
        if (Global.tabIndex) {
            var elements = this.form.get(0).elements;
            this.elementsDOM = elements;
            
            if (elements.length > 0) {
                for (var i = 0; i < elements.length; i++) {
                    elements[i].tabIndex = Global.tabIndex++;
                }
            }
        }
    }

    this.init();
    
    var th = this;
    
    var errorPlacement = function(error, element) {
        var errorBlock = th.getErrorBlock(element);
        error.appendTo($('#' + element.attr('id') + '-errorBlock > .inner'));
    };

    this.validator = this.form.validate({
        rules: this.rules,
        messages: this.messages,
        errorPlacement: errorPlacement,
        errorClass: "error",
        success : "success",
        onsubmit: false,
        onkeyup : false,
        onfocusout : false,
        onkeypress : false
    });
    
    this.validator.showErrors(this.errorMessages);
    
    for (name in this.errorMessages) {
        var input = this.getElement(name);
        input.focus();
        var error = this.getErrorBlock(input);
        error.show();
        break;
    }
    
    /*for(var name in this.views) {
        var input = this.getElement(name);
        if (!this.errorMessages[name]) {
            input.val(this.callbackView(name));
        }
    }*/
}

FormValidate.prototype = {
    pendings: 0,
    
    init: function() {
    
        for(var field in this.formValues) {
            var input = this.getElement(field);
            
            if (this.errorMessages[field]) {
                input.attr('wrong', 'on');
            }
            else {
                input.attr('wrong', '');
            }
        }
        
        for(var field in this.jsrules) {
            
            var input = this.getElement(field);

            var frules = this.jsrules[field];
            
            if (!this.rules[field]){
                this.rules[field] = {};
            }
            
            this.messages[field] = {};
            for(var ruleName in frules) {
                var rule = frules[ruleName];
                this.rules[field][ruleName] = rule.value;
                
                if (rule.message.type == "string") {
                    this.messages[field][ruleName] = rule.message.value;
                }
                else {
                    this.messages[field][ruleName] = eval(rule.message.value);
                }
            }
        }
        
        var object = this;
        
        var onfocusin = function(event) {
            
            var input = jQuery(this);
            var name = input.attr('name');
            object.toInternal(name);
            
            if (!object.rules[name] && !object.errorMessages[name]) {
                return true;
            }
            
            var error = object.getErrorBlock(input);
            
            if (input.attr('wrong') == 'on') {
                
                if (input.attr('jqac') == 'on') {
                    //input.keyup();
                }
            
                input.removeClass('error');
                error.show();
            }
        };
        
        var onfocusout = function(event){
            var input = jQuery(this);
            var name = input.attr('name');
            
            if (input.attr('suggest_menu') == 'on') return true;
            if (!object.rules[name]) {
                object.toExternal(name);
                return true;
            }
            
            var error = object.getErrorBlock(input);
            error.hide();
            if (input.attr('wrong') == 'on') {
                input.addClass('error');
                if ((object.rules[name]['required'] && input.val() == '' && object.examples[name])) {
                   input.removeClass('error');
                   object.toExternal(name);     
                }
                //object.toExternal(name);
                return true;
            }
            
            
            if(object.validator.element(input)) {
                input.attr('wrong', '');
                object.toExternal(name);         
            } 
            else {
                input.attr('wrong', 'on');
                if ((object.rules[name]['required'] && input.val() == '' && object.examples[name])) {
                    input.removeClass('error');
                    object.toExternal(name);     
                }
            }
            if (object.focusoutTimer) {
                clearTimeout(object.focusoutTimer);
            }
            
        };
        
        var onkeyup = function(event) {
            var input = jQuery(this);
            
            var error = object.getErrorBlock(input);
            
            if (input.attr('wrong') == 'on') {
                if (object.validator.element(input)) {
                    input.attr('wrong', '');
                    error.hide();
                }
                else {
                    input.removeClass('error');
                    error.show();
                }
            }   
        };
        
        var onchange = function(event) {
            var input = jQuery(this);
            if (input.attr('suggest_menu') == 'on') return true;
            var error = object.getErrorBlock(input);
               
            if (object.validator.element(input))
            {
                input.attr('wrong', '');
                error.hide();
            } 
            else {
                input.attr('wrong', 'on');
                /*if (input.attr('tagName').toLowerCase() == 'select') {
                    error.show();
                }*/
            }            
        };
        
        //this.form.delegate("focusin", ":text, :password, :file, select, textarea", onfocusin);
        $('input:text,input:file,input:password,select,textarea', this.form).focus(onfocusin);
        //this.form.delegate("focusout", ":text, :password, :file, select, textarea", onfocusout);
        $('input:text,input:file,input:password,select,textarea', this.form).blur(onfocusout);
        this.form.delegate("keyup", ":text, :password, :file, select, textarea", onkeyup);
        $('input:text,input:file,input:password,select,textarea', this.form).change(onchange);
        
    },

    getValues: function() {
        var values = this.form.getFormValues(true, true);
        for (key in values) {
            if (this.hasView(key))
                values[key] = this.formValues[key];
            if (this.examples[key] && values[key] == this.examples[key] ) {
                values[key] = '';
            }    
        }
        return values;
    },
    
    hasView: function(name) {
        return (this.views[name]) ? true : false;
    },
    
    getView: function(name) {
        if (this.hasView(name)) {
            return this.views[name];
        }
        else {
            return null;
        }
    },
    
    callbackView: function(name, value) {
        var view = this.getView(name);
        var input = this.getElement(name);
        if (!view){ 
            return input.val();
        }
        if (!value) {
            value = input.val();
        }
        result = view.call(this, value);
        return result;
    },
    
    setView: function(name, callback) {
        this.views[name] = callback;
        input = $('[name="'+ name +'"]', this.form);
        if (input.val()) {
            input.val(this.callbackView(name, input.val()));
        }
    },
    
    /**
     * @param string name|| jQuery Object input Element
     */
    getErrorBlock: function(name) {
        var input = name;
        if (typeof(name) === 'string') {
            input = this.getElement(name);
        }
        var errorId = input.attr('id') + '-errorBlock';
        var error = $('#' + errorId, this.form);
        if (error.length == 0) {
          input.after('<div id="' + input.attr('id') + '-errorBlock" style="display: none;" class="errorBlock"><div class="arrow"></div><div class="inner form_element_error"></div></div>');
          error = $('#' + errorId);
        }
        
        return error;
    },

    getRequiredErrorBlock: function(message) {
        var el = $('<div style="display:none"><div class="errorRequiredBlock"><div class="inner form_element_error errorRequiredBlock"><label class="error errorRequiredBlock">'+   message +'</label></div></div></div>');
        this.form.after(el);
        return el;
    },
    
    getElement: function(name) {
        if (this.elements[name]) {
            return this.elements[name];
        }
        else {
            var input = $('[name="'+ name +'"]', this.form);
            return this.elements[name] = input;
        }
    },
    
    toInternal: function(name) {
        var input = this.getElement(name);
        var value = input.val();
        
        if (this.examples[name]) {
            var exValue = this.examples[name];
            if (this.hasView(name)) {
                exValue = this.callbackView(name, exValue);
            }
            if (value == exValue) {
                input.val('');
                input.removeClass('example'); 
            }
        }
        if (this.hasView(name) && input.attr('wrong') != 'on') {
            input.val(this.formValues[name]);
        }
    },

    toExternal: function(name) {
        var input = this.getElement(name);
        
        input.removeClass('example');
        
        var value = input.val();
        if (this.examples[name]) {
            var input = this.getElement(name); 
            if (value == '') {
                var exValue = this.examples[name];
                if (this.hasView(name)) {
                    exValue = this.callbackView(name, exValue);
                }
                input.val(exValue);
                input.addClass('example');
            }
        }
        if (this.hasView(name) && input.attr('wrong') != 'on') {
            this.formValues[name] = value;
            if (value != '') {
                input.val(this.callbackView(name, value));
            }
        }        
    },
    
    check: function(el) {
        var input = $(el);
        var name = el.attr('name');
        if(this.validator.element(input)) {
            input.attr('wrong', '');
            return true;     
        } 
        else {
            input.attr('wrong', 'on');
            return false;
        }
    },
    
    validate: function()
    {
        var th = this;
        var invalid = false;
        
        $.each(this.formValues, function(key, value) {
            if (!th.rules[key]) return;
            var input = $('[name="'+ key +'"]', th.form);
            
            if (!input.enabled()) {
                return true;
            }
            
            th.toInternal(key);
            
            if (th.validator.element(input)) {
                input.attr('wrong', '');
                th.toExternal(key);
            }
            else {
                input.attr('wrong', 'on');
                if (!invalid) {
                    invalid = input;
                }
            }
        });
        var resultRequired = true;
        if (!invalid && this.requireElements.elements && this.requireElements.elements.length > 0) {
            var values = this.getValues(); 
            resultRequired = false;
            
            for (id in this.requireElements.elements) {
                var key = this.requireElements.elements[id];
                var input = $('[name="'+ key +'"]', this.form);
                
                if (!input.enabled()) {
                    continue;
                }
                if (values[key].length > 0) {
                    resultRequired = true;
                    break;
                }
            }
        }
        
        if (!invalid && resultRequired) {
            return true;
        }
        else if (invalid) {
            invalid.focus();
            return false;    
        }
        else {
            if (!this.prompt) {
                var message = this.requireElements.message || 'One of fields is required';
                
                var el = this.getRequiredErrorBlock(message);
                
                var promptParams = {
                    container: this.form.parent().parent(),
                    zindex: 900,
                    opacity: 0,
                    bothPosition: false,
                    prefix: 'errorRequired',
                    loaded: function(jqi) {
                    },
                    iframesrc: ''
                };
                
                var prompt = $.prompt(el.html(), promptParams);
                
                el.remove();
                
                if (jQuery.browser.msie) {
                    var b = $(promptParams.container);
                    prompt.ieClickHack = b.prepend('<div id="'+ promptParams.prefix +'fix"></div>').children('#'+ promptParams.prefix + 'fix');
                    prompt.ieClickHack.css({ backgroundColor: '#fff', opacity: 0, height: b.height(), width: "100%", position: "absolute", top: 0, left: 0, right: 0, bottom: 0, zIndex: promptParams.zindex - 1, display: "none" });
                    prompt.fade.css({ zIndex: promptParams.zindex - 2 });
                    
                    prompt.ieClickHack.click(function() {
                        prompt.ieClickHack.hide();
                        prompt.close();
                    });
                }
                
                prompt.click(function() {
                    if (jQuery.browser.msie) {
                        prompt.ieClickHack.hide();
                    }
                    prompt.close();
                });
                prompt.fade.click(function() {
                    if (jQuery.browser.msie) {
                        prompt.ieClickHack.hide();
                    }
                    prompt.close();
                });
                
                this.prompt = prompt;
            }
            
            if (jQuery.browser.msie) {
                this.prompt.ieClickHack.show();
            }
            this.prompt.open();
            
            return false;
        }
        
        return false;
    }
}

Global = {
    tabIndex: 100,
    airports: {},
    airportsSearchCache: {},
    airportsValidateCache: {},
    configurationWindow : null,
    unitsWindow : null,
    countryWindow : null,
    subscriptionConfirmationWindow : null,
    subscriptionConfirmationResendWindow: null,
    mutex: false,
    showUnits : function() {
        if (this.mutex) {
            return;
        }                
        this.mutex = true;
                
        if (this.unitsWindow) {
            this.unitsWindow.open();
        }
    },
    
    closeUnits : function() {
        if (this.unitsWindow) {
            this.unitsWindow.close();
        }
        
        this.mutex = false;
    },
    
    showCountry : function(siteId, sitePath, siteTitle) {
        if (this.countryWindow) {
            this.countryWindow.siteId = siteId;
            this.countryWindow.sitePath = sitePath;
            this.countryWindow.siteTitle = siteTitle;
            this.countryWindow.open();
            this.countryWindow.message = Global.countryWindow.messages[siteId];
            $("#settings_redirect_to_national_site").html(Global.countryWindow.messages[siteId]);
        }
    },
        
    enableTabLocker: function(startElement, endElement, enable) {
        var tabLocker = function(ev) {
            if (ev.keyCode == 9){
	            startElement.focus();
	            ev.cancelBubble = true;
	            return false;
            }
        };
    
        if (enable !== false) {
            $(endElement).bind('keydown', tabLocker);
        }
        else {
            $(endElement).unbind('keydown', tabLocker);
        }
    },
    
    airport_callback: function(obj) {
		Global.airports[obj.id] = obj.value;
		$('#'+$(this).attr('id')+'-airport-id').val(obj.id);
		$(this).change();
    },
    
    airport_search: function(value, callback) {
    	if (Global.airportsSearchCache[value]) {
    		callback.call(window, Global.airportsSearchCache[value]);
    		return;
    	} 
   		$.getJSON('/airports.php?action=search',{q: value}, function(data){
   			var res = [];
   			for (id in data) {
   				res.push({id: id, value: data[id]});
   			}
   			Global.airportsSearchCache[value] = res;
   			callback.call(window, res);
   		});
   	}
}

function hint(on, id, text) {
    var e = document.getElementById(id);
    var str = text;
    if (on && (e.value == ''))
        e.value = str;
    else if (!on && (e.value == str))
        e.value = ''
}

Rotator = function(options) {
    this.items = options.items;
    this.pointer = 0;
    this.image = document.getElementById(options.imgId);
    this.href = document.getElementById(options.hrefId);
}
Rotator.prototype = {
    show : function() {
        var th = this;
        if (th.items.length > 0) {
            /*if( !th.image ) {
                var img = $('<img id="rotator-image" src="'+th.items[th.pointer].image+'" width="247" height="217" alt="" />');
                img.appendTo($(th));
                th.image = img;
            }*/
            $(th.image).fadeOut("slow", function() {
                th.image.src = th.items[th.pointer].image;
                th.href.href = th.items[th.pointer].url;
                th.href.target = (th.items[th.pointer].target == 1) ? "_blank" : "";    
                $(th.image).fadeIn("slow");
            });
        }
    },
    next: function() {
        this.pointer++;
        if (this.pointer > this.items.length - 1) {
            this.pointer = 0;
        }
        this.show();
    },
    previous: function() {
        this.pointer--;
        if (this.pointer < 0) {
            this.pointer = this.items.length - 1;
        }
        this.show();
    }     
}

function openPopup(url, width, height, resizable) {
    if (typeof(width) == "undefined") {
        height = 700;
    }
    if (typeof(height) == "undefined") {
        height = 300;
    }
    self.name = "opener";
    remote = open(url, "remote", "scrollbars=1,width="+width+",height=" + height + ",left=325,top=100,location=0,status=0,resizable=" + resizable);
}

/**
* JQuery get form values plugin
*/
$.fn.getFormValues = function(assoc, includeDisabled)
{
   var a = assoc ? {} : [];
   $('input,textarea,select,button', this).each(function() {
       var n = this.name;
       var t = this.type;
       if ( !n || t == 'reset' ||
           (t == 'checkbox' || t == 'radio') && !this.checked ||
           (t == 'submit' || t == 'image' || t == 'button') && this.form.clicked != this ||
           this.tagName.toLowerCase() == 'select' && this.selectedIndex == -1)
           return;
	   if  (!includeDisabled && this.disabled) {
		   return;
	   }
       if (t == 'image' && this.form.clicked_x)
           return a.push(
               {name: n+'_x', value: this.form.clicked_x},
               {name: n+'_y', value: this.form.clicked_y}
           );
       if (t == 'select-multiple') {
           $('option:selected', this).each( function() {
               a.push({name: n, value: this.value});
           });
           return;
       }
       if (assoc) {
           a[n] = this.value;
       }
       else {
           a.push({name: n, value: this.value});
       }
   });
   return a;
};

$.fn.enabled = function(enable)
{
    if (typeof(enable) != 'boolean') {
        return !this.attr('disabled');
    }
    
    this.attr('disabled', !enable);
    
    return this;
};

$.fn.switcher = function(objects, reverse, checkValueCallback, eventType, enableCallback)
{
    var th = this;
    
    if (typeof(eventType) != 'string') {
        eventType = 'change keyup';
    }
    
    if (typeof(checkValueCallback) != 'function') {
        checkValueCallback = function()
        {
            var value = true;
            
            this.each(function() {
                if (!value) {
                    return;
                }
                value = !$(this).val().match(/\S+/);
            });
            
            return value;
        };
    }
    
    var switcher = function()
    {
        enable = checkValueCallback.call(th);
        objects.enabled(enable);
        
        if (typeof(enableCallback) == 'function') {
            enableCallback.call(this, objects, enable);
        }
    };
    this.bind(eventType, switcher);
    switcher.call(this);
    
    if (reverse) {
        switcher = function()
        {
            enable = checkValueCallback.call(objects);
            th.enabled(enable);
            
            if (typeof(enableCallback) == 'function') {
                enableCallback.call(objects, this, enable);
            }
        };
        objects.bind(eventType, switcher);
        switcher.call(this);
    }
    
    return this;
};

THOUSANDS_SEPARATOR = ',';

function formatNumber(num, dec)
{
    if (typeof(dec) == 'undefined') {
        dec = 2;
    }
    if (dec) {
        var result = decRound(num, dec);
        var right = String(result).match(/\d+(\.\d+)?/)[1];
        if (!right) {
            right = '.';
        }
        while (right.length - 1 < dec) {
            right += '0';
        }
        result = String(result).replace(/(\.\d+)?$/, right);
    }
    else {
        var result = Math.round(num);
    }
    // Thousands
    if (THOUSANDS_SEPARATOR) {
        var left = String(result).match(/(\d+)(\.\d+)?/)[1];
        var newLeft = '';
        var s = left.length - 1;
        for (var i = s, k = 0; i >= 0; i--) {
            if (k++ % 3 == 0 && i < s) {
                newLeft = THOUSANDS_SEPARATOR + newLeft;
            }
            newLeft = left.charAt(i) + newLeft;
        }
        result = String(result).replace(/^(\d+)/, newLeft);
    }
    
    return result;
}

function decRound(num, dec)
{
    return Math.round(num * Math.pow(10, dec)) / Math.pow(10, dec);
}

// Map class
var Map = function()
{
    // Map object constructor function
    var constructor = function(mapId)
    {
        this.id = mapId;
        this.data = document.getElementById(this.id);
        constructor.maps[this.id] = this;
    }
    // Map initialization function
    constructor.init = function(mapId, editable)
    {
        var initMap = Map.maps[mapId];
        
        initMap.map = new GMap2(document.getElementById(initMap.id + '_id_map'));
        initMap.map.setCenter(new GLatLng(Map.defaultLatitude, Map.defaultLongitude), Map.defaultZoom);
        initMap.map.addControl(new GLargeMapControl());
        initMap.map.addControl(new GMapTypeControl());
        
        if (editable) {
            initMap.enableEditable(true);
        }
        
        if (initMap.data.value) {
            initMap.setLocations(initMap.data.value);
        }
    };
    //
    constructor.goTo = function(mapId, address)
    {
        if (Map.gClientGeocoder == null) {
            Map.gClientGeocoder = new GClientGeocoder();
        }
        
        Map.gClientGeocoder.getLatLng(address, function(c)
        {
            if (c !== null) {
                Map.maps[mapId].map.panTo(c);
            }
        })
    };
    
    //
    constructor.saveData = function()
    {
        for (map in Map.maps) {
            Map.maps[map].saveData();
        }
    }
    
    // Global collection of Map instances
    constructor.maps = {};
    // Global GClientGeocoder used fo Map.goTo function
    constructor.gClientGeocoder = null;
    // Default settings for maps (England)
    constructor.defaultLatitude = 51.781435604431195;
    constructor.defaultLongitude = -1.6259765625;
    constructor.defaultZoom = 6;
    
    return constructor;
}();

// Map object definition
Map.prototype = function()
{
    return {
        // Array of Map object locations
        'editable' : false,
        'locations' : [],
        
        // Map.init method wrapper
        'init' : function(editable)
        {
            Map.init(this.id, editable);
        },
        // Map.goTo method wrapper
        'goTo' : function(address)
        {
            Map.goTo(this.id, address);
        },
        //
        'mapClick' : function(point)
        {
            if (point)
            {
                if (!this.hasLocations()) {
                    this.openMarkerInfoWindow(this.addLocation(point));
                }
            }
        },
        //
        'enableEditable' : function(editable)
        {
            if (editable) {
                this.editable = true;
                var th = this;
                GEvent.addListener(this.map, 'click', function(layer, point)
                {
                    th.mapClick(point);
                });
            }
        },
        'hasLocations' : function()
        {
            return this.locations.length > 0;  
        },
        //
        'createMarker' : function(locationId)
        {
            var th = this;
            var location = this.locations[locationId];
            
            // TODO rewrite to types
            var marker = new GMarker(new GLatLng(location.points[0].latitude, location.points[0].longitude), {draggable: this.editable});
            
            GEvent.addListener(marker, 'click', function()
            {
                th.openMarkerInfoWindow(locationId);
                /*setTimeout(function()
                {
                    $('#marker-' + id + ' textarea')
                        .val(marker.text)
                        .focus();
                }, 100);*/
            });
            
            GEvent.addListener(marker, 'dragstart', function()
            {
                  th.closeMarkerInfoWindow(locationId);
            });
            
            if (this.editable) {
	            GEvent.addListener(marker, 'dragend', function()
	            {
	                  th.refreshLocationData(locationId);
	            });
            }
            
            location.marker = marker;
            
            return marker;
        },
        //
        'refreshLocationData' : function(locationId)
        {
            this.locations[locationId].points[0].latitude = this.locations[locationId].marker.getLatLng().lat();
            this.locations[locationId].points[0].longitude = this.locations[locationId].marker.getLatLng().lng();
        },
        //
        'openMarkerInfoWindow' : function(locationId)
        {
            if (this.editable) {
                return;
            }
            
            var html = '';
            if (this.editable) {
                html += '<textarea id="map_' + this.id + '_marker_' + locationId + '">';
            }
            html += this.locations[locationId].text;
            if (this.editable) {
                html += '</textarea><br /><input type="button" value="save" onclick="Map.maps[\'' + this.id + '\'].updateMarkerText(\'' + locationId + '\')" />';
            }
            
            this.locations[locationId].marker.openInfoWindow(html, { maxWidth: 300 });
        },
        //
        'updateMarkerText' : function(locationId)
        {
            this.locations[locationId].text = document.getElementById('map_' + this.id + '_marker_' + locationId).value;
            this.closeMarkerInfoWindow(locationId);
        },
        //
        'closeMarkerInfoWindow' : function(locationId)
        {
            this.locations[locationId].marker.closeInfoWindow();
        },
        //
        'addLocation' : function(point)
        {
            var locationId = this.locations.push({
                'text' : '',
                'points' : [
                    {
                        'latitude' : point.lat(),
                        'longitude' : point.lng()
                    }
                ]
            }) - 1;
            this.locations[locationId].marker = this.createMarker(locationId);
            
            this.map.addOverlay(this.locations[locationId].marker);
            
            return locationId;
        },
        //
        'initLocations' : function()
        {
	        var b = new GLatLngBounds();
            for (var locationId in this.locations) {
                this.locations[locationId].marker = this.createMarker(locationId);
                this.map.addOverlay(this.locations[locationId].marker);
                b.extend(new GLatLng(this.locations[locationId].points[0].latitude, this.locations[locationId].points[0].longitude));
            }
	        if (!b.isEmpty()) {
	            var level = this.locations.length > 1 ? this.map.getBoundsZoomLevel(b) : 5;
	            this.map.setCenter(b.getCenter(), level);
	        }
        },
        //
        'setLocations' : function(locations)
        {
            this.locations = JSON.parse(locations);
            this.initLocations();
        },
        //
        'exportLocations' : function()
        {
            var locations = this.locations;
            for (var locationId in locations) {
                delete locations[locationId].marker;
            }
            return JSON.stringify(locations);
        },
        //
        'saveData' : function()
        {
            this.data.value = this.exportLocations();
        }
    }
}();

// Project map class
var ProjectMap = {
    
    markers : [],
    countMarkers : 0,

    init : function(edit)
    {
        if (typeof edit == 'undefined') {
            edit = true;
        }
        
        // Load pam
        Map.load('project-map');
        
        if (edit) {
            // Bind country dropdown change to change map coordinates
            $('select[@name="f[country]"]').change(function()
            {
                if (ProjectMap.countMarkers == 0) {
                    Map.goTo($(this).find('option:selected').html());
                }
            });
            // Bind map right click to create new marker
            GEvent.addListener(Map.m, 'singlerightclick', function(point, src)
            {
                var center = Map.m.fromContainerPixelToLatLng(point);
                ProjectMap.createMarker(center);
            });
        }
    },
    
    createMarker : function(center, text)
    {
        // Create marker instance
        var id = ProjectMap.markers.length;
        ProjectMap.markers[id] = new GMarker(center, {draggable: true});
        var marker = ProjectMap.markers[id];
        
        // Initialize info text
        marker.text = text || '';
        
        // Initialize info window html
        var html = '<div class="markerInfo" id="marker-' + id + '">' +
                   'Marker Info:<br />' +
                   '<textarea name="info"></textarea><br />' +
                   '<input type="button" onclick="ProjectMap.saveMarkerInfo(' + id + ')" value="Save" />' +
                   '<input type="button" onclick="ProjectMap.removeMarker(' + id + ')" value="Delete" />' +
                   '</div>';
        
        // Initialize click handler callback
        var markerClick = function()
        {
            marker.openInfoWindow(html);
            setTimeout(function()
            {
                $('#marker-' + id + ' textarea')
                    .val(marker.text)
                    .focus();
            }, 100);
        };
        
        // Drag event initialization
        GEvent.addListener(marker, "dragstart", function()
        {
              Map.m.closeInfoWindow();
        });
        
        // Add click event to marker
        GEvent.addListener(marker, "click", markerClick);
        
        // Add marker to map
        Map.m.addOverlay(marker);
        
        // Show marker info window
        if (!text) {
            markerClick();
        }
        
        ProjectMap.countMarkers ++;
    },
    
    removeMarker : function(id)
    {
        Map.m.removeOverlay(ProjectMap.markers[id]);
        ProjectMap.markers[id] = null;
        ProjectMap.countMarkers --;
    },
    
    saveMarkerInfo : function(id)
    {
        ProjectMap.markers[id].text = $('#marker-' + id + ' textarea').val();
        Map.m.closeInfoWindow();
    },
    
    createHiddenData : function(form)
    {
        // Initialize
        var f = $(form);
        // Remove old markers
        $('input:hidden.marker', form).remove();
        // Add new markers
        for (var i = 0, k = 0; i < ProjectMap.markers.length; i ++) {
            if (ProjectMap.markers[i] !== null) {
                f.append($('<input type="hidden">').
                    attr('name', 'f[markers][' + k + '][text]').
                    addClass('marker').
                    val(ProjectMap.markers[i].text)
                );
                f.append($('<input type="hidden">').
                    attr('name', 'f[markers][' + k + '][lat]').
                    addClass('marker').
                    val(ProjectMap.markers[i].getLatLng().lat())
                );
                f.append($('<input type="hidden">').
                    attr('name', 'f[markers][' + k + '][lng]').
                    addClass('marker').
                    val(ProjectMap.markers[i].getLatLng().lng())
                );
                k ++;
            }
        }
        
        return true;
    },
    
    addMarkers : function(markers, edit)
    {
        if (typeof edit == 'undefined') {
            edit = true;
        }
        var bounds = new GLatLngBounds();
        for (var i in markers) { 
            // Initialize center
            var center = new GLatLng(markers[i]['lat'], markers[i]['lng']);
            // Add to bounds
            bounds.extend(center);
            // Add marker
            if (edit) {
                ProjectMap.createMarker(center, markers[i]['text']);
            }
            else {
	            // Create marker instance
	            var id = ProjectMap.markers.length;
	            ProjectMap.markers[id] = new GMarker(center);
	            var marker = ProjectMap.markers[id];
	            // Set text to marker
	            marker.text = markers[i]['text'];
	            
	            // Drag event initialization
	            GEvent.addListener(marker, "dragstart", function()
	            {
	                  Map.m.closeInfoWindow();
	            });
	            
	            // Add click event to marker
	            GEvent.addListener(marker, "click", (function(id)
	            {
	                return (function()
	                {
                        ProjectMap.highlightMarker(id);
                    });
	            })(id));
	             
	            // Add marker to map
	            Map.m.addOverlay(marker);
	            ProjectMap.countMarkers ++;
            }
        }
        // Centerize map to middle of bounds
        var zoom = ProjectMap.countMarkers > 1 ? Map.m.getBoundsZoomLevel(bounds) : 6;
        Map.m.setCenter(bounds.getCenter(), zoom);
    },
    
    highlightMarker : function(id)
    {
        var m = ProjectMap.markers[id];
        m.openInfoWindow('<div class="markerInfo">' + escapeHtml(m.text) + '</div>');
    }
}

function escapeHtml(str)
{
    return str.
        replace('&', '&amp;').
        replace('<', '&lt;').
        replace('>', '&gt;').
        replace('"', '&quot;');
}

if(!this.JSON){JSON=function(){function f(n){return n<10?'0'+n:n;}Date.prototype.toJSON=function(){return this.getUTCFullYear()+'-'+f(this.getUTCMonth()+1)+'-'+f(this.getUTCDate())+'T'+f(this.getUTCHours())+':'+f(this.getUTCMinutes())+':'+f(this.getUTCSeconds())+'Z';};var m={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'};function stringify(value,whitelist){var a,i,k,l,r=/["\\\x00-\x1f\x7f-\x9f]/g,v;switch(typeof value){case'string':return r.test(value)?'"'+value.replace(r,function(a){var c=m[a];if(c){return c;}c=a.charCodeAt();return'\\u00'+Math.floor(c/16).toString(16)+(c%16).toString(16);})+'"':'"'+value+'"';case'number':return isFinite(value)?String(value):'null';case'boolean':case'null':return String(value);case'object':if(!value){return'null';}if(typeof value.toJSON==='function'){return stringify(value.toJSON());}a=[];if(typeof value.length==='number'&&!(value.propertyIsEnumerable('length'))){l=value.length;for(i=0;i<l;i+=1){a.push(stringify(value[i],whitelist)||'null');}return'['+a.join(',')+']';}if(whitelist){l=whitelist.length;for(i=0;i<l;i+=1){k=whitelist[i];if(typeof k==='string'){v=stringify(value[k],whitelist);if(v){a.push(stringify(k)+':'+v);}}}}else{for(k in value){if(typeof k==='string'){v=stringify(value[k],whitelist);if(v){a.push(stringify(k)+':'+v);}}}}return'{'+a.join(',')+'}';}}return{stringify:stringify,parse:function(text,filter){var j;function walk(k,v){var i,n;if(v&&typeof v==='object'){for(i in v){if(Object.prototype.hasOwnProperty.apply(v,[i])){n=walk(i,v[i]);if(n!==undefined){v[i]=n;}}}}return filter(k,v);}if(/^[\],:{}\s]*$/.test(text.replace(/\\./g,'@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').replace(/(?:^|:|,)(?:\s*\[)+/g,''))){j=eval('('+text+')');return typeof filter==='function'?walk('',j):j;}throw new SyntaxError('parseJSON');}};}();}

Widget = function (id, url)
{
	jQuery.ajaxSetup({
	    cache: true
	});

    Widget.pool[id] = this;
    this.id = id;
    this.document = document;
    this.load(url);
};

Widget.pool = {};

Widget.get = function (id)
{
    return Widget.pool[id];
}

Widget.prototype = {
    
    id: null,
    handlers: {},
    document: null,
    formValidator: null,
    calculationId: null,
    mutex: false,
    
    load: function (url, data, callback)
    {
        if (typeof(url) == 'undefined') {
            return false;
        }

    	if (this.mutex === true) {
    		return false;
    	}
    	this.mutex = true;
        
        if (url) {
            var mask = this.mask();
            var th = this;
            
            var mutexTimeout = setTimeout(function(){
            	if (th.mutex === true) {
		    		th.mutex = false;
		    	}
		    	clearTimeout(mutexTimeout);
            }, 5000);
            
	        return $('#' + this.id).load(url, data, function(responseText, textStatus, XMLHttpRequest){
	        	th.mutex = false;
				if (callback) {
				    callback.call(th, responseText, textStatus, XMLHttpRequest);
				 }
				 mask.remove();                   
              });
        }
        
        return false;
    },
    
    calculate: function (callback)
    {
        if (this.formValidator.validate()) {
        	var th = this;
        	var timeout = null;
        	var calculateFn = function() {
            	return th.load(th.formValidator.form.attr('action'), 
                	th.formValidator.getValues(), callback);
        	}
        	
        	if (this.formValidator.validator.pendingRequest === 0) {
        		return calculateFn.call(this);
            } else if (timeout == null) {
            	timeout = setTimeout( function() {
            		if (th.formValidator.validator.pendingRequest === 0) {
            			if (th.formValidator.validator.valid()) {
            				calculateFn.call(th);
            			}
            			else {
            				th.formValidator.validator.focusInvalid();
            			}
            			clearTimeout(timeout);
            		}
            	}, 100);
            }
        }
        
        return false;
    },
    
    handle: function (action, callback)
    {
        if (!this.handlers[action]) {
            this.handlers[action] = [];
        }
        this.handlers[action].push(callback);
    },
    
    trigger: function (action)
    {
        if (this.handlers[action]) {
            for (var i in this.handlers[action]) {
                this.handlers[action][i].call(this, action);
            }
        }
    },
    
    mask: function()
    {
        var container = $('#' + this.id);
        var div = $('<div></div>');
        var mask = $('<div class="ext-el-mask"></div>').appendTo(div);
        $($('#widget_loading_text').html()).appendTo(div);
        mask.css({opacity: 0.5, width: container.width(), height: container.height()});
        div.appendTo(container);
        return div;
    }
};