/*
 * jQuery 1.2.6 - 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-05-24 14:22:17 -0400 (Sat, 24 May 2008) $
 * $Rev: 5685 $
 */
(function(){var _jQuery=window.jQuery,_$=window.$;var jQuery=window.jQuery=window.$=function(selector,context){return new jQuery.fn.init(selector,context);};var quickExpr=/^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/,isSimple=/^.[^:#\[\.]*$/,undefined;jQuery.fn=jQuery.prototype={init:function(selector,context){selector=selector||document;if(selector.nodeType){this[0]=selector;this.length=1;return this;}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);return jQuery(elem);}selector=[];}}else
return jQuery(context).find(selector);}else if(jQuery.isFunction(selector))return jQuery(document)[jQuery.fn.ready?"ready":"load"](selector);return this.setArray(jQuery.makeArray(selector));},jquery:"1.2.6",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;return jQuery.inArray(elem&&elem.jquery?elem[0]:elem,this);},attr:function(name,value,type){var options=name;if(name.constructor==String)if(value===undefined)return this[0]&&jQuery[type||"attr"](this[0],name);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 this.pushStack(jQuery.unique(jQuery.merge(this.get(),typeof selector=='string'?jQuery(selector):jQuery.makeArray(selector))));},is:function(selector){return!!selector&&jQuery.multiFilter(selector,this).length>0;},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;}if(value.constructor==Number)value+='';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=jQuery.makeArray(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[0]?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===undefined){var data=this.triggerHandler("getData"+parts[1]+"!",[parts[0]]);if(data===undefined&&this.length)data=jQuery.data(this[0],key);return data===undefined&&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.fn.init.prototype=jQuery.fn;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);}function now(){return+new Date;}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==i){target=this;--i;}for(;i<length;i++)if((options=arguments[i])!=null)for(var name in options){var src=target[name],copy=options[name];if(target===copy)continue;if(deep&&copy&&typeof copy=="object"&&!copy.nodeType)target[name]=jQuery.extend(deep,src||(copy.length!=null?[]:{}),copy);else if(copy!==undefined)target[name]=copy;}return target;};var expando="jQuery"+now(),uuid=0,windowData={},exclude=/z-?index|font-?weight|opacity|zoom|line-?height/i,defaultView=document.defaultView||{};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&&/^[\s[]?function/.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.insertBefore(script,head.firstChild);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){var name,i=0,length=object.length;if(args){if(length==undefined){for(name in object)if(callback.apply(object[name],args)===false)break;}else
for(;i<length;)if(callback.apply(object[i++],args)===false)break;}else{if(length==undefined){for(name in object)if(callback.call(object[name],name,object[name])===false)break;}else
for(var value=object[0];i<length&&callback.call(value,i,value)!==false;value=object[++i]){}}return object;},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,style=elem.style;function color(elem){if(!jQuery.browser.safari)return false;var ret=defaultView.getComputedStyle(elem,null);return!ret||ret.getPropertyValue("color")=="";}if(name=="opacity"&&jQuery.browser.msie){ret=jQuery.attr(style,"opacity");return ret==""?"1":ret;}if(jQuery.browser.opera&&name=="display"){var save=style.outline;style.outline="0 solid black";style.outline=save;}if(name.match(/float/i))name=styleFloat;if(!force&&style&&style[name])ret=style[name];else if(defaultView.getComputedStyle){if(name.match(/float/i))name="float";name=name.replace(/([A-Z])/g,"-$1").toLowerCase();var computedStyle=defaultView.getComputedStyle(elem,null);if(computedStyle&&!color(elem))ret=computedStyle.getPropertyValue(name);else{var swap=[],stack=[],a=elem,i=0;for(;a&&color(a);a=a.parentNode)stack.unshift(a);for(;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":(computedStyle&&computedStyle.getPropertyValue(name))||"";for(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 left=style.left,rsLeft=elem.runtimeStyle.left;elem.runtimeStyle.left=elem.currentStyle.left;style.left=ret||0;ret=style.pixelLeft+"px";style.left=left;elem.runtimeStyle.left=rsLeft;}}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+='';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 notxml=!jQuery.isXMLDoc(elem),set=value!==undefined,msie=jQuery.browser.msie;name=notxml&&jQuery.props[name]||name;if(elem.tagName){var special=/href|src|style/.test(name);if(name=="selected"&&jQuery.browser.safari)elem.parentNode.selectedIndex;if(name in elem&&notxml&&!special){if(set){if(name=="type"&&jQuery.nodeName(elem,"input")&&elem.parentNode)throw"type property can't be changed";elem[name]=value;}if(jQuery.nodeName(elem,"form")&&elem.getAttributeNode(name))return elem.getAttributeNode(name).nodeValue;return elem[name];}if(msie&&notxml&&name=="style")return jQuery.attr(elem.style,"cssText",value);if(set)elem.setAttribute(name,""+value);var attr=msie&&notxml&&special?elem.getAttribute(name,2):elem.getAttribute(name);return attr===null?undefined:attr;}if(msie&&name=="opacity"){if(set){elem.zoom=1;elem.filter=(elem.filter||"").replace(/alpha\([^)]*\)/,"")+(parseInt(value)+''=="NaN"?"":"alpha(opacity="+value*100+")");}return elem.filter&&elem.filter.indexOf("opacity=")>=0?(parseFloat(elem.filter.match(/opacity=([^)]*)/)[1])/100)+'':"";}name=name.replace(/-([a-z])/ig,function(all,letter){return letter.toUpperCase();});if(set)elem[name]=value;return elem[name];},trim:function(text){return(text||"").replace(/^\s+|\s+$/g,"");},makeArray:function(array){var ret=[];if(array!=null){var i=array.length;if(i==null||array.split||array.setInterval||array.call)ret[0]=array;else
while(i)ret[--i]=array[i];}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){var i=0,elem,pos=first.length;if(jQuery.browser.msie){while(elem=second[i++])if(elem.nodeType!=8)first[pos++]=elem;}else
while(elem=second[i++])first[pos++]=elem;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))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)ret[ret.length]=value;}return ret.concat.apply([],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,readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing"}});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");};});function num(elem,prop){return elem[0]&&parseInt(jQuery.curCSS(elem[0],prop,true),10)||0;}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,re=quickChild,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=[],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&&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)elem=window;if(!handler.guid)handler.guid=this.guid++;if(data!=undefined){var fn=handler;handler=this.proxy(fn,function(){return fn.apply(this,arguments);});handler.data=data;}var events=jQuery.data(elem,"events")||jQuery.data(elem,"events",{}),handle=jQuery.data(elem,"handle")||jQuery.data(elem,"handle",function(){if(typeof jQuery!="undefined"&&!jQuery.event.triggered)return jQuery.event.handle.apply(arguments.callee.elem,arguments);});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({type:type,target:elem,preventDefault:function(){},stopPropagation:function(){},timeStamp:now()});data[0][expando]=true;}data[0].type=type;if(exclusive)data[0].exclusive=true;var handle=jQuery.data(elem,"handle");if(handle)val=handle.apply(elem,data);if((!fn||(jQuery.nodeName(elem,'a')&&type=="click"))&&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,ret,namespace,all,handlers;event=arguments[0]=jQuery.event.fix(event||window.event);namespace=event.type.split(".");event.type=namespace[0];namespace=namespace[1];all=!namespace&&!event.exclusive;handlers=(jQuery.data(this,"events")||{})[event.type];for(var j in handlers){var handler=handlers[j];if(all||handler.type==namespace){event.handler=handler;event.data=handler.data;ret=handler.apply(this,arguments);if(val!==false)val=ret;if(ret===false){event.preventDefault();event.stopPropagation();}}}return val;},fix:function(event){if(event[expando]==true)return event;var originalEvent=event;event={originalEvent:originalEvent};var props="altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target timeStamp toElement type view wheelDelta which".split(" ");for(var i=props.length;i;i--)event[props[i]]=originalEvent[props[i]];event[expando]=true;event.preventDefault=function(){if(originalEvent.preventDefault)originalEvent.preventDefault();originalEvent.returnValue=false;};event.stopPropagation=function(){if(originalEvent.stopPropagation)originalEvent.stopPropagation();originalEvent.cancelBubble=true;};event.timeStamp=event.timeStamp||now();if(!event.target)event.target=event.srcElement||document;if(event.target.nodeType==3)event.target=event.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;},proxy:function(fn,proxy){proxy.guid=fn.guid=fn.guid||proxy.guid||this.guid++;return proxy;},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;event.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;event.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){var one=jQuery.event.proxy(fn||data,function(event){jQuery(this).unbind(event,one);return(fn||data).apply(this,arguments);});return this.each(function(){jQuery.event.add(this,type,one,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){return this[0]&&jQuery.event.trigger(type,data,this[0],false,fn);},toggle:function(fn){var args=arguments,i=1;while(i<args.length)jQuery.event.proxy(fn,args[i++]);return this.click(jQuery.event.proxy(fn,function(event){this.lastToggle=(this.lastToggle||0)%i;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.call(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:jQuery.fn.load,load:function(url,params,callback){if(typeof url!='string')return this._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=now();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:{url:location.href,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){s=jQuery.extend(true,s,jQuery.extend(true,{},jQuery.ajaxSettings,s));var jsonp,jsre=/=\?(&|$)/g,status,data,type=s.type.toUpperCase();if(s.data&&s.processData&&typeof s.data!="string")s.data=jQuery.param(s.data);if(s.dataType=="jsonp"){if(type=="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&&type=="GET"){var ts=now();var ret=s.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+ts+"$2");s.url=ret+((ret==s.url)?(s.url.match(/\?/)?"&":"?")+"_="+ts:"");}if(s.data&&type=="GET"){s.url+=(s.url.match(/\?/)?"&":"?")+s.data;s.data=null;}if(s.global&&!jQuery.active++)jQuery.event.trigger("ajaxStart");var remote=/^(?:\w+:)?\/\/([^\/?#]+)/;if(s.dataType=="script"&&type=="GET"&&remote.test(s.url)&&remote.exec(s.url)[1]!=location.host){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 xhr=window.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest();if(s.username)xhr.open(type,s.url,s.async,s.username,s.password);else
xhr.open(type,s.url,s.async);try{if(s.data)xhr.setRequestHeader("Content-Type",s.contentType);if(s.ifModified)xhr.setRequestHeader("If-Modified-Since",jQuery.lastModified[s.url]||"Thu, 01 Jan 1970 00:00:00 GMT");xhr.setRequestHeader("X-Requested-With","XMLHttpRequest");xhr.setRequestHeader("Accept",s.dataType&&s.accepts[s.dataType]?s.accepts[s.dataType]+", */*":s.accepts._default);}catch(e){}if(s.beforeSend&&s.beforeSend(xhr,s)===false){s.global&&jQuery.active--;xhr.abort();return false;}if(s.global)jQuery.event.trigger("ajaxSend",[xhr,s]);var onreadystatechange=function(isTimeout){if(!requestDone&&xhr&&(xhr.readyState==4||isTimeout=="timeout")){requestDone=true;if(ival){clearInterval(ival);ival=null;}status=isTimeout=="timeout"&&"timeout"||!jQuery.httpSuccess(xhr)&&"error"||s.ifModified&&jQuery.httpNotModified(xhr,s.url)&&"notmodified"||"success";if(status=="success"){try{data=jQuery.httpData(xhr,s.dataType,s.dataFilter);}catch(e){status="parsererror";}}if(status=="success"){var modRes;try{modRes=xhr.getResponseHeader("Last-Modified");}catch(e){}if(s.ifModified&&modRes)jQuery.lastModified[s.url]=modRes;if(!jsonp)success();}else
jQuery.handleError(s,xhr,status);complete();if(s.async)xhr=null;}};if(s.async){var ival=setInterval(onreadystatechange,13);if(s.timeout>0)setTimeout(function(){if(xhr){xhr.abort();if(!requestDone)onreadystatechange("timeout");}},s.timeout);}try{xhr.send(s.data);}catch(e){jQuery.handleError(s,xhr,null,e);}if(!s.async)onreadystatechange();function success(){if(s.success)s.success(data,status);if(s.global)jQuery.event.trigger("ajaxSuccess",[xhr,s]);}function complete(){if(s.complete)s.complete(xhr,status);if(s.global)jQuery.event.trigger("ajaxComplete",[xhr,s]);if(s.global&&!--jQuery.active)jQuery.event.trigger("ajaxStop");}return xhr;},handleError:function(s,xhr,status,e){if(s.error)s.error(xhr,status,e);if(s.global)jQuery.event.trigger("ajaxError",[xhr,s,e]);},active:0,httpSuccess:function(xhr){try{return!xhr.status&&location.protocol=="file:"||(xhr.status>=200&&xhr.status<300)||xhr.status==304||xhr.status==1223||jQuery.browser.safari&&xhr.status==undefined;}catch(e){}return false;},httpNotModified:function(xhr,url){try{var xhrRes=xhr.getResponseHeader("Last-Modified");return xhr.status==304||xhrRes==jQuery.lastModified[url]||jQuery.browser.safari&&xhr.status==undefined;}catch(e){}return false;},httpData:function(xhr,type,filter){var ct=xhr.getResponseHeader("content-type"),xml=type=="xml"||!type&&ct&&ct.indexOf("xml")>=0,data=xml?xhr.responseXML:xhr.responseText;if(xml&&data.documentElement.tagName=="parsererror")throw"parsererror";if(filter)data=filter(data,type);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(jQuery.isFunction(a[j])?a[j]():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.apply(this,arguments):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),p,hidden=jQuery(this).is(":hidden"),self=this;for(p in prop){if(prop[p]=="hide"&&hidden||prop[p]=="show"&&!hidden)return opt.complete.call(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.call(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){type=type||"fx";var q=jQuery.data(elem,type+"queue");if(!q||array)q=jQuery.data(elem,type+"queue",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].call(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:jQuery.fx.speeds[opt.duration])||jQuery.fx.speeds.def;opt.old=opt.complete;opt.complete=function(){if(opt.queue!==false)jQuery(this).dequeue();if(jQuery.isFunction(opt.old))opt.old.call(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.call(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=now();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=now();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)this.options.complete.call(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.extend(jQuery.fx,{speeds:{slow:600,fast:200,def:400},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),css=jQuery.curCSS,fixed=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&&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(css(parent,"display")))add(-parent.scrollLeft,-parent.scrollTop);if(mozilla&&css(parent,"overflow")!="visible")border(parent);parent=parent.parentNode;}if((safari2&&(fixed||css(offsetChild,"position")=="absolute"))||(mozilla&&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,10)||0;top+=parseInt(t,10)||0;}return results;};jQuery.fn.extend({position:function(){var left=0,top=0,results;if(this[0]){var offsetParent=this.offsetParent(),offset=this.offset(),parentOffset=/^body|html$/i.test(offsetParent[0].tagName)?{top:0,left:0}:offsetParent.offset();offset.top-=num(this,'marginTop');offset.left-=num(this,'marginLeft');parentOffset.top+=num(offsetParent,'borderTopWidth');parentOffset.left+=num(offsetParent,'borderLeftWidth');results={top:offset.top-parentOffset.top,left:offset.left-parentOffset.left};}return results;},offsetParent:function(){var offsetParent=this[0].offsetParent;while(offsetParent&&(!/^body|html$/i.test(offsetParent.tagName)&&jQuery.css(offsetParent,'position')=='static'))offsetParent=offsetParent.offsetParent;return jQuery(offsetParent);}});jQuery.each(['Left','Top'],function(i,name){var method='scroll'+name;jQuery.fn[method]=function(val){if(!this[0])return;return val!=undefined?this.each(function(){this==window||this==document?window.scrollTo(!i?val:jQuery(window).scrollLeft(),i?val:jQuery(window).scrollTop()):this[method]=val;}):this[0]==window||this[0]==document?self[i?'pageYOffset':'pageXOffset']||jQuery.boxModel&&document.documentElement[method]||document.body[method]:this[0][method];};});jQuery.each(["Height","Width"],function(i,name){var tl=i?"Left":"Top",br=i?"Right":"Bottom";jQuery.fn["inner"+name]=function(){return this[name.toLowerCase()]()+num(this,"padding"+tl)+num(this,"padding"+br);};jQuery.fn["outer"+name]=function(margin){return this["inner"+name]()+num(this,"border"+tl+"Width")+num(this,"border"+br+"Width")+(margin?num(this,"margin"+tl)+num(this,"margin"+br):0);};});})();



/* jQuery UI Date Picker v3.3 - previously jQuery Calendar
   Written by Marc Grabanski (m@marcgrabanski.com) and Keith Wood (kbwood@virginbroadband.com.au).

   Copyright (c) 2007 Marc Grabanski (http://marcgrabanski.com/code/ui-datepicker)
   Dual licensed under the MIT (MIT-LICENSE.txt)
   and GPL (GPL-LICENSE.txt) licenses.
   Date: 09-03-2007  */

/* Date picker manager.
   Use the singleton instance of this class, $.datepicker, to interact with the date picker.
   Settings for (groups of) date pickers are maintained in an instance object
   (DatepickerInstance), allowing multiple different settings on the same page. */
   
(function($) { // hide the namespace

function Datepicker() {
    this.debug = false; // Change this to true to start debugging
    this._nextId = 0; // Next ID for a date picker instance
    this._inst = []; // List of instances indexed by ID
    this._curInst = null; // The current instance in use
    this._disabledInputs = []; // List of date picker inputs that have been disabled
    this._datepickerShowing = false; // True if the popup picker is showing , false if not
    this._inDialog = false; // True if showing within a "dialog", false if not
    this.regional = []; // Available regional settings, indexed by language code
    this.regional['ru'] = { // Default regional settings
        clearText: 'Очистить', // Display text for clear link
        clearStatus: 'Стереть текущую дату', // Status text for clear link
        closeText: 'Закрыть', // Display text for close link
        closeStatus: 'Закрыть без сохранения', // Status text for close link
        prevText: '&#x3c;Пред', // Display text for previous month link
        prevStatus: 'Предыдущий месяц', // Status text for previous month link
        nextText: 'След&#x3e;', // Display text for next month link
        nextStatus: 'Следующий месяц', // Status text for next month link
        currentText: 'Сегодня', // Display text for current month link
        currentStatus: 'Текущий месяц', // Status text for current month link
        monthNames: ['Январь','Февраль','Март','Апрель','Май','Июнь',
            'Июль','Август','Сентябрь','Октябрь','Ноябрь','Декабрь'], // Names of months for drop-down and formatting
        monthNamesShort: ['Янв', 'Фев', 'Мар', 'Апр', 'Май', 'Июн', 'Июл', 'Авг', 'Сен', 'Окт', 'Ноя', 'Дек'], // For formatting
        monthStatus: 'Показать другой месяц', // Status text for selecting a month
        yearStatus: 'Показать другой год', // Status text for selecting a year
        weekHeader: 'Нед', // Header for the week of the year column
        weekStatus: 'Неделя года', // Status text for the week of the year column
        dayNames: ['Воскресенье', 'Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота'], // For formatting
        dayNamesShort: ['Вск', 'Пнд', 'Втр', 'Срд', 'Чтв', 'Птн', 'Сбт'], // For formatting
        dayNamesMin: ['Вс','Пн','Вт','Ср','Чт','Пт','Сб'], // Column headings for days starting at Sunday
        dayStatus: 'Установить первым днем недели', // Status text for the day of the week selection
        dateStatus: 'Выбрать день, месяц, год', // Status text for the date selection
        dateFormat: 'dd.mm.yy', // See format options on parseDate
        firstDay: 1, // The first day of the week, Sun = 0, Mon = 1, ...
        initStatus: 'Выбрать дату', // Initial Status text on opening
        isRTL: false // True if right-to-left language, false if left-to-right
    };
    this.regional['en'] = { // Default regional settings
        clearText: 'Clear', // Display text for clear link
        clearStatus: 'Стереть текущую дату', // Status text for clear link
        closeText: 'Close', // Display text for close link
        closeStatus: 'Закрыть без сохранения', // Status text for close link
        prevText: '&#x3c;Prev', // Display text for previous month link
        prevStatus: 'Previous month', // Status text for previous month link
        nextText: 'Next&#x3e;', // Display text for next month link
        nextStatus: 'Next month', // Status text for next month link
        currentText: 'Today', // Display text for current month link
        currentStatus: 'Current month', // Status text for current month link
        monthNames: ['January','February','March','April','May','June',
            'July','August','September','October','November','December'], // Names of months for drop-down and formatting
        monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], // For formatting
        monthStatus: 'Show other month', // Status text for selecting a month
        yearStatus: 'Show other year', // Status text for selecting a year
        weekHeader: 'Week', // Header for the week of the year column
        weekStatus: 'Week of year', // Status text for the week of the year column
        dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], // For formatting
        dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sut'], // For formatting
        dayNamesMin: ['Sn','Mn','Tu','Wd','Th','Fr','St'], // Column headings for days starting at Sunday
        dayStatus: 'Make first day of week', // Status text for the day of the week selection
        dateStatus: 'Choose day, month, year', // Status text for the date selection
        dateFormat: 'dd.mm.yy', // See format options on parseDate
        firstDay: 1, // The first day of the week, Sun = 0, Mon = 1, ...
        initStatus: 'Choose date', // Initial Status text on opening
        isRTL: false // True if right-to-left language, false if left-to-right
    };

    this._defaults = { // Global defaults for all the date picker instances
        showOn: 'focus', // 'focus' for popup on focus,
            // 'button' for trigger button, or 'both' for either
        showAnim: 'show', // Name of jQuery animation for popup
        defaultDate: null, // Used when field is blank: actual date,
            // +/-number for offset from today, null for today
        appendText: '', // Display text following the input box, e.g. showing the format
        buttonText: '...', // Text for trigger button
        buttonImage: '', // URL for trigger button image
        buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
        closeAtTop: true, // True to have the clear/close at the top,
            // false to have them at the bottom
        mandatory: false, // True to hide the Clear link, false to include it
        hideIfNoPrevNext: false, // True to hide next/previous month links
            // if not applicable, false to just disable them
        changeMonth: true, // True if month can be selected directly, false if only prev/next
        changeYear: true, // True if year can be selected directly, false if only prev/next
        yearRange: '-10:+10', // Range of years to display in drop-down,
            // either relative to current year (-nn:+nn) or absolute (nnnn:nnnn)
        changeFirstDay: true, // True to click on day name to change, false to remain as set
        showOtherMonths: false, // True to show dates in other months, false to leave blank
        showWeeks: false, // True to show week of the year, false to omit
        calculateWeek: this.iso8601Week, // How to calculate the week of the year,
            // takes a Date and returns the number of the week for it
        shortYearCutoff: '+10', // Short year values < this are in the current century,
            // > this are in the previous century, 
            // string value starting with '+' for current year + value
        showStatus: false, // True to show status bar at bottom, false to not show it
        statusForDate: this.dateStatus, // Function to provide status text for a date -
            // takes date and instance as parameters, returns display text
        minDate: null, // The earliest selectable date, or null for no limit
        maxDate: null, // The latest selectable date, or null for no limit
        speed: 'medium', // Speed of display/closure
        beforeShowDay: null, // Function that takes a date and returns an array with
            // [0] = true if selectable, false if not,
            // [1] = custom CSS class name(s) or '', e.g. $.datepicker.noWeekends
        beforeShow: null, // Function that takes an input field and
            // returns a set of custom settings for the date picker
        onSelect: null, // Define a callback function when a date is selected
        numberOfMonths: 1, // Number of months to show at a time
        stepMonths: 1, // Number of months to step back/forward
        rangeSelect: false, // Allows for selecting a date range on one date picker
        rangeSeparator: ' - ' // Text between two dates in a range
    };
    if(!window.lang) window.lang = 'en';
    $.extend(this._defaults, this.regional[window.lang]);
    this._datepickerDiv = $('<div id="datepicker_div"></div>');
}

$.extend(Datepicker.prototype, {
    /* Class name added to elements to indicate already configured with a date picker. */
    markerClassName: 'hasDatepicker',

    /* Debug logging (if enabled). */
    log: function () {
        if (this.debug) {
            console.log.apply('', arguments);
        }
    },
    
    /* Register a new date picker instance - with custom settings. */
    _register: function(inst) {
        var id = this._nextId++;
        this._inst[id] = inst;
        return id;
    },

    /* Retrieve a particular date picker instance based on its ID. */
    _getInst: function(id) {
        return this._inst[id] || id;
    },

    /* Override the default settings for all instances of the date picker. 
       @param  settings  object - the new settings to use as defaults (anonymous object)
       @return the manager object */
    setDefaults: function(settings) {
        extendRemove(this._defaults, settings || {});
        return this;
    },

    /* Handle keystrokes. */
    _doKeyDown: function(e) {
        var inst = $.datepicker._getInst(this._calId);
        if ($.datepicker._datepickerShowing) {
            switch (e.keyCode) {
                case 9:  $.datepicker.hideDatepicker('');
                        break; // hide on tab out
                case 13: $.datepicker._selectDay(inst, inst._selectedMonth, inst._selectedYear,
                            $('td.datepicker_daysCellOver', inst._datepickerDiv)[0]);
                        return false; // don't submit the form
                        break; // select the value on enter
                case 27: $.datepicker.hideDatepicker(inst._get('speed'));
                        break; // hide on escape
                case 33: $.datepicker._adjustDate(inst,
                            (e.ctrlKey ? -1 : -inst._get('stepMonths')), (e.ctrlKey ? 'Y' : 'M'));
                        break; // previous month/year on page up/+ ctrl
                case 34: $.datepicker._adjustDate(inst,
                            (e.ctrlKey ? +1 : +inst._get('stepMonths')), (e.ctrlKey ? 'Y' : 'M'));
                        break; // next month/year on page down/+ ctrl
                case 35: if (e.ctrlKey) $.datepicker._clearDate(inst);
                        break; // clear on ctrl+end
                case 36: if (e.ctrlKey) $.datepicker._gotoToday(inst);
                        break; // current on ctrl+home
                case 37: if (e.ctrlKey) $.datepicker._adjustDate(inst, -1, 'D');
                        break; // -1 day on ctrl+left
                case 38: if (e.ctrlKey) $.datepicker._adjustDate(inst, -7, 'D');
                        break; // -1 week on ctrl+up
                case 39: if (e.ctrlKey) $.datepicker._adjustDate(inst, +1, 'D');
                        break; // +1 day on ctrl+right
                case 40: if (e.ctrlKey) $.datepicker._adjustDate(inst, +7, 'D');
                        break; // +1 week on ctrl+down
            }
        }
        else if (e.keyCode == 36 && e.ctrlKey) { // display the date picker on ctrl+home
            $.datepicker.showFor(this);
        }
    },

    /* Filter entered characters - based on date format. */
    _doKeyPress: function(e) {
        var inst = $.datepicker._getInst(this._calId);
        var chars = $.datepicker._possibleChars(inst._get('dateFormat'));
        var chr = String.fromCharCode(e.charCode == undefined ? e.keyCode : e.charCode);
        return (chr < ' ' || !chars || chars.indexOf(chr) > -1);
    },

    /* Attach the date picker to an input field. */
    _connectDatepicker: function(target, inst) {
        var input = $(target);
        if (this._hasClass(input, this.markerClassName)) {
            return;
        }
        var appendText = inst._get('appendText');
        var isRTL = inst._get('isRTL');
        if (appendText) {
            if (isRTL) {
                input.before('<span class="datepicker_append">' + appendText + '</span>');
            }
            else {
                input.after('<span class="datepicker_append">' + appendText + '</span>');
            }
        }
        var showOn = inst._get('showOn');
        if (showOn == 'focus' || showOn == 'both') { // pop-up date picker when in the marked field
            input.focus(this.showFor);
        }
        if (showOn == 'button' || showOn == 'both') { // pop-up date picker when button clicked
            var buttonText = inst._get('buttonText');
            var buttonImage = inst._get('buttonImage');
            var buttonImageOnly = inst._get('buttonImageOnly');
            var trigger = $(buttonImageOnly ? '<img class="datepicker_trigger" src="' +
                buttonImage + '" alt="' + buttonText + '" title="' + buttonText + '"/>' :
                '<button type="button" class="datepicker_trigger">' + (buttonImage != '' ?
                '<img src="' + buttonImage + '" alt="' + buttonText + '" title="' + buttonText + '"/>' :
                buttonText) + '</button>');
            input.wrap('<span class="datepicker_wrap"></span>');
            if (isRTL) {
                input.before(trigger);
            }
            else {
                input.after(trigger);
            }
            trigger.click(this.showFor);
        }
        input.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress);
        input[0]._calId = inst._id;
    },

    /* Attach an inline date picker to a div. */
    _inlineDatepicker: function(target, inst) {
        var input = $(target);
        if (this._hasClass(input, this.markerClassName)) {
            return;
        }
        input.addClass(this.markerClassName).append(inst._datepickerDiv);
        input[0]._calId = inst._id;
        this._updateDatepicker(inst);
        /* @todo: fix _inlineShow automatic resizing
            - Endless loop bug in IE6.  
            - inst._datepickerDiv.resize doesn't ever fire in firefox.  */
        // inst._datepickerDiv.resize(function() { $.datepicker._inlineShow(inst); });
    },

    /* Tidy up after displaying the date picker. */
    _inlineShow: function(inst) {
        var numMonths = inst._getNumberOfMonths(); // fix width for dynamic number of date pickers
        inst._datepickerDiv.width(numMonths[1] * $('.datepicker', inst._datepickerDiv[0]).width());
    }, 

    /* Does this element have a particular class? */
    _hasClass: function(element, className) {
        var classes = element.attr('class');
        return (classes && classes.indexOf(className) > -1);
    },

    /* Pop-up the date picker in a "dialog" box.
       @param  dateText  string - the initial date to display (in the current format)
       @param  onSelect  function - the function(dateText) to call when a date is selected
       @param  settings  object - update the dialog date picker instance's settings (anonymous object)
       @param  pos       int[2] - coordinates for the dialog's position within the screen or
                         event - with x/y coordinates or
                         leave empty for default (screen centre)
       @return the manager object */
    dialogDatepicker: function(dateText, onSelect, settings, pos) {
        var inst = this._dialogInst; // internal instance
        if (!inst) {
            inst = this._dialogInst = new DatepickerInstance({}, false);
            this._dialogInput = $('<input type="text" size="1" style="position: absolute; top: -100px;"/>');
            this._dialogInput.keydown(this._doKeyDown);
            $('body').append(this._dialogInput);
            this._dialogInput[0]._calId = inst._id;
        }
        extendRemove(inst._settings, settings || {});
        this._dialogInput.val(dateText);

        this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);
        if (!this._pos) {
            var browserWidth = window.innerWidth || document.documentElement.clientWidth ||
                document.body.clientWidth;
            var browserHeight = window.innerHeight || document.documentElement.clientHeight ||
                document.body.clientHeight;
            var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
            var scrollY = document.documentElement.scrollTop || document.body.scrollTop;
            this._pos = // should use actual width/height below
                [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY];
        }

        // move input on screen for focus, but hidden behind dialog
        this._dialogInput.css('left', this._pos[0] + 'px').css('top', this._pos[1] + 'px');
        inst._settings.onSelect = onSelect;
        this._inDialog = true;
        this._datepickerDiv.addClass('datepicker_dialog');
        this.showFor(this._dialogInput[0]);
        if ($.blockUI) {
            $.blockUI(this._datepickerDiv);
        }
        return this;
    },

    /* Pop-up the date picker for a given input field.
       @param  control  element - the input field attached to the date picker or
                        string - the ID or other jQuery selector of the input field or
                        object - jQuery object for input field
       @return the manager object */
    showFor: function(control) {
        control = (control.jquery ? control[0] :
            (typeof control == 'string' ? $(control)[0] : control));
        var input = (control.nodeName && control.nodeName.toLowerCase() == 'input' ? control : this);
        if (input.nodeName.toLowerCase() != 'input') { // find from button/image trigger
            input = $('input', input.parentNode)[0];
        }
        if ($.datepicker._lastInput == input) { // already here
            return;
        }
        if ($(input).isDisabledDatepicker()) {
            return;
        }
        var inst = $.datepicker._getInst(input._calId);
        var beforeShow = inst._get('beforeShow');
        extendRemove(inst._settings, (beforeShow ? beforeShow.apply(input, [input, inst]) : {}));
        $.datepicker.hideDatepicker('');
        $.datepicker._lastInput = input;
        inst._setDateFromField(input);
        if ($.datepicker._inDialog) { // hide cursor
            input.value = '';
        }
        if (!$.datepicker._pos) { // position below input
            $.datepicker._pos = $.datepicker._findPos(input);
            $.datepicker._pos[1] += input.offsetHeight; // add the height
        }
        var isFixed = false;
        $(input).parents().each(function() {
            isFixed |= $(this).css('position') == 'fixed';
        });
        if (isFixed && $.browser.opera) { // correction for Opera when fixed and scrolled
            $.datepicker._pos[0] -= document.documentElement.scrollLeft;
            $.datepicker._pos[1] -= document.documentElement.scrollTop;
        }
        inst._datepickerDiv.css('position', ($.datepicker._inDialog && $.blockUI ?
            'static' : (isFixed ? 'fixed' : 'absolute'))).
            css('left', $.datepicker._pos[0] + 'px').css('top', $.datepicker._pos[1] + 'px');
        $.datepicker._pos = null;
        $.datepicker._showDatepicker(inst);
        return this;
    },

    /* Construct and display the date picker. */
    _showDatepicker: function(id) {
        var inst = this._getInst(id);
        inst._rangeStart = null;
        this._updateDatepicker(inst);
        if (!inst._inline) {
            var speed = inst._get('speed');
            var postProcess = function() {
                $.datepicker._datepickerShowing = true;
                $.datepicker._afterShow(inst);
            };
            var showAnim = inst._get('showAnim') || 'show';
            inst._datepickerDiv[showAnim](speed, postProcess);
            if (speed == '') {
                postProcess();
            }
            if (inst._input[0].type != 'hidden') {
                inst._input[0].focus();
            }
            this._curInst = inst;
        }
    },

    /* Generate the date picker content. */
    _updateDatepicker: function(inst) {
        inst._datepickerDiv.empty().append(inst._generateDatepicker());
        var numMonths = inst._getNumberOfMonths();
        if (numMonths[0] != 1 || numMonths[1] != 1) {
            inst._datepickerDiv.addClass('datepicker_multi');
        } 
        else {
            inst._datepickerDiv.removeClass('datepicker_multi');
        }
        if (inst._get('isRTL')) {
            inst._datepickerDiv.addClass('datepicker_rtl');
        }
        else {
            inst._datepickerDiv.removeClass('datepicker_rtl');
        }
        if (inst._input && inst._input[0].type != 'hidden') {
            inst._input[0].focus();
        }
    },

    /* Tidy up after displaying the date picker. */
    _afterShow: function(inst) {
        var numMonths = inst._getNumberOfMonths(); // fix width for dynamic number of date pickers
        inst._datepickerDiv.width(numMonths[1] * $('.datepicker', inst._datepickerDiv[0]).width());
        if ($.browser.msie && parseInt($.browser.version) < 7) { // fix IE < 7 select problems
            $('#datepicker_cover').css({width: inst._datepickerDiv.width() + 4,
                height: inst._datepickerDiv.height() + 4});
        }
        // re-position on screen if necessary
        var isFixed = inst._datepickerDiv.css('position') == 'fixed';
        var pos = inst._input ? $.datepicker._findPos(inst._input[0]) : null;
        var browserWidth = window.innerWidth || document.documentElement.clientWidth ||
            document.body.clientWidth;
        var browserHeight = window.innerHeight || document.documentElement.clientHeight ||
            document.body.clientHeight;
        var scrollX = (isFixed ? 0 : document.documentElement.scrollLeft || document.body.scrollLeft);
        var scrollY = (isFixed ? 0 : document.documentElement.scrollTop || document.body.scrollTop);
        // reposition date picker horizontally if outside the browser window
        if ((inst._datepickerDiv.offset().left + inst._datepickerDiv.width() -
                (isFixed && $.browser.msie ? document.documentElement.scrollLeft : 0)) >
                (browserWidth + scrollX)) {
            inst._datepickerDiv.css('left', Math.max(scrollX,
                pos[0] + (inst._input ? $(inst._input[0]).width() : null) - inst._datepickerDiv.width() -
                (isFixed && $.browser.opera ? document.documentElement.scrollLeft : 0)) + 'px');
        }
        // reposition date picker vertically if outside the browser window
        if ((inst._datepickerDiv.offset().top + inst._datepickerDiv.height() -
                (isFixed && $.browser.msie ? document.documentElement.scrollTop : 0)) >
                (browserHeight + scrollY) ) {
            inst._datepickerDiv.css('top', Math.max(scrollY,
                pos[1] - (this._inDialog ? 0 : inst._datepickerDiv.height()) -
                (isFixed && $.browser.opera ? document.documentElement.scrollTop : 0)) + 'px');
        }
    },
    
    /* Find an object's position on the screen. */
    _findPos: function(obj) {
        while (obj && (obj.type == 'hidden' || obj.nodeType != 1)) {
            obj = obj.nextSibling;
        }
        var curleft = curtop = 0;
        if (obj && obj.offsetParent) {
            curleft = obj.offsetLeft;
            curtop = obj.offsetTop;
            while (obj = obj.offsetParent) {
                var origcurleft = curleft;
                curleft += obj.offsetLeft;
                if (curleft < 0) {
                    curleft = origcurleft;
                }
                curtop += obj.offsetTop;
            }
        }
        return [curleft,curtop];
    },

    /* Hide the date picker from view.
       @param  speed  string - the speed at which to close the date picker
       @return void */
    hideDatepicker: function(speed) {
        var inst = this._curInst;
        if (!inst) {
            return;
        }
        var rangeSelect = inst._get('rangeSelect');
        if (rangeSelect && this._stayOpen) {
            this._selectDate(inst, inst._formatDate(
                inst._currentDay, inst._currentMonth, inst._currentYear));
        }
        this._stayOpen = false;
        if (this._datepickerShowing) {
            speed = (speed != null ? speed : inst._get('speed'));
            inst._datepickerDiv.hide(speed, function() {
                $.datepicker._tidyDialog(inst);
            });
            if (speed == '') {
                this._tidyDialog(inst);
            }
            this._datepickerShowing = false;
            this._lastInput = null;
            inst._settings.prompt = null;
            if (this._inDialog) {
                this._dialogInput.css('position', 'absolute').
                    css('left', '0px').css('top', '-100px');
                if ($.blockUI) {
                    $.unblockUI();
                    $('body').append(this._datepickerDiv);
                }
            }
            this._inDialog = false;
        }
        this._curInst = null;
    },

    /* Tidy up after a dialog display. */
    _tidyDialog: function(inst) {
        inst._datepickerDiv.removeClass('datepicker_dialog');
        $('.datepicker_prompt', inst._datepickerDiv).remove();
    },

    /* Close date picker if clicked elsewhere. */
    _checkExternalClick: function(event) {
        if (!$.datepicker._curInst) {
            return;
        }
        var target = $(event.target);
        if ((target.parents("#datepicker_div").length == 0) &&
                (target.attr('class') != 'datepicker_trigger') &&
                $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI)) {
            $.datepicker.hideDatepicker('');
        }
    },

    /* Adjust one of the date sub-fields. */
    _adjustDate: function(id, offset, period) {
        var inst = this._getInst(id);
        inst._adjustDate(offset, period);
        this._updateDatepicker(inst);
    },

    /* Action for current link. */
    _gotoToday: function(id) {
        var date = new Date();
        var inst = this._getInst(id);
        inst._selectedDay = date.getDate();
        inst._selectedMonth = date.getMonth();
        inst._selectedYear = date.getFullYear();
        this._adjustDate(inst);
    },

    /* Action for selecting a new month/year. */
    _selectMonthYear: function(id, select, period) {
        var inst = this._getInst(id);
        inst._selectingMonthYear = false;
        inst[period == 'M' ? '_selectedMonth' : '_selectedYear'] =
            select.options[select.selectedIndex].value - 0;
        this._adjustDate(inst);
    },

    /* Restore input focus after not changing month/year. */
    _clickMonthYear: function(id) {
        var inst = this._getInst(id);
        if (inst._input && inst._selectingMonthYear && !$.browser.msie) {
            inst._input[0].focus();
        }
        inst._selectingMonthYear = !inst._selectingMonthYear;
    },

    /* Action for changing the first week day. */
    _changeFirstDay: function(id, day) {
        var inst = this._getInst(id);
        inst._settings.firstDay = day;
        this._updateDatepicker(inst);
    },

    /* Action for selecting a day. */
    _selectDay: function(id, month, year, td) {
        if (this._hasClass($(td), 'datepicker_unselectable')) {
            return;
        }
        var inst = this._getInst(id);
        var rangeSelect = inst._get('rangeSelect');
        if (rangeSelect) {
            if (!this._stayOpen) {
                $('.datepicker td').removeClass('datepicker_currentDay');
                $(td).addClass('datepicker_currentDay');
            } 
            this._stayOpen = !this._stayOpen;
        }
        inst._currentDay = $('a', td).html();
        inst._currentMonth = month;
        inst._currentYear = year;
        this._selectDate(id, inst._formatDate(
            inst._currentDay, inst._currentMonth, inst._currentYear));
        if (this._stayOpen) {
            inst._endDay = inst._endMonth = inst._endYear = null;
            inst._rangeStart = new Date(inst._currentYear, inst._currentMonth, inst._currentDay);
            this._updateDatepicker(inst);
        }
        else if (rangeSelect) {
            inst._endDay = inst._currentDay;
            inst._endMonth = inst._currentMonth;
            inst._endYear = inst._currentYear;
            inst._selectedDay = inst._currentDay = inst._rangeStart.getDate();
            inst._selectedMonth = inst._currentMonth = inst._rangeStart.getMonth();
            inst._selectedYear = inst._currentYear = inst._rangeStart.getFullYear();
            inst._rangeStart = null;
            if (inst._inline) {
                this._updateDatepicker(inst);
            }
        }
    },

    /* Erase the input field and hide the date picker. */
    _clearDate: function(id) {
        var inst = this._getInst(id);
        this._stayOpen = false;
        inst._endDay = inst._endMonth = inst._endYear = inst._rangeStart = null;
        this._selectDate(inst, '');
    },

    /* Update the input field with the selected date. */
    _selectDate: function(id, dateStr) {
        var inst = this._getInst(id);
        dateStr = (dateStr != null ? dateStr : inst._formatDate());
        if (inst._rangeStart) {
            dateStr = inst._formatDate(inst._rangeStart) + inst._get('rangeSeparator') + dateStr;
        }
        if (inst._input) {
            inst._input.val(dateStr);
        }
        var onSelect = inst._get('onSelect');
        if (onSelect) {
            onSelect.apply((inst._input ? inst._input[0] : null), [dateStr, inst]);  // trigger custom callback
        }
        else {
            if (inst._input) {
                inst._input.trigger('change'); // fire the change event
            }
        }
        if (inst._inline) {
            this._updateDatepicker(inst);
        }
        else {
            if (!this._stayOpen) {
                this.hideDatepicker(inst._get('speed'));
                this._lastInput = inst._input[0];
                if (typeof(inst._input[0]) != 'object') {
                    inst._input[0].focus(); // restore focus
                }
                this._lastInput = null;
            }
        }
    },

    /* Set as beforeShowDay function to prevent selection of weekends.
       @param  date  Date - the date to customise
       @return [boolean, string] - is this date selectable?, what is its CSS class? */
    noWeekends: function(date) {
        var day = date.getDay();
        return [(day > 0 && day < 6), ''];
    },
    
    /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
       @param  date  Date - the date to get the week for
       @return  number - the number of the week within the year that contains this date */
    iso8601Week: function(date) {
        var checkDate = new Date(date.getFullYear(), date.getMonth(), date.getDate());
        var firstMon = new Date(checkDate.getFullYear(), 1 - 1, 4); // First week always contains 4 Jan
        var firstDay = firstMon.getDay() || 7; // Day of week: Mon = 1, ..., Sun = 7
        firstMon.setDate(firstMon.getDate() + 1 - firstDay); // Preceding Monday
        if (firstDay < 4 && checkDate < firstMon) { // Adjust first three days in year if necessary
            checkDate.setDate(checkDate.getDate() - 3); // Generate for previous year
            return $.datepicker.iso8601Week(checkDate);
        }
        else if (checkDate > new Date(checkDate.getFullYear(), 12 - 1, 28)) { // Check last three days in year
            firstDay = new Date(checkDate.getFullYear() + 1, 1 - 1, 4).getDay() || 7;
            if (firstDay > 4 && (checkDate.getDay() || 7) < firstDay - 3) { // Adjust if necessary
                checkDate.setDate(checkDate.getDate() + 3); // Generate for next year
                return $.datepicker.iso8601Week(checkDate);
            }
        }
        return Math.floor(((checkDate - firstMon) / 86400000) / 7) + 1; // Weeks to given date
    },
    
    /* Provide status text for a particular date.
       @param  date  the date to get the status for
       @param  inst  the current datepicker instance
       @return  the status display text for this date */
    dateStatus: function(date, inst) {
        return $.datepicker.formatDate(inst._get('dateStatus'), date, inst._get('dayNamesShort'),
            inst._get('dayNames'), inst._get('monthNamesShort'), inst._get('monthNames'));
    },

    /* Parse a string value into a date object.
       The format can be combinations of the following:
       d  - day of month (no leading zero)
       dd - day of month (two digit)
       D  - day name short
       DD - day name long
       m  - month of year (no leading zero)
       mm - month of year (two digit)
       M  - month name short
       MM - month name long
       y  - year (two digit)
       yy - year (four digit)
       '...' - literal text
       '' - single quote

       @param  format           String - the expected format of the date
       @param  value            String - the date in the above format
       @param  shortYearCutoff  Number - the cutoff year for determining the century (optional)
       @param  dayNamesShort    String[7] - abbreviated names of the days from Sunday (optional)
       @param  dayNames         String[7] - names of the days from Sunday (optional)
       @param  monthNamesShort  String[12] - abbreviated names of the months (optional)
       @param  monthNames       String[12] - names of the months (optional)
       @return  Date - the extracted date value or null if value is blank */
    parseDate: function (format, value, shortYearCutoff, dayNamesShort, dayNames, monthNamesShort, monthNames) {
        if (format == null || value == null) {
            throw 'Invalid arguments';
        }
//        format = dateFormats[format] || format;
        value = (typeof value == 'object' ? value.toString() : value + '');
        if (value == '') {
            return null;
        }
        dayNamesShort = dayNamesShort || this._defaults.dayNamesShort;
        dayNames = dayNames || this._defaults.dayNames;
        monthNamesShort = monthNamesShort || this._defaults.monthNamesShort;
        monthNames = monthNames || this._defaults.monthNames;
        var year = -1;
        var month = -1;
        var day = -1;
        var literal = false;
        // Check whether a format character is doubled
        var lookAhead = function(match) {
            var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);
            if (matches) {
                iFormat++;
            }
            return matches;    
        };
        // Extract a number from the string value
        var getNumber = function(match) {
            lookAhead(match);
            var size = (match == 'y' ? 4 : 2);
            var num = 0;
            while (size > 0 && iValue < value.length &&
                    value.charAt(iValue) >= '0' && value.charAt(iValue) <= '9') {
                num = num * 10 + (value.charAt(iValue++) - 0);
                size--;
            }
            if (size == (match == 'y' ? 4 : 2)) {
                throw 'Missing number at position ' + iValue;
            }
            return num;
        };
        // Extract a name from the string value and convert to an index
        var getName = function(match, shortNames, longNames) {
            var names = (lookAhead(match) ? longNames : shortNames);
            var size = 0;
            for (var j = 0; j < names.length; j++) {
                size = Math.max(size, names[j].length);
            }
            var name = '';
            var iInit = iValue;
            while (size > 0 && iValue < value.length) {
                name += value.charAt(iValue++);
                for (var i = 0; i < names.length; i++) {
                    if (name == names[i]) {
                        return i + 1;
                    }
                }
                size--;
            }
            throw 'Unknown name at position ' + iInit;
        };
        // Confirm that a literal character matches the string value
        var checkLiteral = function() {
            if (value.charAt(iValue) != format.charAt(iFormat)) {
                throw 'Unexpected literal at position ' + iValue;
            }
            iValue++;
        };
        var iValue = 0;
        for (var iFormat = 0; iFormat < format.length; iFormat++) {
            if (literal) {
                if (format.charAt(iFormat) == '\'' && !lookAhead('\'')) {
                    literal = false;
                }
                else {
                    checkLiteral();
                }
            }
            else {
                switch (format.charAt(iFormat)) {
                    case 'd':
                        day = getNumber('d');
                        break;
                    case 'D': 
                        getName('D', dayNamesShort, dayNames);
                        break;
                    case 'm': 
                        month = getNumber('m');
                        break;
                    case 'M':
                        month = getName('M', monthNamesShort, monthNames); 
                        break;
                    case 'y':
                        year = getNumber('y');
                        break;
                    case '\'':
                        if (lookAhead('\'')) {
                            checkLiteral();
                        }
                        else {
                            literal = true;
                        }
                        break;
                    default:
                        checkLiteral();
                }
            }
        }
        if (year < 100) {
            year += new Date().getFullYear() - new Date().getFullYear() % 100 +
                (year <= shortYearCutoff ? 0 : -100);
        }
        var date = new Date(year, month - 1, day);
        if (date.getFullYear() != year || date.getMonth() + 1 != month || date.getDate() != day) {
            throw 'Invalid date'; // E.g. 31/02/*
        }
        return date;
    },

    /* Format a date object into a string value.
       The format can be combinations of the following:
       d  - day of month (no leading zero)
       dd - day of month (two digit)
       D  - day name short
       DD - day name long
       m  - month of year (no leading zero)
       mm - month of year (two digit)
       M  - month name short
       MM - month name long
       y  - year (two digit)
       yy - year (four digit)
       '...' - literal text
       '' - single quote

       @param  format           String - the desired format of the date
       @param  date             Date - the date value to format
       @param  dayNamesShort    String[7] - abbreviated names of the days from Sunday (optional)
       @param  dayNames         String[7] - names of the days from Sunday (optional)
       @param  monthNamesShort  String[12] - abbreviated names of the months (optional)
       @param  monthNames       String[12] - names of the months (optional)
       @return  String - the date in the above format */
    formatDate: function (format, date, dayNamesShort, dayNames, monthNamesShort, monthNames) {
        if (!date) {
            return '';
        }
//        format = dateFormats[format] || format;
        dayNamesShort = dayNamesShort || this._defaults.dayNamesShort;
        dayNames = dayNames || this._defaults.dayNames;
        monthNamesShort = monthNamesShort || this._defaults.monthNamesShort;
        monthNames = monthNames || this._defaults.monthNames;
        // Check whether a format character is doubled
        var lookAhead = function(match) {
            var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);
            if (matches) {
                iFormat++;
            }
            return matches;    
        };
        // Format a number, with leading zero if necessary
        var formatNumber = function(match, value) {
            return (lookAhead(match) && value < 10 ? '0' : '') + value;
        };
        // Format a name, short or long as requested
        var formatName = function(match, value, shortNames, longNames) {
            return (lookAhead(match) ? longNames[value] : shortNames[value]);
        };
        var output = '';
        var literal = false;
        if (date) {
            for (var iFormat = 0; iFormat < format.length; iFormat++) {
                if (literal) {
                    if (format.charAt(iFormat) == '\'' && !lookAhead('\'')) {
                        literal = false;
                    }
                    else {
                        output += format.charAt(iFormat);
                    }
                }
                else {
                    switch (format.charAt(iFormat)) {
                        case 'd':
                            output += formatNumber('d', date.getDate()); 
                            break;
                        case 'D': 
                            output += formatName('D', date.getDay(), dayNamesShort, dayNames);
                            break;
                        case 'm': 
                            output += formatNumber('m', date.getMonth() + 1); 
                            break;
                        case 'M':
                            output += formatName('M', date.getMonth(), monthNamesShort, monthNames); 
                            break;
                        case 'y':
                            output += (lookAhead('y') ? date.getFullYear() : 
                                (date.getYear() % 100 < 10 ? '0' : '') + date.getYear() % 100);
                            break;
                        case '\'':
                            if (lookAhead('\'')) {
                                output += '\'';
                            }
                            else {
                                literal = true;
                            }
                            break;
                        default:
                            output += format.charAt(iFormat);
                    }
                }
            }
        }
        return output;
    },

    /* Extract all possible characters from the date format. */
    _possibleChars: function (format) {
//        format = dateFormats[format] || format;
        var chars = '';
        var literal = false;
        for (var iFormat = 0; iFormat < format.length; iFormat++) {
            if (literal) {
                if (format.charAt(iFormat) == '\'' && !lookAhead('\'')) {
                    literal = false;
                }
                else {
                    chars += format.charAt(iFormat);
                }
            }
            else {
                switch (format.charAt(iFormat)) {
                    case 'd':
                    case 'm': 
                    case 'y':
                        chars += '0123456789'; 
                        break;
                    case 'D': 
                    case 'M':
                        return null; // Accept anything
                    case '\'':
                        if (lookAhead('\'')) {
                            chars += '\'';
                        }
                        else {
                            literal = true;
                        }
                        break;
                    default:
                        chars += format.charAt(iFormat);
                }
            }
        }
        return chars;
    }
});

/* Individualised settings for date picker functionality applied to one or more related inputs.
   Instances are managed and manipulated through the Datepicker manager. */
function DatepickerInstance(settings, inline) {
    this._id = $.datepicker._register(this);
    this._selectedDay = 0;
    this._selectedMonth = 0; // 0-11
    this._selectedYear = 0; // 4-digit year
    this._input = null; // The attached input field
    this._inline = inline; // True if showing inline, false if used in a popup
    this._datepickerDiv = (!inline ? $.datepicker._datepickerDiv :
        $('<div id="datepicker_div_' + this._id + '" class="datepicker_inline"></div>'));
    // customise the date picker object - uses manager defaults if not overridden
    this._settings = extendRemove({}, settings || {}); // clone
    if (inline) {
        this._setDate(this._getDefaultDate());
    }
}

$.extend(DatepickerInstance.prototype, {
    /* Get a setting value, defaulting if necessary. */
    _get: function(name) {
        return (this._settings[name] != null ? this._settings[name] : $.datepicker._defaults[name]);
    },

    /* Parse existing date and initialise date picker. */
    _setDateFromField: function(input) {
        this._input = $(input);
        var dateFormat = this._get('dateFormat');
        var dates = this._input ? this._input.val().split(this._get('rangeSeparator')) : null; 
        this._endDay = this._endMonth = this._endYear = null;
        var shortYearCutoff = this._get('shortYearCutoff');
        shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff :
            new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
        var date = defaultDate = this._getDefaultDate();
        if (dates.length > 0) {
            var dayNamesShort = this._get('dayNamesShort');
            var dayNames = this._get('dayNames');
            var monthNamesShort = this._get('monthNamesShort');
            var monthNames = this._get('monthNames');
            if (dates.length > 1) {
                date = $.datepicker.parseDate(dateFormat, dates[1], shortYearCutoff,
                    dayNamesShort, dayNames, monthNamesShort, monthNames) || defaultDate;
                this._endDay = date.getDate();
                this._endMonth = date.getMonth();
                this._endYear = date.getFullYear();
            }
            try {
                date = $.datepicker.parseDate(dateFormat, dates[0], shortYearCutoff,
                    dayNamesShort, dayNames, monthNamesShort, monthNames) ||defaultDate;
            }
            catch (e) {
                $.datepicker.log(e);
                date = defaultDate;
            }
        }
        this._selectedDay = this._currentDay = date.getDate();
        this._selectedMonth = this._currentMonth = date.getMonth();
        this._selectedYear = this._currentYear = date.getFullYear();
        this._adjustDate();
    },
    
    /* Retrieve the default date shown on opening. */
    _getDefaultDate: function() {
        return this._determineDate('defaultDate', new Date());
    },

    /* A date may be specified as an exact value or a relative one. */
    _determineDate: function(name, defaultDate) {
        var offsetNumeric = function(offset) {
            var date = new Date();
            date.setDate(date.getDate() + offset);
            return date;
        };
        var offsetString = function(offset, getDaysInMonth) {
            var date = new Date();
            var matches = /^([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?$/.exec(offset);
            if (matches) {
                var year = date.getFullYear();
                var month = date.getMonth();
                var day = date.getDate();
                switch (matches[2] || 'd') {
                    case 'd' : case 'D' :
                        day += (matches[1] - 0); break;
                    case 'w' : case 'W' :
                        day += (matches[1] * 7); break;
                    case 'm' : case 'M' :
                        month += (matches[1] - 0); 
                        day = Math.min(day, getDaysInMonth(year, month));
                        break;
                    case 'y': case 'Y' :
                        year += (matches[1] - 0);
                        day = Math.min(day, getDaysInMonth(year, month));
                        break;
                }
                date = new Date(year, month, day);
            }
            return date;
        };
        var date = this._get(name);
        return (date == null ? defaultDate :
            (typeof date == 'string' ? offsetString(date, this._getDaysInMonth) :
            (typeof date == 'number' ? offsetNumeric(date) : date)));
    },

    /* Set the date(s) directly. */
    _setDate: function(date, endDate) {
        this._selectedDay = this._currentDay = date.getDate();
        this._selectedMonth = this._currentMonth = date.getMonth();
        this._selectedYear = this._currentYear = date.getFullYear();
        if (this._get('rangeSelect')) {
            if (endDate) {
                this._endDay = endDate.getDate();
                this._endMonth = endDate.getMonth();
                this._endYear = endDate.getFullYear();
            }
            else {
                this._endDay = this._currentDay;
                this._endMonth = this._currentMonth;
                this._endYear = this._currentYear;
            }
        }
        this._adjustDate();
    },

    /* Retrieve the date(s) directly. */
    _getDate: function() {
        var startDate = (!this._currentYear || (this._input && this._input.val() == '') ? null :
            new Date(this._currentYear, this._currentMonth, this._currentDay));
        if (this._get('rangeSelect')) {
            return [startDate, (!this._endYear ? null :
                new Date(this._endYear, this._endMonth, this._endDay))];
        }
        else {
            return startDate;
        }
    },

    /* Generate the HTML for the current state of the date picker. */
    _generateDatepicker: function() {
        var today = new Date();
        today = new Date(today.getFullYear(), today.getMonth(), today.getDate()); // clear time
        var showStatus = this._get('showStatus');
        var isRTL = this._get('isRTL');
        // build the date picker HTML
        var clear = (this._get('mandatory') ? '' :
            '<div class="datepicker_clear"><a onclick="jQuery.datepicker._clearDate(' + this._id + ');"' + 
            (showStatus ? this._addStatus(this._get('clearStatus') || '&#xa0;') : '') + '>' +
            this._get('clearText') + '</a></div>');
        var controls = '<div class="datepicker_control">' + (isRTL ? '' : clear) +
            '<div class="datepicker_close"><a onclick="jQuery.datepicker.hideDatepicker();"' +
            (showStatus ? this._addStatus(this._get('closeStatus') || '&#xa0;') : '') + '>' +
            this._get('closeText') + '</a></div>' + (isRTL ? clear : '')  + '</div>';
        var prompt = this._get('prompt');
        var closeAtTop = this._get('closeAtTop');
        var hideIfNoPrevNext = this._get('hideIfNoPrevNext');
        var numMonths = this._getNumberOfMonths();
        var stepMonths = this._get('stepMonths');
        var isMultiMonth = (numMonths[0] != 1 || numMonths[1] != 1);
        var minDate = this._getMinMaxDate('min', true);
        var maxDate = this._getMinMaxDate('max');
        var drawMonth = this._selectedMonth;
        var drawYear = this._selectedYear;
        if (maxDate) {
            var maxDraw = new Date(maxDate.getFullYear(),
                maxDate.getMonth() - numMonths[1] + 1, maxDate.getDate());
            maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw);
            while (new Date(drawYear, drawMonth, 1) > maxDraw) {
                drawMonth--;
                if (drawMonth < 0) {
                    drawMonth = 11;
                    drawYear--;
                }
            }
        }
        // controls and links
        var prev = '<div class="datepicker_prev">' + (this._canAdjustMonth(-1, drawYear, drawMonth) ? 
            '<a onclick="jQuery.datepicker._adjustDate(' + this._id + ', -' + stepMonths + ', \'M\');"' +
            (showStatus ? this._addStatus(this._get('prevStatus') || '&#xa0;') : '') + '>' +
            this._get('prevText') + '</a>' :
            (hideIfNoPrevNext ? '' : '<label>' + this._get('prevText') + '</label>')) + '</div>';
        var next = '<div class="datepicker_next">' + (this._canAdjustMonth(+1, drawYear, drawMonth) ?
            '<a onclick="jQuery.datepicker._adjustDate(' + this._id + ', +' + stepMonths + ', \'M\');"' +
            (showStatus ? this._addStatus(this._get('nextStatus') || '&#xa0;') : '') + '>' +
            this._get('nextText') + '</a>' :
            (hideIfNoPrevNext ? '>' : '<label>' + this._get('nextText') + '</label>')) + '</div>';
        var html = (prompt ? '<div class="datepicker_prompt">' + prompt + '</div>' : '') +
            (closeAtTop && !this._inline ? controls : '') +
            '<div class="datepicker_links">' + (isRTL ? next : prev) +
            (this._isInRange(today) ? '<div class="datepicker_current">' +
            '<a onclick="jQuery.datepicker._gotoToday(' + this._id + ');"' +
            (showStatus ? this._addStatus(this._get('currentStatus') || '&#xa0;') : '') + '>' +
            this._get('currentText') + '</a></div>' : '') + (isRTL ? prev : next) + '</div>';
        var showWeeks = this._get('showWeeks');
        for (var row = 0; row < numMonths[0]; row++) {
        for (var col = 0; col < numMonths[1]; col++) {
            var selectedDate = new Date(drawYear, drawMonth, this._selectedDay);
            html += '<div class="datepicker_oneMonth' + (col == 0 ? ' datepicker_newRow' : '') + '">' +
                this._generateMonthYearHeader(drawMonth, drawYear, minDate, maxDate,
                selectedDate, row > 0 || col > 0) + // draw month headers
                '<table class="datepicker" cellpadding="0" cellspacing="0"><thead>' + 
                '<tr class="datepicker_titleRow">' +
                (showWeeks ? '<td>' + this._get('weekHeader') + '</td>' : '');
            var firstDay = this._get('firstDay');
            var changeFirstDay = this._get('changeFirstDay');
            var dayNames = this._get('dayNames');
            var dayNamesShort = this._get('dayNamesShort');
            var dayNamesMin = this._get('dayNamesMin');
            for (var dow = 0; dow < 7; dow++) { // days of the week
                var day = (dow + firstDay) % 7;
                var status = this._get('dayStatus') || '&#xa0;';
                status = (status.indexOf('DD') > -1 ? status.replace(/DD/, dayNames[day]) :
                    status.replace(/D/, dayNamesShort[day]));
                html += '<td' + ((dow + firstDay + 6) % 7 >= 5 ? ' class="datepicker_weekEndCell"' : '') + '>' +
                    (!changeFirstDay ? '<span' :
                    '<a onclick="jQuery.datepicker._changeFirstDay(' + this._id + ', ' + day + ');"') + 
                    (showStatus ? this._addStatus(status) : '') + ' title="' + dayNames[day] + '">' +
                    dayNamesMin[day] + (changeFirstDay ? '</a>' : '</span>') + '</td>';
            }
            html += '</tr></thead><tbody>';
            var daysInMonth = this._getDaysInMonth(drawYear, drawMonth);
            if (drawYear == this._selectedYear && drawMonth == this._selectedMonth) {
                this._selectedDay = Math.min(this._selectedDay, daysInMonth);
            }
            var leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;
            var currentDate = new Date(this._currentYear, this._currentMonth, this._currentDay);
            var endDate = this._endDay ? new Date(this._endYear, this._endMonth, this._endDay) : currentDate;
            var printDate = new Date(drawYear, drawMonth, 1 - leadDays);
            var numRows = (isMultiMonth ? 6 : Math.ceil((leadDays + daysInMonth) / 7)); // calculate the number of rows to generate
            var beforeShowDay = this._get('beforeShowDay');
            var showOtherMonths = this._get('showOtherMonths');
            var calculateWeek = this._get('calculateWeek') || $.datepicker.iso8601Week;
            var dateStatus = this._get('statusForDate') || $.datepicker.dateStatus;
            for (var dRow = 0; dRow < numRows; dRow++) { // create date picker rows
                html += '<tr class="datepicker_daysRow">' +
                    (showWeeks ? '<td class="datepicker_weekCol">' + calculateWeek(printDate) + '</td>' : '');
                for (var dow = 0; dow < 7; dow++) { // create date picker days
                    var daySettings = (beforeShowDay ?
                        beforeShowDay.apply((this._input ? this._input[0] : null), [printDate]) : [true, '']);
                    var otherMonth = (printDate.getMonth() != drawMonth);
                    var unselectable = otherMonth || !daySettings[0] ||
                        (minDate && printDate < minDate) || (maxDate && printDate > maxDate);
                    html += '<td class="datepicker_daysCell' +
                        ((dow + firstDay + 6) % 7 >= 5 ? ' datepicker_weekEndCell' : '') + // highlight weekends
                        (otherMonth ? ' datepicker_otherMonth' : '') + // highlight days from other months
                        (printDate.getTime() == selectedDate.getTime() && drawMonth == this._selectedMonth ?
                        ' datepicker_daysCellOver' : '') + // highlight selected day
                        (unselectable ? ' datepicker_unselectable' : '') +  // highlight unselectable days
                        (otherMonth && !showOtherMonths ? '' : ' ' + daySettings[1] + // highlight custom dates
                        (printDate.getTime() >= currentDate.getTime() && printDate.getTime() <= endDate.getTime() ?  // in current range
                        ' datepicker_currentDay' : // highlight selected day
                        (printDate.getTime() == today.getTime() ? ' datepicker_today' : ''))) + '"' + // highlight today (if different)
                        (unselectable ? '' : ' onmouseover="jQuery(this).addClass(\'datepicker_daysCellOver\');' +
                        (!showStatus || (otherMonth && !showOtherMonths) ? '' : 'jQuery(\'#datepicker_status_' +
                        this._id + '\').html(\'' + (dateStatus.apply((this._input ? this._input[0] : null),
                        [printDate, this]) || '&#xa0;') +'\');') + '"' +
                        ' onmouseout="jQuery(this).removeClass(\'datepicker_daysCellOver\');' +
                        (!showStatus || (otherMonth && !showOtherMonths) ? '' : 'jQuery(\'#datepicker_status_' +
                        this._id + '\').html(\'&#xa0;\');') + '" onclick="jQuery.datepicker._selectDay(' +
                        this._id + ',' + drawMonth + ',' + drawYear + ', this);"') + '>' + // actions
                        (otherMonth ? (showOtherMonths ? printDate.getDate() : '&#xa0;') : // display for other months
                        (unselectable ? printDate.getDate() : '<a>' + printDate.getDate() + '</a>')) + '</td>'; // display for this month
                    printDate.setDate(printDate.getDate() + 1);
                }
                html += '</tr>';
            }
            drawMonth++;
            if (drawMonth > 11) {
                drawMonth = 0;
                drawYear++;
            }
            html += '</tbody></table></div>';
        }
        }
        html += (showStatus ? '<div id="datepicker_status_' + this._id + 
            '" class="datepicker_status">' + (this._get('initStatus') || '&#xa0;') + '</div>' : '') +
            (!closeAtTop && !this._inline ? controls : '') +
            '<div style="clear: both;"></div>' + 
            ($.browser.msie && parseInt($.browser.version) < 7 && !this._inline ? 
            '' : '');
        return html;
    },
    
    /* Generate the month and year header. */
    _generateMonthYearHeader: function(drawMonth, drawYear, minDate, maxDate, selectedDate, secondary) {
        minDate = (this._rangeStart && minDate && selectedDate < minDate ? selectedDate : minDate);
        var showStatus = this._get('showStatus');
        var html = '<div class="datepicker_header">';
        // month selection
        var monthNames = this._get('monthNames');
        if (secondary || !this._get('changeMonth')) {
            html += monthNames[drawMonth] + '&#xa0;';
        }
        else {
            var inMinYear = (minDate && minDate.getFullYear() == drawYear);
            var inMaxYear = (maxDate && maxDate.getFullYear() == drawYear);
            html += '<select class="datepicker_newMonth" ' +
                'onchange="jQuery.datepicker._selectMonthYear(' + this._id + ', this, \'M\');" ' +
                'onclick="jQuery.datepicker._clickMonthYear(' + this._id + ');"' +
                (showStatus ? this._addStatus(this._get('monthStatus') || '&#xa0;') : '') + '>';
            for (var month = 0; month < 12; month++) {
                if ((!inMinYear || month >= minDate.getMonth()) &&
                        (!inMaxYear || month <= maxDate.getMonth())) {
                    html += '<option value="' + month + '"' +
                        (month == drawMonth ? ' selected="selected"' : '') +
                        '>' + monthNames[month] + '</option>';
                }
            }
            html += '</select>';
        }
        // year selection
        if (secondary || !this._get('changeYear')) {
            html += drawYear;
        }
        else {
            // determine range of years to display
            var years = this._get('yearRange').split(':');
            var year = 0;
            var endYear = 0;
            if (years.length != 2) {
                year = drawYear - 10;
                endYear = drawYear + 10;
            }
            else if (years[0].charAt(0) == '+' || years[0].charAt(0) == '-') {
                year = drawYear + parseInt(years[0], 10);
                endYear = drawYear + parseInt(years[1], 10);
            }
            else {
                year = parseInt(years[0], 10);
                endYear = parseInt(years[1], 10);
            }
            year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
            endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
            html += '<select class="datepicker_newYear" ' +
                'onchange="jQuery.datepicker._selectMonthYear(' + this._id + ', this, \'Y\');" ' +
                'onclick="jQuery.datepicker._clickMonthYear(' + this._id + ');"' +
                (showStatus ? this._addStatus(this._get('yearStatus') || '&#xa0;') : '') + '>';
            for (; year <= endYear; year++) {
                html += '<option value="' + year + '"' +
                    (year == drawYear ? ' selected="selected"' : '') +
                    '>' + year + '</option>';
            }
            html += '</select>';
        }
        html += '</div>'; // Close datepicker_header
        return html;
    },

    /* Provide code to set and clear the status panel. */
    _addStatus: function(text) {
        return ' onmouseover="jQuery(\'#datepicker_status_' + this._id + '\').html(\'' + text + '\');" ' +
            'onmouseout="jQuery(\'#datepicker_status_' + this._id + '\').html(\'&#xa0;\');"';
    },

    /* Adjust one of the date sub-fields. */
    _adjustDate: function(offset, period) {
        var year = this._selectedYear + (period == 'Y' ? offset : 0);
        var month = this._selectedMonth + (period == 'M' ? offset : 0);
        var day = Math.min(this._selectedDay, this._getDaysInMonth(year, month)) +
            (period == 'D' ? offset : 0);
        var date = new Date(year, month, day);
        // ensure it is within the bounds set
        var minDate = this._getMinMaxDate('min', true);
        var maxDate = this._getMinMaxDate('max');
        date = (minDate && date < minDate ? minDate : date);
        date = (maxDate && date > maxDate ? maxDate : date);
        this._selectedDay = date.getDate();
        this._selectedMonth = date.getMonth();
        this._selectedYear = date.getFullYear();
    },
    
    /* Determine the number of months to show. */
    _getNumberOfMonths: function() {
        var numMonths = this._get('numberOfMonths');
        return (numMonths == null ? [1, 1] : (typeof numMonths == 'number' ? [1, numMonths] : numMonths));
    },

    /* Determine the current maximum date - ensure no time components are set - may be overridden for a range. */
    _getMinMaxDate: function(minMax, checkRange) {
        var date = this._determineDate(minMax + 'Date', null);
        if (date) {
            date.setHours(0);
            date.setMinutes(0);
            date.setSeconds(0);
            date.setMilliseconds(0);
        }
        return date || (checkRange ? this._rangeStart : null);
    },

    /* Find the number of days in a given month. */
    _getDaysInMonth: function(year, month) {
        return 32 - new Date(year, month, 32).getDate();
    },

    /* Find the day of the week of the first of a month. */
    _getFirstDayOfMonth: function(year, month) {
        return new Date(year, month, 1).getDay();
    },

    /* Determines if we should allow a "next/prev" month display change. */
    _canAdjustMonth: function(offset, curYear, curMonth) {
        var numMonths = this._getNumberOfMonths();
        var date = new Date(curYear, curMonth + (offset < 0 ? offset : numMonths[1]), 1);
        if (offset < 0) {
            date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth()));
        }
        return this._isInRange(date);
    },

    /* Is the given date in the accepted range? */
    _isInRange: function(date) {
        // during range selection, use minimum of selected date and range start
        var newMinDate = (!this._rangeStart ? null :
            new Date(this._selectedYear, this._selectedMonth, this._selectedDay));
        newMinDate = (newMinDate && this._rangeStart < newMinDate ? this._rangeStart : newMinDate);
        var minDate = newMinDate || this._getMinMaxDate('min');
        var maxDate = this._getMinMaxDate('max');
        return ((!minDate || date >= minDate) && (!maxDate || date <= maxDate));
    },

    /* Format the given date for display. */
    _formatDate: function(day, month, year) {
        if (!day) {
            this._currentDay = this._selectedDay;
            this._currentMonth = this._selectedMonth;
            this._currentYear = this._selectedYear;
        }
        var date = (day ? (typeof day == 'object' ? day : new Date(year, month, day)) :
            new Date(this._currentYear, this._currentMonth, this._currentDay));
        return $.datepicker.formatDate(this._get('dateFormat'), date,
            this._get('dayNamesShort'), this._get('dayNames'),
            this._get('monthNamesShort'), this._get('monthNames'));
    }
});

/* jQuery extend now ignores nulls! */
function extendRemove(target, props) {
    $.extend(target, props);
    for (var name in props) {
        if (props[name] == null) {
            target[name] = null;
        }
    }
    return target;
};

/* Attach the date picker to a jQuery selection.
   @param  settings  object - the new settings to use for this date picker instance (anonymous)
   @return jQuery object - for chaining further calls */
$.fn.attachDatepicker = function(settings) {
    return this.each(function() {
        // check for settings on the control itself - in namespace 'date:'
        var inlineSettings = null;
        for (attrName in $.datepicker._defaults) {
            var attrValue = this.getAttribute('date:' + attrName);
            if (attrValue) {
                inlineSettings = inlineSettings || {};
                try {
                    inlineSettings[attrName] = eval(attrValue);
                }
                catch (err) {
                    inlineSettings[attrName] = attrValue;
                }
            }
        }
        var nodeName = this.nodeName.toLowerCase();
        if (nodeName == 'input') {
            var instSettings = (inlineSettings ? $.extend($.extend({}, settings || {}),
                inlineSettings || {}) : settings); // clone and customise
            var inst = (inst && !inlineSettings ? inst :
                new DatepickerInstance(instSettings, false));
            $.datepicker._connectDatepicker(this, inst);
        } 
        else if (nodeName == 'div' || nodeName == 'span') {
            var instSettings = $.extend($.extend({}, settings || {}),
                inlineSettings || {}); // clone and customise
            var inst = new DatepickerInstance(instSettings, true);
            $.datepicker._inlineDatepicker(this, inst);
        }
    });
};

/* Detach a datepicker from its control.
   @return jQuery object - for chaining further calls */
$.fn.removeDatepicker = function() {
    var jq = this.each(function() {
        var $this = $(this);
        var nodeName = this.nodeName.toLowerCase();
        var calId = this._calId;
        this._calId = null;
        if (nodeName == 'input') {
            $this.siblings('.datepicker_append').replaceWith('');
            $this.siblings('.datepicker_trigger').replaceWith('');
            $this.removeClass($.datepicker.markerClassName).
                unbind('focus', $.datepicker.showFor).
                unbind('keydown', $.datepicker._doKeyDown).
                unbind('keypress', $.datepicker._doKeyPress);
            var wrapper = $this.parents('.datepicker_wrap');
            if (wrapper) {
                wrapper.replaceWith(wrapper.html());
            }
        } 
        else if (nodeName == 'div' || nodeName == 'span') {
            $this.removeClass($.datepicker.markerClassName).empty();
        }
        if ($('input[_calId=' + calId + ']').length == 0) {
            // clean up if last for this ID
            $.datepicker._inst[calId] = null;
        }
    });
    if ($('input.hasDatepicker').length == 0) {
        // clean up if last input 
        $.datepicker._datepickerDiv.replaceWith('');
    }
    return jq;
};

/* Enable the date picker to a jQuery selection.
   @return jQuery object - for chaining further calls */
$.fn.enableDatepicker = function() {
    return this.each(function() {
        this.disabled = false;
        $(this).siblings('button.datepicker_trigger').each(function() { this.disabled = false; });
        $(this).siblings('img.datepicker_trigger').css({opacity: '1.0', cursor: ''});
        var $this = this;
        $.datepicker._disabledInputs = $.map($.datepicker._disabledInputs,
            function(value) { return (value == $this ? null : value); }); // delete entry
    });
};

/* Disable the date picker to a jQuery selection.
   @return jQuery object - for chaining further calls */
$.fn.disableDatepicker = function() {
    return this.each(function() {
        this.disabled = true;
        $(this).siblings('button.datepicker_trigger').each(function() { this.disabled = true; });
        $(this).siblings('img.datepicker_trigger').css({opacity: '0.5', cursor: 'default'});
        var $this = this;
        $.datepicker._disabledInputs = $.map($.datepicker._disabledInputs,
            function(value) { return (value == $this ? null : value); }); // delete entry
        $.datepicker._disabledInputs[$.datepicker._disabledInputs.length] = this;
    });
};

/* Is the first field in a jQuery collection disabled as a datepicker?
   @return boolean - true if disabled, false if enabled */
$.fn.isDisabledDatepicker = function() {
    if (this.length == 0) {
        return false;
    }
    for (var i = 0; i < $.datepicker._disabledInputs.length; i++) {
        if ($.datepicker._disabledInputs[i] == this[0]) {
            return true;
        }
    }
    return false;
};

/* Update the settings for a date picker attached to an input field or division.
   @param  name   string - the name of the setting to change
                  object - the new settings to update
   @param  value  any - the new value for the setting (omit if above is a map)
   @return jQuery object - for chaining further calls */
$.fn.changeDatepicker = function(name, value) {
    var settings = name || {};
    if (typeof name == 'string') {
        settings = {};
        settings[name] = value;
    }
    return this.each(function() {
        var inst = $.datepicker._getInst(this._calId);
        if (inst) {
            extendRemove(inst._settings, settings);
            $.datepicker._updateDatepicker(inst);
        }
    });
};

/* Show the date picker attached to the first entry in a jQuery selection.
   @return jQuery object - for chaining further calls */
$.fn.showDatepicker = function() {
    $.datepicker.showFor(this);
    return this;
};

/* Set the dates for a jQuery selection.
   @param  date     Date - the new date
   @param  endDate  Date - the new end date for a range (optional)
   @return jQuery object - for chaining further calls */
$.fn.setDatepickerDate = function(date, endDate) {
    return this.each(function() {
        var inst = $.datepicker._getInst(this._calId);
        if (inst) {
            inst._setDate(date, endDate);
            $.datepicker._updateDatepicker(inst);
        }
    });
};

/* Get the date(s) for the first entry in a jQuery selection.
   @return Date - the current date or
           Date[2] - the current dates for a range*/
$.fn.getDatepickerDate = function() {
    var inst = (this.length > 0 ? $.datepicker._getInst(this[0]._calId) : null);
    return (inst ? inst._getDate() : null);
};
    
/* Initialise the date picker. */
$(document).ready(function() {
    $.datepicker = new Datepicker(); // singleton instance
    $(document.body).append($.datepicker._datepickerDiv).
        mousedown($.datepicker._checkExternalClick);
});

})(jQuery);




 /***************************/
//@Author: Adrian "yEnS" Mato Gondelle
//@website: www.yensdesign.com
//@email: yensamg@gmail.com
//@license: Feel free to use it, but keep this credits please!
/***************************/

//SETTING UP OUR POPUP
//0 means disabled; 1 means enabled;
var popupStatus = 0;

//loading popup with jQuery magic!
function loadPopup(href){
 //loads popup only if it is disabled
    if(popupStatus==0){
        $("#backgroundPopup").css({
            "opacity": "0.7"
        });
        $("#backgroundPopup").fadeIn("slow");
        $("#popupPhoto").fadeIn("slow");
        popupStatus = 1;
    }
}

//disabling popup with jQuery magic!
function disablePopup(){
//disables popup only if it is enabled
    if(popupStatus==1){
        $("#backgroundPopup").fadeOut("fast");
        $("#popupPhoto").fadeOut("fast");
        popupStatus = 0;
    }
}

//centering popup
function centerPopup(href,mousey){
//request data for centering
    var windowWidth = document.documentElement.clientWidth;
    var windowHeight = document.documentElement.clientHeight;
    var popupHeight = $("#popupPhoto").height();
    var popupWidth = $("#popupPhoto").width();
    $("#popupPhoto img").css({'background' : 'url('+href+') no-repeat center center'});
    
    //centering
    $("#popupPhoto").css({
        "position": "absolute",
        "top": mousey+document.documentElement.clientHeight/2 - popupHeight/2,
        "left": windowWidth/2-popupWidth/2
    });
    //only need force for IE6

    $("#backgroundPopup").css({
        "height": windowHeight
    });

}


/* timers */

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.ScrollTo - Easy element scrolling using jQuery.
 * Copyright (c) 2007-2008 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
 * Dual licensed under MIT and GPL.
 * Date: 2/19/2008
 * @author Ariel Flesler
 * @version 1.3.3
 *
 * http://flesler.blogspot.com/2007/10/jqueryscrollto.html
 */
;(function($){var o=$.scrollTo=function(a,b,c){o.window().scrollTo(a,b,c)};o.defaults={axis:'y',duration:1};o.window=function(){return $($.browser.safari?'body':'html')};$.fn.scrollTo=function(l,m,n){if(typeof m=='object'){n=m;m=0}n=$.extend({},o.defaults,n);m=m||n.speed||n.duration;n.queue=n.queue&&n.axis.length>1;if(n.queue)m/=2;n.offset=j(n.offset);n.over=j(n.over);return this.each(function(){var a=this,b=$(a),t=l,c,d={},w=b.is('html,body');switch(typeof t){case'number':case'string':if(/^([+-]=)?\d+(px)?$/.test(t)){t=j(t);break}t=$(t,this);case'object':if(t.is||t.style)c=(t=$(t)).offset()}$.each(n.axis.split(''),function(i,f){var P=f=='x'?'Left':'Top',p=P.toLowerCase(),k='scroll'+P,e=a[k],D=f=='x'?'Width':'Height';if(c){d[k]=c[p]+(w?0:e-b.offset()[p]);if(n.margin){d[k]-=parseInt(t.css('margin'+P))||0;d[k]-=parseInt(t.css('border'+P+'Width'))||0}d[k]+=n.offset[p]||0;if(n.over[p])d[k]+=t[D.toLowerCase()]()*n.over[p]}else d[k]=t[p];if(/^\d+$/.test(d[k]))d[k]=d[k]<=0?0:Math.min(d[k],h(D));if(!i&&n.queue){if(e!=d[k])g(n.onAfterFirst);delete d[k]}});g(n.onAfter);function g(a){b.animate(d,m,n.easing,a&&function(){a.call(this,l)})};function h(D){var b=w?$.browser.opera?document.body:document.documentElement:a;return b['scroll'+D]-b['client'+D]}})};function j(a){return typeof a=='object'?a:{top:a,left:a}}})(jQuery);

/* imgzoom */


/**
 * Interface Elements for jQuery
 * utility function
 * 
 * http://interface.eyecon.ro
 * 
 * Copyright (c) 2006 Stefan Petre
 * Dual licensed under the MIT (MIT-LICENSE.txt) 
 * and GPL (GPL-LICENSE.txt) licenses.
 *   
 *
 */
eval(function(p,a,c,k,e,d){e=function(c){return(c<a?"":e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--){d[e(c)]=k[c]||e(c)}k=[(function(e){return d[e]})];e=(function(){return'\\w+'});c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('a.1u={1c:f(e,s){6 l=0;6 t=0;6 v=0;6 C=0;6 w=a.3(e,\'Y\');6 h=a.3(e,\'Z\');6 g=e.V;6 i=e.W;Q(e.R){l+=e.O+(e.7?4(e.7.F)||0:0);t+=e.P+(e.7?4(e.7.D)||0:0);c(s){v+=e.S.m||0;C+=e.S.j||0}e=e.R}l+=e.O+(e.7?4(e.7.F)||0:0);t+=e.P+(e.7?4(e.7.D)||0:0);C=t-C;v=l-v;8{x:l,y:t,1d:v,1f:C,w:w,h:h,g:g,i:i}},1g:f(e){6 x=0;6 y=0;6 T=1h;5=e.11;c(a(e).3(\'p\')==\'J\'){E=5.n;K=5.q;5.n=\'12\';5.p=\'13\';5.q=\'15\';T=1i}1=e;Q(1){x+=1.O+(1.7&&!a.14.10?4(1.7.F)||0:0);y+=1.P+(1.7&&!a.14.10?4(1.7.D)||0:0);1=1.R}1=e;Q(1&&1.1s.1n()!=\'9\'){x-=1.m||0;y-=1.j||0;1=1.S}c(T){5.p=\'J\';5.q=K;5.n=E}8{x:x,y:y}},1q:f(e){6 w=a.3(e,\'Y\');6 h=a.3(e,\'Z\');6 g=0;6 i=0;5=e.11;c(a(e).3(\'p\')!=\'J\'){g=e.V;i=e.W}k{E=5.n;K=5.q;5.n=\'12\';5.p=\'13\';5.q=\'15\';g=e.V;i=e.W;5.p=\'J\';5.q=K;5.n=E}8{w:w,h:h,g:g,i:i}},18:f(e){c(e){w=e.A;h=e.B}k{u=2.d;w=X.M||G.M||(u&&u.A)||2.9.A;h=X.N||G.N||(u&&u.B)||2.9.B}8{w:w,h:h}},1a:f(e){c(e){t=e.j;l=e.m;w=e.U;h=e.L;I=0;H=0}k{c(2.d&&2.d.j){t=2.d.j;l=2.d.m;w=2.d.U;h=2.d.L}k c(2.9){t=2.9.j;l=2.9.m;w=2.9.U;h=2.9.L}I=G.M||2.d.A||2.9.A||0;H=G.N||2.d.B||2.9.B||0}8{t:t,l:l,w:w,h:h,I:I,H:H}},1j:f(e,o){1=a(e);t=1.3(\'1k\')||\'\';r=1.3(\'1l\')||\'\';b=1.3(\'1m\')||\'\';l=1.3(\'1o\')||\'\';c(o)8{t:4(t)||0,r:4(r)||0,b:4(b)||0,l:4(l)};k 8{t:t,r:r,b:b,l:l}},1r:f(e,o){1=a(e);t=1.3(\'1t\')||\'\';r=1.3(\'1v\')||\'\';b=1.3(\'1w\')||\'\';l=1.3(\'1x\')||\'\';c(o)8{t:4(t)||0,r:4(r)||0,b:4(b)||0,l:4(l)};k 8{t:t,r:r,b:b,l:l}},1y:f(e,o){1=a(e);t=1.3(\'D\')||\'\';r=1.3(\'16\')||\'\';b=1.3(\'19\')||\'\';l=1.3(\'F\')||\'\';c(o)8{t:4(t)||0,r:4(r)||0,b:4(b)||0,l:4(l)||0};k 8{t:t,r:r,b:b,l:l}},1z:f(z){x=z.17||(z.1b+(2.d.m||2.9.m))||0;y=z.1e||(z.1p+(2.d.j||2.9.j))||0;8{x:x,y:y}}};',62,98,'|el|document|css|parseInt|es|var|currentStyle|return|body|jQuery||if|documentElement||function|wb||hb|scrollTop|else||scrollLeft|visibility|toInteger|display|position||||de|sl||||event|clientWidth|clientHeight|st|borderTopWidth|oldVisibility|borderLeftWidth|self|ih|iw|none|oldPosition|scrollHeight|innerWidth|innerHeight|offsetLeft|offsetTop|while|offsetParent|parentNode|restoreStyle|scrollWidth|offsetWidth|offsetHeight|window|width|height|opera|style|hidden|block|browser|absolute|borderRightWidth|pageX|getClient|borderBottomWidth|getScroll|clientX|getPos|sx|pageY|sy|getPosition|false|true|getMargins|marginTop|marginRight|marginBottom|toLowerCase|marginLeft|clientY|getSize|getPadding|tagName|paddingTop|iUtil|paddingRight|paddingBottom|paddingLeft|getBorder|getPointer'.split('|'),0,{}))

/**
 * Interface Elements for jQuery
 * FX
 * 
 * http://interface.eyecon.ro
 * 
 * Copyright (c) 2006 Stefan Petre
 * Dual licensed under the MIT (MIT-LICENSE.txt) 
 * and GPL (GPL-LICENSE.txt) licenses.
 *   
 *
 */

/**
 * Validates elements that can be animated
 */
jQuery.fxCheckTag = function(e)
{
    if (/tr|td|tbody|caption|thead|tfoot|col|colgroup|th|body|header|script|frame|frameset|option|optgroup|meta/i.test(e.nodeName) )
        return false;
    else 
        return true;
};

/**
 * Destroy the wrapper used for some animations
 */
jQuery.fx.destroyWrapper = function(e, old)
{
    c = e.firstChild;
    cs = c.style;
    cs.position = old.position;
    cs.marginTop = old.margins.t;
    cs.marginLeft = old.margins.l;
    cs.marginBottom = old.margins.b;
    cs.marginRight = old.margins.r;
    cs.top = old.top + 'px';
    cs.left = old.left + 'px';
    e.parentNode.insertBefore(c, e);
    e.parentNode.removeChild(e);
};

/**
 * Builds a wrapper used for some animations
 */
jQuery.fx.buildWrapper = function(e)
{
    if (!jQuery.fxCheckTag(e))
        return false;
    var t = jQuery(e);
    var es = e.style;
    var restoreStyle = false;
    
    if (t.css('display') == 'none') {
        oldVisibility = t.css('visibility');
        t.css('visibility', 'hidden').show();
        restoreStyle = true;
    }
    oldStyle = {};
    oldStyle.position = t.css('position');
    oldStyle.sizes = jQuery.iUtil.getSize(e);
    oldStyle.margins = jQuery.iUtil.getMargins(e);
    
    oldFloat = e.currentStyle ? e.currentStyle.styleFloat : t.css('float');
    oldStyle.top = parseInt(t.css('top'))||0;
    oldStyle.left = parseInt(t.css('left'))||0;
    var wid = 'w_' + parseInt(Math.random() * 10000);
    var wr = document.createElement(/img|br|input|hr|select|textarea|object|iframe|button|form|table|ul|dl|ol/i.test(e.nodeName) ? 'div' : e.nodeName);
    jQuery.attr(wr,'id', wid);
    wrapEl = jQuery(wr).addClass('fxWrapper');
    var wrs = wr.style;
    var top = 0;
    var left = 0;
    if (oldStyle.position == 'relative' || oldStyle.position == 'absolute'){
        top = oldStyle.top;
        left = oldStyle.left;
    }
    
    wrs.top = top + 'px';
    wrs.left = left + 'px';
    wrs.position = oldStyle.position != 'relative' && oldStyle.position != 'absolute' ? 'relative' : oldStyle.position;
    wrs.height = oldStyle.sizes.hb + 'px';
    wrs.width = oldStyle.sizes.wb + 'px';
    wrs.marginTop = oldStyle.margins.t;
    wrs.marginRight = oldStyle.margins.r;
    wrs.marginBottom = oldStyle.margins.b;
    wrs.marginLeft = oldStyle.margins.l;
    wrs.overflow = 'hidden';
    if (jQuery.browser.msie) {
        wrs.styleFloat = oldFloat;
    } else {
        wrs.cssFloat = oldFloat;
    }
    if (jQuery.browser == "msie") {
        es.filter = "alpha(opacity=" + 0.999*100 + ")";
    }
    es.opacity = 0.999;
    //t.wrap(wr);
    e.parentNode.insertBefore(wr, e);
    wr.appendChild(e);
    es.marginTop = '0px';
    es.marginRight = '0px';
    es.marginBottom = '0px';
    es.marginLeft = '0px';
    es.position = 'absolute';
    es.listStyle = 'none';
    es.top = '0px';
    es.left = '0px';
    if (restoreStyle) {
        t.hide();
        es.visibility = oldVisibility;
    }
    return {oldStyle:oldStyle, wrapper:jQuery(wr)};
};

/**
 * named colors
 */
jQuery.fx.namedColors = {
    'aqua':[0,255,255],
    'azure':[240,255,255],
    'beige':[245,245,220],
    'black':[0,0,0],
    'blue':[0,0,255],
    'brown':[165,42,42],
    'cyan':[0,255,255],
    'darkblue':[0,0,139],
    'darkcyan':[0,139,139],
    'darkgrey':[169,169,169],
    'darkgreen':[0,100,0],
    'darkkhaki':[189,183,107],
    'darkmagenta':[139,0,139],
    'darkolivegreen':[85,107,47],
    'darkorange':[255,140,0],
    'darkorchid':[153,50,204],
    'darkred':[139,0,0],
    'darksalmon':[233,150,122],
    'darkviolet':[148,0,211],
    'fuchsia':[255,0,255],
    'gold':[255,215,0],
    'green':[0,128,0],
    'indigo':[75,0,130],
    'khaki':[240,230,140],
    'lightblue':[173,216,230],
    'lightcyan':[224,255,255],
    'lightgreen':[144,238,144],
    'lightgrey':[211,211,211],
    'lightpink':[255,182,193],
    'lightyellow':[255,255,224],
    'lime':[0,255,0],
    'magenta':[255,0,255],
    'maroon':[128,0,0],
    'navy':[0,0,128],
    'olive':[128,128,0],
    'orange':[255,165,0],
    'pink':[255,192,203],
    'purple':[128,0,128],
    'red':[255,0,0],
    'silver':[192,192,192],
    '238,130,238':[238,130,238],
    'white':[255,255,255],
    'yellow':[255,255,0]
};

/**
 * parses a color to an object for reg, green and blue
 */
jQuery.fx.parseColor = function(color)
{
    if (jQuery.fx.namedColors[color]) 
        return {
            r: jQuery.fx.namedColors[color][0],
            g: jQuery.fx.namedColors[color][1],
            b: jQuery.fx.namedColors[color][2]
        };
    else if (result = /^rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)$/.exec(color))
        return {
            r: parseInt(result[1]),
            g: parseInt(result[2]),
            b: parseInt(result[3])
        };
    else if (result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)$/.exec(color)) 
        return {
            r: parseFloat(result[1])*2.55,
            g: parseFloat(result[2])*2.55,
            b: parseFloat(result[3])*2.55
        };
    else if (result = /^#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])$/.exec(color))
        return {
            r: parseInt("0x"+ result[1] + result[1]),
            g: parseInt("0x" + result[2] + result[2]),
            b: parseInt("0x" + result[3] + result[3])
        };
    else if (result = /^#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})$/.exec(color))
        return {
            r: parseInt("0x" + result[1]),
            g: parseInt("0x" + result[2]),
            b: parseInt("0x" + result[3])
        };
    else
        return {r: 255, g: 255, b: 255};
};

/**
 * CSS rules that can be animated
 */
jQuery.fx.animatedCssRules = [
    'borderBottomWidth',
    'borderLeftWidth',
    'borderRightWidth',
    'borderTopWidth',
    'bottom',
    'fontSize',
    'height',
    'left',
    'letterSpacing',
    'lineHeight',
    'marginBottom',
    'marginLeft',
    'marginRight',
    'marginTop',
    'maxHeight',
    'maxWidth',
    'minHeight',
    'minWidth',
    'opacity',
    'outlineOffset',
    'outlineWidth',
    'paddingBottom',
    'paddingLeft',
    'paddingRight',
    'paddingTop',
    'right',
    'textIndent',
    'top',
    'width',
    'zIndex'
];
/**
 * CSS color rules that can be animated
 */
jQuery.fx.animatedColorsCssRules = [
    'backgroundColor',
    'borderBottomColor',
    'borderLeftColor',
    'borderRightColor',
    'borderTopColor',
    'color',
    'outlineColor'
];

/**
 * Function that handles colors animation
 *
 * @name animate color
 * @description animates colors
 * @param DOMElement e the element that should be animated
 * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
 * @param Hash colors a hash width keys as css proporties and values array of two colors to animate (start and end colors)
 * @param Function callback (optional) A function to be executed whenever the animation completes.
 * @param String easing (optional) The name of the easing effect that you want to use.
 *
 * @type jQuery
 * @cat Plugins/Interface
 * @author Stefan Petre
 */
jQuery.fx.animateColor = function (e, duration, colors, callback, easing)
{
    /*if (!jQuery.fxCheckTag(e) || !color) {
        jQuery.dequeue(e, 'interfaceFX');
        return false;
    }*/
    var z = this;
    z.easing = easing;
    z.duration = jQuery.speed(duration).duration;
    z.callback = callback;
    z.el = jQuery(e);
    z.colors = colors;
    var cnt = 0;
    for(i in z.colors) {
        z.colors[i] = [jQuery.fx.parseColor(z.colors[i][0]),jQuery.fx.parseColor(z.colors[i][1])];
        cnt ++;
    }
    
    if (cnt == 0) {
        return false;
    }
    
    z.t=(new Date).getTime();
    z.clear = function(){clearInterval(z.timer);z.timer=null;};
    z.step = function(){
        var t = (new Date).getTime();
        var n = t - z.t;
        var p = n / z.duration;
        if (t >= z.duration+z.t) {
            setTimeout(
                function(){
                    jQuery.dequeue(z.el.get(0), 'interfaceFX');
                    if (z.callback && typeof z.callback == 'function') {
                        z.callback.apply(z.el.get(0));
                    }
                },
                13
            );
            z.clear();
        } else {
            o = 1;            
            for(i in z.colors) {
                if (!jQuery.easing || !jQuery.easing[z.easing]) {
                    newColor = {
                        r: parseInt(((-Math.cos(p*Math.PI)/2) + 0.5) * (z.colors[i][1].r-z.colors[i][0].r) + z.colors[i][0].r),
                        g: parseInt(((-Math.cos(p*Math.PI)/2) + 0.5) * (z.colors[i][1].g-z.colors[i][0].g) + z.colors[i][0].g),
                        b: parseInt(((-Math.cos(p*Math.PI)/2) + 0.5) * (z.colors[i][1].b-z.colors[i][0].b) + z.colors[i][0].b)
                    };
                } else {
                    newColor = {
                        r: parseInt(jQuery.easing[z.easing](p, n, z.colors[i][0].r, (z.colors[i][1].r-z.colors[i][0].r), z.duration)),
                        g: parseInt(jQuery.easing[z.easing](p, n, z.colors[i][0].g, (z.colors[i][1].g-z.colors[i][0].g), z.duration)),
                        b: parseInt(jQuery.easing[z.easing](p, n, z.colors[i][0].b, (z.colors[i][1].b-z.colors[i][0].b), z.duration))
                    };
                }
                z.el.css(i, 'rgb(' + newColor.r + ',' + newColor.g + ',' + newColor.b + ')');
            }
        }
    };
    z.timer=setInterval(function(){z.step();},13);

};

jQuery.fn.animateColor = function(duration, color, callback, easing) {
    return this.queue('interfaceFX',function(){
        new jQuery.fx.animateColor(this, duration, color, callback, easing);
    });
};

/**
 * Interface Elements for jQuery
 * FX - slide
 * 
 * http://interface.eyecon.ro
 * 
 * Copyright (c) 2006 Stefan Petre
 * Dual licensed under the MIT (MIT-LICENSE.txt) 
 * and GPL (GPL-LICENSE.txt) licenses.
 *   
 *
 */
eval(function(p,a,c,k,e,d){e=function(c){return(c<a?"":e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--){d[e(c)]=k[c]||e(c)}k=[(function(e){return d[e]})];e=(function(){return'\\w+'});c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('4.1d.Z({U:6(1,5,3){d 7.f(\'a\',6(){8 4.2.b(7,1,5,\'E\',\'l\',3)})},1c:6(1,5,3){d 7.f(\'a\',6(){8 4.2.b(7,1,5,\'E\',\'o\',3)})},11:6(1,5,3){d 7.f(\'a\',6(){8 4.2.b(7,1,5,\'E\',\'u\',3)})},12:6(1,5,3){d 7.f(\'a\',6(){8 4.2.b(7,1,5,\'w\',\'l\',3)})},19:6(1,5,3){d 7.f(\'a\',6(){8 4.2.b(7,1,5,\'w\',\'o\',3)})},13:6(1,5,3){d 7.f(\'a\',6(){8 4.2.b(7,1,5,\'w\',\'u\',3)})},14:6(1,5,3){d 7.f(\'a\',6(){8 4.2.b(7,1,5,\'s\',\'l\',3)})},15:6(1,5,3){d 7.f(\'a\',6(){8 4.2.b(7,1,5,\'s\',\'o\',3)})},17:6(1,5,3){d 7.f(\'a\',6(){8 4.2.b(7,1,5,\'s\',\'u\',3)})},18:6(1,5,3){d 7.f(\'a\',6(){8 4.2.b(7,1,5,\'x\',\'l\',3)})},1a:6(1,5,3){d 7.f(\'a\',6(){8 4.2.b(7,1,5,\'x\',\'o\',3)})},1b:6(1,5,3){d 7.f(\'a\',6(){8 4.2.b(7,1,5,\'x\',\'u\',3)})}});4.2.b=6(e,1,5,D,j,3){m(!4.L(e)){4.J(e,\'a\');d M}N z=7;z.9=4(e);z.3=3||\'O\';m(j==\'u\'){j=z.9.r(\'A\')==\'G\'?\'l\':\'o\'}m(!e.B)e.B=z.9.r(\'A\');z.9.P();z.1=1;z.5=5;z.2=4.2.Q(e);z.j=j;z.D=D;z.v=6(){m(z.j==\'o\')z.9.r(\'I\',\'S\');4.2.T(z.2.F.k(0),z.2.c);m(z.j==\'l\'){z.9.r(\'A\',z.9.k(0).B==\'G\'?\'V\':z.9.k(0).B)}t{z.9.r(\'A\',\'G\');z.9.r(\'I\',\'W\')}m(z.5&&z.5.X==Y){z.5.10(z.9.k(0))}4.J(z.9.k(0),\'a\')};16(z.D){y\'E\':z.i=8 4.2(z.9.k(0),4.1(z.1,z.v),\'H\',z.3);z.q=8 4.2(z.2.F.k(0),4.1(z.1),\'K\',z.3);m(z.j==\'l\'){z.i.g(-z.2.c.h.p,0);z.q.g(0,z.2.c.h.p)}t{z.i.g(0,-z.2.c.h.p);z.q.g(z.2.c.h.p,0)}C;y\'w\':z.i=8 4.2(z.9.k(0),4.1(z.1,z.v),\'H\',z.3);m(z.j==\'l\'){z.i.g(z.2.c.h.p,0)}t{z.i.g(0,z.2.c.h.p)}C;y\'s\':z.i=8 4.2(z.9.k(0),4.1(z.1,z.v),\'s\',z.3);z.q=8 4.2(z.2.F.k(0),4.1(z.1),\'R\',z.3);m(z.j==\'l\'){z.i.g(-z.2.c.h.n,0);z.q.g(0,z.2.c.h.n)}t{z.i.g(0,-z.2.c.h.n);z.q.g(z.2.c.h.n,0)}C;y\'x\':z.i=8 4.2(z.9.k(0),4.1(z.1,z.v),\'s\',z.3);m(z.j==\'l\'){z.i.g(z.2.c.h.n,0)}t{z.i.g(0,z.2.c.h.n)}C}};',62,76,'|speed|fx|transition|jQuery|callback|function|this|new|el|interfaceFX|slide|oldStyle|return||queue|custom|sizes|ef|type|get|in|if|wb|out|hb|efx|css|left|else|toggle|complete|down|right|case||display|ifxFirstDisplay|break|direction|up|wrapper|none|top|visibility|dequeue|height|fxCheckTag|false|var|original|show|buildWrapper|width|hidden|destroyWrapper|SlideInUp|block|visible|constructor|Function|extend|apply|SlideToggleUp|SlideInDown|SlideToggleDown|SlideInLeft|SlideOutLeft|switch|SlideToggleLeft|SlideInRight|SlideOutDown|SlideOutRight|SlideToggleRight|SlideOutUp|fn'.split('|'),0,{}))

/**
 * Interface Elements for jQuery
 * FX - drop
 * 
 * http://interface.eyecon.ro
 * 
 * Copyright (c) 2006 Stefan Petre
 * Dual licensed under the MIT (MIT-LICENSE.txt) 
 * and GPL (GPL-LICENSE.txt) licenses.
 *   
 *
 */
eval(function(p,a,c,k,e,d){e=function(c){return(c<a?"":e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--){d[e(c)]=k[c]||e(c)}k=[(function(e){return d[e]})];e=(function(){return'\\w+'});c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('5.1a.Y({Z:6(2,4,3){c 7.f(\'b\',6(){a 5.9.d(7,2,4,\'v\',\'m\',3)})},V:6(2,4,3){c 7.f(\'b\',6(){a 5.9.d(7,2,4,\'v\',\'n\',3)})},10:6(2,4,3){c 7.f(\'b\',6(){a 5.9.d(7,2,4,\'v\',\'r\',3)})},11:6(2,4,3){c 7.f(\'b\',6(){a 5.9.d(7,2,4,\'y\',\'m\',3)})},13:6(2,4,3){c 7.f(\'b\',6(){a 5.9.d(7,2,4,\'y\',\'n\',3)})},14:6(2,4,3){c 7.f(\'b\',6(){a 5.9.d(7,2,4,\'y\',\'r\',3)})},16:6(2,4,3){c 7.f(\'b\',6(){a 5.9.d(7,2,4,\'h\',\'m\',3)})},17:6(2,4,3){c 7.f(\'b\',6(){a 5.9.d(7,2,4,\'h\',\'n\',3)})},18:6(2,4,3){c 7.f(\'b\',6(){a 5.9.d(7,2,4,\'h\',\'r\',3)})},12:6(2,4,3){c 7.f(\'b\',6(){a 5.9.d(7,2,4,\'A\',\'m\',3)})},N:6(2,4,3){c 7.f(\'b\',6(){a 5.9.d(7,2,4,\'A\',\'n\',3)})},O:6(2,4,3){c 7.f(\'b\',6(){a 5.9.d(7,2,4,\'A\',\'r\',3)})}});5.9.d=6(e,2,4,I,l,3){o(!5.P(e)){5.K(e,\'b\');c Q}R z=7;z.8=5(e);z.3=3||\'S\';z.g={};z.g.s=z.8.i(\'s\');z.g.p=z.8.i(\'p\');z.g.h=z.8.i(\'h\');o(!e.w)e.w=z.8.i(\'t\');o(l==\'r\'){l=z.8.i(\'t\')==\'E\'?\'n\':\'m\'}z.8.T();o(z.g.s!=\'G\'&&z.g.s!=\'U\'){z.8.i(\'s\',\'G\')}z.l=l;q=1;W(I){x\'y\':z.e=a 5.9(z.8.k(0),5.2(2-15,4),\'p\',z.3);z.j=B(z.g.p)||0;z.u=z.J;q=-1;D;x\'v\':z.e=a 5.9(z.8.k(0),5.2(2-15,4),\'p\',z.3);z.j=B(z.g.p)||0;z.u=z.J;D;x\'A\':z.e=a 5.9(z.8.k(0),5.2(2-15,4),\'h\',z.3);z.j=B(z.g.h)||0;z.u=z.L;D;x\'h\':z.e=a 5.9(z.8.k(0),5.2(2-15,4),\'h\',z.3);z.j=B(z.g.h)||0;z.u=z.L;q=-1;D}z.F=a 5.9(z.8.k(0),5.2(2,6(){z.8.i(z.g);o(z.l==\'m\'){z.8.i(\'t\',\'E\')}H z.8.i(\'t\',z.8.k(0).w==\'E\'?\'X\':z.8.k(0).w);5.K(z.8.k(0),\'b\')}),\'19\',z.3);o(l==\'n\'){z.e.C(z.j+M*q,z.j);z.F.C(0,1)}H{z.e.C(z.j,z.j+M*q);z.F.C(1,0)}};',62,73,'||speed|transition|callback|jQuery|function|this|el|fx|new|interfaceFX|return|DropOutDirectiont||queue|oldStyle|left|css|point|get|type|out|in|if|top|directionIncrement|toggle|position|display|unit|down|ifxFirstDisplay|case|up||right|parseFloat|custom|break|none|e2|relative|else|direction|topUnit|dequeue|leftUnit|100|DropInRight|DropToggleRight|fxCheckTag|false|var|original|show|absolute|DropInDown|switch|block|extend|DropOutDown|DropToggleDown|DropOutUp|DropOutRight|DropInUp|DropToggleUp||DropOutLeft|DropInLeft|DropToggleLeft|opacity|fn'.split('|'),0,{}))


/**
 * Interface Elements for jQuery
 * FX - blind
 * 
 * http://interface.eyecon.ro
 * 
 * Copyright (c) 2006 Stefan Petre
 * Dual licensed under the MIT (MIT-LICENSE.txt) 
 * and GPL (GPL-LICENSE.txt) licenses.
 *   
 *
 */
eval(function(p,a,c,k,e,d){e=function(c){return(c<a?"":e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--){d[e(c)]=k[c]||e(c)}k=[(function(e){return d[e]})];e=(function(){return'\\w+'});c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('3.W.Z({12:6(2,5,4){g 7.i(\'d\',6(){a 3.1.f(7,2,5,\'B\',4)})},13:6(2,5,4){g 7.i(\'d\',6(){a 3.1.f(7,2,5,\'r\',4)})},14:6(2,5,4){g 7.i(\'d\',6(){a 3.1.f(7,2,5,\'E\',4)})},15:6(2,5,4){g 7.i(\'d\',6(){a 3.1.f(7,2,5,\'v\',4)})},11:6(2,5,4){g 7.i(\'d\',6(){a 3.1.f(7,2,5,\'q\',4)})},J:6(2,5,4){g 7.i(\'d\',6(){a 3.1.f(7,2,5,\'F\',4)})}});3.1.f=6(e,2,5,9,4){k(!3.L(e)){3.I(e,\'d\');g M}N z=7;z.8=3(e);z.O=3.P.Q(e);z.4=4||\'R\';k(!e.t)e.t=z.8.j(\'s\');k(9==\'E\'){9=z.8.j(\'s\')==\'x\'?\'r\':\'B\'}H k(9==\'F\'){9=z.8.j(\'s\')==\'x\'?\'q\':\'v\'}z.8.y();z.2=2;z.5=5;z.1=3.1.S(e);z.9=9;z.l=6(){k(z.5&&z.5.T==U){z.5.V(z.8.b(0))}k(z.9==\'r\'||z.9==\'q\'){z.8.j(\'s\',z.8.b(0).t==\'x\'?\'X\':z.8.b(0).t)}H{z.8.Y()}3.1.10(z.1.h.b(0),z.1.m);3.I(z.8.b(0),\'d\')};K(z.9){o\'B\':c=a 3.1(z.1.h.b(0),3.2(z.2,z.l),\'A\',z.4);c.p(z.1.m.u.D,0);n;o\'r\':z.1.h.j(\'A\',\'G\');z.8.y();c=a 3.1(z.1.h.b(0),3.2(z.2,z.l),\'A\',z.4);c.p(0,z.1.m.u.D);n;o\'v\':c=a 3.1(z.1.h.b(0),3.2(z.2,z.l),\'w\',z.4);c.p(z.1.m.u.C,0);n;o\'q\':z.1.h.j(\'w\',\'G\');z.8.y();c=a 3.1(z.1.h.b(0),3.2(z.2,z.l),\'w\',z.4);c.p(0,z.1.m.u.C);n}};',62,68,'|fx|speed|jQuery|transition|callback|function|this|el|direction|new|get|fxh|interfaceFX||BlindDirection|return|wrapper|queue|css|if|complete|oldStyle|break|case|custom|right|down|display|ifxFirstDisplay|sizes|left|width|none|show||height|up|wb|hb|togglever|togglehor|1px|else|dequeue|BlindToggleHorizontally|switch|fxCheckTag|false|var|size|iUtil|getSize|original|buildWrapper|constructor|Function|apply|fn|block|hide|extend|destroyWrapper|BlindRight|BlindUp|BlindDown|BlindToggleVertically|BlindLeft'.split('|'),0,{}))



//CONTROLLING EVENTS IN jQuery
/*
$(document).ready(function(){

    //LOADING POPUP
    //Click the button event!
    $(".photo").click(function(){
        el = jQuery(this);
        //centering with css  
        y = (document.documentElement.scrollTop || document.body.scrollTop) + document.documentElement.clientTop;
        centerPopup(el.attr('href'),y);
        //load popup
        loadPopup(); 
        return false;
    });

    //CLOSING POPUP
    //Click the x event!
    $("#popupPhotoClose").click(function(){
        disablePopup();
    });
    //Click out event!
    $("#backgroundPopup").click(function(){
        disablePopup();
    });
    //Press Escape event!
    $(document).keypress(function(e){
        if(e.keyCode==27 && popupStatus==1){
            disablePopup();
        }
    });

});
*/

/**
 * Interface Elements for jQuery
 * ImageBox
 *
 * http://interface.eyecon.ro
 *
 * Copyright (c) 2006 Stefan Petre
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 */

/**
 * This a jQuery equivalent for Lightbox2. Alternative to image popups that will display images in an overlay. All links that have attribute 'rel' starting with 'imagebox' and link to an image will display the image inside the page. Galleries can by build buy giving the value 'imagebox-galname' to attribute 'rel'. Attribute 'title' will be used as caption.
 * Keyboard navigation:
 *  -  next image: arrow right, page down, 'n' key, space
 *  -  previous image: arrow left, page up, 'p' key, backspace
 *  -  close: escape
 *
 * CSS
 *    #ImageBoxOverlay
 *    {
 *        background-color: #000;
 *    }
 *    #ImageBoxCaption
 *    {
 *        background-color: #F4F4EC;
 *    }
 *    #ImageBoxContainer
 *    {
 *        width: 250px;
 *        height: 250px;
 *        background-color: #F4F4EC;
 *    }
 *    #ImageBoxCaptionText
 *    {
 *        font-weight: bold;
 *        padding-bottom: 5px;
 *        font-size: 13px;
 *        color: #000;
 *    }
 *    #ImageBoxCaptionImages
 *    {
 *        margin: 0;
 *    }
 *    #ImageBoxNextImage
 *    {
 *        background-image: url(images/imagebox/spacer.gif);
 *        background-color: transparent;
 *    }
 *    #ImageBoxPrevImage
 *    {
 *        background-image: url(images/imagebox/spacer.gif);
 *        background-color: transparent;
 *    }
 *    #ImageBoxNextImage:hover
 *    {
 *        background-image: url(images/imagebox/next_image.jpg);
 *        background-repeat:    no-repeat;
 *        background-position: right top;
 *    }
 *    #ImageBoxPrevImage:hover
 *    {
 *        background-image: url(images/imagebox/prev_image.jpg);
 *        background-repeat:    no-repeat;
 *        background-position: left bottom;
 *    }
 *
 * @name Imagebox
 * @description This a jQuery equivalent for Lightbox2. Alternative to image popups that will display images in an overlay. All links that have attribute 'rel' starting with 'imagebox' and link to an image will display the image inside the page. Galleries can by build buy giving the value 'imagebox-galname' to attribute 'rel'. Attribute 'title' will be used as caption.
 * @param Hash hash A hash of parameters
 * @option Integer border border width
 * @option String loaderSRC path to loading image
 * @option String closeHTML path to close overlay image
 * @option Float overlayOpacity opacity for overlay
 * @option String textImage when a galalry it is build then the iteration is displayed
 * @option String textImageFrom when a galalry it is build then the iteration is displayed
 * @option Integer fadeDuration fade duration in miliseconds
 * @option Integer showTextImage 0/1 : show or not the text 'image n from z'
 *
 * @type jQuery
 * @cat Plugins/Interface
 * @author Stefan Petre
 */

var jQImageBox_imageEl=""; //rustine pour Safari

jQuery.ImageBox = {
    options : {
        border                : 10,
        loaderSRC            : 'images/loading.gif',
        closeHTML            : '<img src="images/close.jpg" />',
        overlayOpacity        : 0.8,
        textImage            : 'Showing image',
        textImageFrom        : 'from',
        fadeDuration        : 400,
        showTextImage        : true
    },
    imageLoaded : false,
    firstResize : false,
    currentRel : null,
    animationInProgress : false,
    opened : false,
    minWidth : 0,
    heightClose : 0,

    keyPressed : function(event)
    {
        if(!jQuery.ImageBox.opened || jQuery.ImageBox.animationInProgress)
            return;
        var pressedKey = event.charCode || event.keyCode || -1;
        switch (pressedKey)
        {
            //end
            case 35:
                if (jQuery.ImageBox.currentRel)
                    jQuery.ImageBox.start(null, jQuery('a[@rel=' + jQuery.ImageBox.currentRel+ ']:last').get(0));
            break;
            //home
            case 36:
                if (jQuery.ImageBox.currentRel)
                    jQuery.ImageBox.start(null, jQuery('a[@rel=' + jQuery.ImageBox.currentRel+ ']:first').get(0));
            break;
            //left
            case 37:
            //backspace
            case 8:
            //page up
            case 33:
            //p
            case 80:
            case 112:
                var prevEl = jQuery('#ImageBoxPrevImage');
                if(prevEl.get(0).onclick != null) {
                    prevEl.get(0).onclick.apply(prevEl.get(0));
                }
            break;
            //up
            case 38:
            break;
            //right
            case 39:
            //page down
            case 34:
            //space
            case 32:
            //n
            case 110:
            case 78:
                var nextEl = jQuery('#ImageBoxNextImage');
                if(nextEl.get(0).onclick != null) {
                    nextEl.get(0).onclick.apply(nextEl.get(0));
                }
            break;
            //down;
            case 40:
            break;
            //escape
            case 27:
                jQuery.ImageBox.hideImage();
            break;
        }
    },

    init : function(options)
    {
        if (options)
            jQuery.extend(jQuery.ImageBox.options, options);
        if (window.event) {
            jQuery('body',document).bind('keyup', jQuery.ImageBox.keyPressed);
        } else {
            jQuery(document).bind('keyup', jQuery.ImageBox.keyPressed);
        }
        jQuery('a').each(
            function()
            {    
                var el                 = jQuery(this);
                relAttr         = el.attr('rel')||'';
                hrefAttr         = el.attr('href')||'';
                imageTypes         = /\.jpg|\.jpeg|\.png|\.gif|\.bmp|blobid=\d/g;
                if (hrefAttr.toLowerCase().match(imageTypes) != null && relAttr.toLowerCase().indexOf('imagebox') == 0) {
                    el.bind('click', jQuery.ImageBox.start);
                }
            }
        );
        if (jQuery.browser.msie) {
            iframe = document.createElement('iframe');
            jQuery(iframe)
                .attr(
                    {
                        id            : 'ImageBoxIframe',
                        src            : 'javascript:false;',
                        frameborder    : 'no',
                        scrolling    : 'no'
                    }
                )
                .css (
                    {
                        display        : 'none',
                        position    : 'absolute',
                        top            : '0',
                        left        : '0',
                        filter        : 'progid:DXImageTransform.Microsoft.Alpha(opacity=0)'
                    }
                );
            jQuery('body').append(iframe);
        }

        overlay    = document.createElement('div');
        jQuery(overlay)
            .attr('id', 'ImageBoxOverlay')
            .css(
                {
                    position    : 'absolute',
                    display        : 'none',
                    top            : '0',
                    left        : '0',
                    opacity        : 0
                }
            )
            .append(document.createTextNode(' '))
            .bind('click', jQuery.ImageBox.hideImage);

        captionText = document.createElement('div');
        jQuery(captionText)
            .attr('id', 'ImageBoxCaptionText')
            .css(
                {
                    paddingLeft        : jQuery.ImageBox.options.border + 'px'
                }
            )
            .append(document.createTextNode(' '));

        captionImages = document.createElement('div');
        jQuery(captionImages)
            .attr('id', 'ImageBoxCaptionImages')
            .css(
                {
                    paddingLeft        : jQuery.ImageBox.options.border + 'px',
                    paddingBottom    : jQuery.ImageBox.options.border + 'px'
                }
            )
            .append(document.createTextNode(' '));

        closeEl = document.createElement('a');
        jQuery(closeEl)
            .attr(
                {
                    id            : 'ImageBoxClose',
                    href        : '#'
                }
            )
            .css(
                {
                    position    : 'absolute',
                    right        : jQuery.ImageBox.options.border + 'px',
                    top            : '0'
                }
            )
            .append(jQuery.ImageBox.options.closeHTML)
            .bind('click', jQuery.ImageBox.hideImage);

        captionEl = document.createElement('div');
        jQuery(captionEl)
            .attr('id', 'ImageBoxCaption')
            .css(
                {
                    position    : 'relative',
                    textAlign    : 'left',
                    margin        : '0 auto',
                    zIndex        : 1
                }
            )
            .append(captionText)
            .append(captionImages)
            .append(closeEl);

        loader = document.createElement('img');
        loader.src = jQuery.ImageBox.options.loaderSRC;
        jQuery(loader)
            .attr('id', 'ImageBoxLoader')
            .css(
                {
                    position    : 'absolute'
                }
            );

        prevImage = document.createElement('a');
        jQuery(prevImage)
            .attr(
                {
                    id            : 'ImageBoxPrevImage',
                    href        : '#'
                }
            )
            .css(
                {
                    position        : 'absolute',
                    display            : 'none',
                    overflow        : 'hidden',
                    textDecoration    : 'none'
                }
            )
            .append(document.createTextNode(' '));

        nextImage = document.createElement('a');
        jQuery(nextImage)
            .attr(
                {
                    id            : 'ImageBoxNextImage',
                    href        : '#'
                }
            )
            .css(
                {
                    position        : 'absolute',
                    overflow        : 'hidden',
                    textDecoration    : 'none'
                }
            )
            .append(document.createTextNode(' '));

        container = document.createElement('div');
        jQuery(container)
            .attr('id', 'ImageBoxContainer')
            .css(
                {
                    display        : 'none',
                    position    : 'relative',
                    overflow    : 'hidden',
                    textAlign    : 'left',
                    margin        : '0 auto',
                    top            : '0',
                    left        : '0',
                    zIndex        : 2
                }
            )
            .append([loader, prevImage, nextImage]);

        outerContainer = document.createElement('div');
        jQuery(outerContainer)
            .attr('id', 'ImageBoxOuterContainer')
            .css(
                {
                    display        : 'none',
                    position    : 'absolute',
                    overflow    : 'hidden',
                    top            : '0',
                    left        : '0',
                    textAlign    : 'center',
                    backgroundColor : 'transparent',
                    lineHeigt    : '0'
                }
            )
            .append([container,captionEl]);

        jQuery('body')
            .append(overlay)
            .append(outerContainer);


        //minimum width :
        prevImageEl = jQuery('#ImageBoxPrevImage');
        prevWidth = prevImageEl.css("width");
        if (!prevWidth) {
            prevWidth='';
        }
        else{
            if(prevWidth!=''){
                prevWidth = prevWidth.replace(/px/g,''); //on eleve le texte 'px' pour pouvoir faire des calculs
            }
        }
        nextImageEl = jQuery('#ImageBoxNextImage');
        nextWidth = nextImageEl.css("width");
        if (!nextWidth) {
            nextWidth='';
        }
        else{
            if(nextWidth!=''){
                nextWidth = nextWidth.replace(/px/g,''); //on eleve le texte 'px' pour pouvoir faire des calculs
            }
        }

        jQuery.ImageBox.minWidth=-(-(jQuery.ImageBox.options.border * 2)-nextWidth-prevWidth); //2*border+nextWidth+prevWidth

    },

    start : function(e, elm)
    {
        var el = elm ? jQuery(elm) : jQuery(this);
        var linkRel =  el.attr('rel');
        var totalImages, iteration, prevImage, nextImage;
        if (linkRel != 'imagebox') {
            jQuery.ImageBox.currentRel = linkRel;
            var gallery = jQuery('a[@rel=' + linkRel + ']');
            var totalImages = gallery.size();
            var iteration = gallery.index(elm ? elm : this);
            prevImage = gallery.get(iteration - 1);
            nextImage = gallery.get(iteration + 1);
        }
        var imageSrc =  el.attr('href');
        var captionText = el.attr('title');
        var caption2 = el.attr('content') || "";
        if (caption2!="") {
            captionText+="<br>"+caption2;
        }

        var pageSize = jQuery.iUtil.getScroll();
        var overlay = jQuery('#ImageBoxOverlay');
        if (!jQuery.ImageBox.opened) {
            jQuery.ImageBox.opened = true;
            if (jQuery.browser.msie) {
                jQuery('#ImageBoxIframe')
                    .css ('height', Math.max(pageSize.ih,pageSize.h) + 'px')
                    .css ('width', Math.max(pageSize.iw,pageSize.w) + 'px')
                    .show();
            }
            overlay
                .css ('height', Math.max(pageSize.ih,pageSize.h) + 'px')
                .css ('width', Math.max(pageSize.iw,pageSize.w) + 'px')
                .show()
                .fadeTo(
                    300,
                    jQuery.ImageBox.options.overlayOpacity,
                    function()
                    {
                        jQuery.ImageBox.loadImage(
                            imageSrc,
                            captionText,
                            pageSize,
                            totalImages,
                            iteration,
                            prevImage,
                            nextImage
                        );
                    }
                );
            jQuery('#ImageBoxOuterContainer').css ('width', Math.max(pageSize.iw,pageSize.w) + 'px');
        } else {
            jQuery('#ImageBoxPrevImage').get(0).onclick = null;
            jQuery('#ImageBoxNextImage').get(0).onclick = null;
            jQuery.ImageBox.loadImage(
                imageSrc,
                captionText,
                pageSize,
                totalImages,
                iteration,
                prevImage,
                nextImage
            );
        }
        return false;
    },

    loadImage : function(imageSrc, captiontext, pageSize, totalImages, iteration, prevImage, nextImage)
    {
        jQuery('#ImageBoxCurrentImage').remove();
        prevImageEl = jQuery('#ImageBoxPrevImage');
        prevImageEl.hide();
        nextImageEl = jQuery('#ImageBoxNextImage');
        nextImageEl.hide();
        loader = jQuery('#ImageBoxLoader');
        container = jQuery('#ImageBoxContainer');
        outerContainer = jQuery('#ImageBoxOuterContainer');
        captionEl = jQuery('#ImageBoxCaption').css('visibility', 'hidden');
        //Avoid safari Bug :
        //jQuery('#ImageBoxCaptionText').html(captionText);
        jQuery('#ImageBoxCaptionText').html("<div id='ImageBoxCaptextcontainer' style='padding-right:4px'>"+captionText+"</div>");
        jQuery.ImageBox.animationInProgress = true;
        if (totalImages && jQuery.ImageBox.options.showTextImage)
            jQuery('#ImageBoxCaptionImages').html(
                jQuery.ImageBox.options.textImage
                + ' ' + (iteration + 1) + ' '
                + jQuery.ImageBox.options.textImageFrom
                + ' ' + totalImages
            );
        if (prevImage) {
            prevImageEl.get(0).onclick = function()
            {
                this.blur();
                jQuery.ImageBox.start(null, prevImage);
                return false;
            };
        }
        if (nextImage) {
            nextImageEl.get(0).onclick =function()
            {
                this.blur();
                jQuery.ImageBox.start(null, nextImage);
                return false;
            };
        }
        loader.show();
        containerSize = jQuery.iUtil.getSize(container.get(0));
        containerW = Math.max(containerSize.wb, loader.get(0).width + jQuery.ImageBox.options.border * 2);
        containerH = Math.max(containerSize.hb, loader.get(0).height + jQuery.ImageBox.options.border * 2);
        loader
            .css(
                {
                    left    : (containerW - loader.get(0).width)/2 + 'px',
                    top        : (containerH - loader.get(0).height)/2 + 'px'
                }
            );
        container
            .css(
                {
                    width    : containerW + 'px',
                    height    : containerH + 'px'
                }
            )
            .show();
        clientSize = jQuery.iUtil.getClient();
        outerContainer
            .css('top', pageSize.t +  (clientSize.h / 15) + 'px');
        if (outerContainer.css('display') == 'none') {
            outerContainer
                .show()
                .fadeIn(
                    jQuery.ImageBox.options.fadeDuration
                );
        }
        imageEl = new Image;
        // avoid Safari bug :
        imageEl.id='ImageBoxCurrentImage';
        imageEl.onload = function(){

                if (jQuery.browser.safari) {
                    containerW = jQImageBox_imageEl.width + jQuery.ImageBox.options.border * 2;
                    containerH = jQImageBox_imageEl.height + jQuery.ImageBox.options.border * 2;
                }

                containerW = imageEl.width + jQuery.ImageBox.options.border * 2;
                containerH = imageEl.height + jQuery.ImageBox.options.border * 2;

                //min width :
                if (jQuery.ImageBox.minWidth > containerW ) {
                    containerW = jQuery.ImageBox.minWidth + jQuery.ImageBox.options.border * 2;
                }

                loader.hide();
                container.animate(
                    {
                        height        : containerH
                    },
                    containerSize.hb != containerH ? jQuery.ImageBox.options.fadeDuration : 1,
                    function()
                    {
                        container.animate(
                            {
                                width        : containerW
                            },
                            containerSize.wb != containerW ? jQuery.ImageBox.options.fadeDuration : 1,
                            function()
                            {


                                if (jQuery.browser.safari) {
                                    var imgtoprepend="<img src='"+jQImageBox_imageEl.src+"' id='imgboxtmp' style='display:none' >";
                                    container.prepend(imgtoprepend);
                                    var jqi_width = jQuery('#imgboxtmp').width();
                                    while(jqi_width==0){
                                        jqi_width = jQuery('#imgboxtmp').width();
                                    }
                                    jqi_height = jQuery('#imgboxtmp').height();
                                    jQuery('#imgboxtmp').remove();

                                    jqi_width = jqi_width - 2* jQuery.ImageBox.options.border;

                                    var imgtoprepend="<img src='"+jQImageBox_imageEl.src+"' id='"+jQImageBox_imageEl.id+"' >";
                                    container.prepend(imgtoprepend); //pour safari...

                                }
                                else{
                                    container.prepend(imageEl);
                                }


                                jQuery('#ImageBoxCurrentImage')
                                    .css(
                                        {
                                            position    : 'absolute',
                                            left        : (containerW-jQuery('#ImageBoxCurrentImage').width())/2+'px', //jQuery.ImageBox.options.border + 'px',
                                            top            : jQuery.ImageBox.options.border + 'px'
                                        }
                                    )
                                    .fadeIn(
                                        jQuery.ImageBox.options.fadeDuration,
                                        function()
                                        {
                                            captionSize = jQuery.iUtil.getSize(captionEl.get(0));

                                            //min width :
                                            if (jQuery.ImageBox.minWidth > containerW ) {
                                                 containerW = jQuery.ImageBox.minWidth;
                                            }

                                            if (prevImage) {
                                                prevImageEl
                                                    .css(
                                                        {
                                                            left    : jQuery.ImageBox.options.border + 'px',
                                                            top        : jQuery.ImageBox.options.border + 'px',
                                                            width    : containerW/2 ,//- jQuery.ImageBox.options.border * 3 + 'px',
                                                            height    : containerH - jQuery.ImageBox.options.border * 2 + 'px'
                                                        }
                                                    )
                                                    .show();
                                            }
                                            if (nextImage) {
                                                nextImageEl
                                                    .css(
                                                        {
                                                            left    : containerW/2 + jQuery.ImageBox.options.border * 2 + 1 + 'px',
                                                            top        : jQuery.ImageBox.options.border + 'px',
                                                            width    : containerW/2 - jQuery.ImageBox.options.border * 3 + 'px',
                                                            height    : containerH - jQuery.ImageBox.options.border * 2 + 'px'
                                                        }
                                                    )
                                                    .show();
                                            }

                                            jQuery("#ImageBoxCaptextcontainer").css('padding-top',jQuery("#ImageBoxClose").height());

                                            captionEl
                                                .css(
                                                    {
                                                        width        : containerW + 'px',
                                                        top            : - captionSize.hb + 'px',
                                                        visibility    : 'visible'
                                                    }
                                                )
                                                .animate(
                                                    {
                                                        top        : -1
                                                    },
                                                    jQuery.ImageBox.options.fadeDuration,
                                                    function()
                                                    {
                                                        jQuery.ImageBox.animationInProgress = false;
                                                    }
                                                );
                                        }
                                    );
                            }
                        );
                    }
                );
            }
        imageEl.src = imageSrc;

        jQImageBox_imageEl = imageEl;
    },

    hideImage : function()
    {
        jQuery('#ImageBoxCurrentImage').remove();
        jQuery('#ImageBoxOuterContainer').hide();
        jQuery('#ImageBoxCaption').css('visibility', 'hidden');
        jQuery('#ImageBoxOverlay').fadeTo(
            300,
            0,
            function(){
                jQuery(this).hide();
                if (jQuery.browser.msie) {
                    jQuery('#ImageBoxIframe').hide();
                }
            }
        );
        jQuery('#ImageBoxPrevImage').get(0).onclick = null;
        jQuery('#ImageBoxNextImage').get(0).onclick = null;
        jQuery.ImageBox.currentRel = null;
        jQuery.ImageBox.opened = false;
        jQuery.ImageBox.animationInProgress = false;
        return false;
    }
};


/*
 * jQuery validation plug-in 1.5
 *
 * 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 5952 2008-11-25 19:12:30Z 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
 */

(function($) {

$.extend($.fn, {
    // http://docs.jquery.com/Plugins/Validation/validate
    validate: function( options ) {
        
        // if nothing is selected, return nothing; can't chain anyway
        if (!this.length) {
            options && options.debug && window.console && console.warn( "nothing selected, can't validate, returning nothing" );
            return;
        }
        
        // check if a validator for this form was already created
        var validator = $.data(this[0], 'validator');
        if ( validator ) {
            return validator;
        }
        
        validator = new $.validator( options, this[0] );
        $.data(this[0], 'validator', validator); 
        
        if ( validator.settings.onsubmit ) {
        
            // allow suppresing validation by adding a cancel class to the submit button
            this.find("input, button").filter(".cancel").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 ( $(this[0]).is('form')) {
            return this.validate().form();
        } else {
            var valid = false;
            var validator = $(this[0].form).validate();
            this.each(function() {
                valid |= validator.element(this);
            });
            return valid;
        }
    },
    // attributes: space seperated list of attributes to retrieve and remove
    removeAttrs: function(attributes) {
        var result = {},
            $element = this;
        $.each(attributes.split(/\s/), function() {
            result[this] = $element.attr(this);
            $element.removeAttr(this);
        });
        return result;
    },
    // http://docs.jquery.com/Plugins/Validation/rules
    rules: function(command, argument) {
        var element = this[0];
        
        if (command) {
            var settings = $.data(element.form, 'validator').settings;
            var staticRules = settings.rules;
            var existingRules = $.validator.staticRules(element);
            switch(command) {
            case "add":
                $.extend(existingRules, $.validator.normalizeRule(argument));
                staticRules[element.name] = existingRules;
                if (argument.messages)
                    settings.messages[element.name] = $.extend( settings.messages[element.name], argument.messages );
                break;
            case "remove":
                if (!argument) {
                    delete staticRules[element.name];
                    return existingRules;
                }
                var filtered = {};
                $.each(argument.split(/\s/), function(index, method) {
                    filtered[method] = existingRules[method];
                    delete existingRules[method];
                });
                return filtered;
            }
        }
        
        var data = $.validator.normalizeRules(
        $.extend(
            {},
            $.validator.metadataRules(element),
            $.validator.classRules(element),
            $.validator.attributeRules(element),
            $.validator.staticRules(element)
        ), element);
        
        // make sure required is at front
        if (data.required) {
            var param = data.required;
            delete data.required;
            data = $.extend({required: param}, data);
        }
        
        return data;
    },
    // destructive add
    push: function( t ) {
        return this.setArray( this.add(t).get() );
    }
});

// Custom selectors
$.extend($.expr[":"], {
    // http://docs.jquery.com/Plugins/Validation/blank
    blank: function(a) {return !$.trim(a.value);},
    // http://docs.jquery.com/Plugins/Validation/filled
    filled: function(a) {return !!$.trim(a.value);},
    // http://docs.jquery.com/Plugins/Validation/unchecked
    unchecked: function(a) {return !a.checked;}
});


$.format = function(source, params) {
    if ( arguments.length == 1 ) 
        return function() {
            var args = $.makeArray(arguments);
            args.unshift(source);
            return $.format.apply( this, args );
        };
    if ( arguments.length > 2 && params.constructor != Array  ) {
        params = $.makeArray(arguments).slice(1);
    }
    if ( params.constructor != Array ) {
        params = [ params ];
    }
    $.each(params, function(i, n) {
        source = source.replace(new RegExp("\\{" + i + "\\}", "g"), n);
    });
    return source;
};

// constructor for validator
$.validator = function( options, form ) {
    this.settings = $.extend( {}, $.validator.defaults, options );
    this.currentForm = form;
    this.init();
};

$.extend($.validator, {

    defaults: {
        messages: {},
        groups: {},
        rules: {},
        errorClass: "error",
        errorElement: "label",
        focusInvalid: true,
        errorContainer: $( [] ),
        errorLabelContainer: $( [] ),
        onsubmit: true,
        ignore: [],
        ignoreTitle: false,
        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 && 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 ) {
            $( element ).addClass( errorClass );
        },
        unhighlight: function( element, errorClass ) {
            $( element ).removeClass( errorClass );
        }
    },

    // http://docs.jquery.com/Plugins/Validation/Validator/setDefaults
    setDefaults: function(settings) {
        $.extend( $.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 number.",
        equalTo: "Please enter the same value again.",
        accept: "Please enter a value with a valid extension.",
        maxlength: $.format("Please enter no more than {0} characters."),
        minlength: $.format("Please enter at least {0} characters."),
        rangelength: $.format("Please enter a value between {0} and {1} characters long."),
        range: $.format("Please enter a value between {0} and {1}."),
        max: $.format("Please enter a value less than or equal to {0}."),
        min: $.format("Please enter a value greater than or equal to {0}.")
    },
    
    autoCreateRanges: false,
    
    prototype: {
        
        init: function() {
            this.labelContainer = $(this.settings.errorLabelContainer);
            this.errorContext = this.labelContainer.length && this.labelContainer || $(this.currentForm);
            this.containers = $(this.settings.errorContainer).add( this.settings.errorLabelContainer );
            this.submitted = {};
            this.valueCache = {};
            this.pendingRequest = 0;
            this.pending = {};
            this.invalid = {};
            this.reset();
            
            var groups = (this.groups = {});
            $.each(this.settings.groups, function(key, value) {
                $.each(value.split(/\s/), function(index, name) {
                    groups[name] = key;
                });
            });
            var rules = this.settings.rules;
            $.each(rules, function(key, value) {
                rules[key] = $.validator.normalizeRule(value);
            });
            
            function delegate(event) {
                var validator = $.data(this[0].form, "validator");
                validator.settings["on" + event.type] && validator.settings["on" + event.type].call(validator, this[0] );
            }
            $(this.currentForm)
                .delegate("focusin focusout keyup", ":text, :password, :file, select, textarea", delegate)
                .delegate("click", ":radio, :checkbox", delegate);

            if (this.settings.invalidHandler)
                $(this.currentForm).bind("invalid-form.validate", this.settings.invalidHandler);
        },

        // http://docs.jquery.com/Plugins/Validation/Validator/form
        form: function() {
            this.checkForm();
            $.extend(this.submitted, this.errorMap);
            this.invalid = $.extend({}, this.errorMap);
            if (!this.valid())
                $(this.currentForm).triggerHandler("invalid-form", [this]);
            this.showErrors();
            return this.valid();
        },
        
        checkForm: function() {
            this.prepareForm();
            for ( var i = 0, elements = (this.currentElements = this.elements()); elements[i]; i++ ) {
                this.check( elements[i] );
            }
            return this.valid(); 
        },
        
        // http://docs.jquery.com/Plugins/Validation/Validator/element
        element: function( element ) {
            element = this.clean( element );
            this.lastElement = element;
            this.prepareElement( element );
            this.currentElements = $(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
                $.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 = $.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 ( $.fn.resetForm )
                $( this.currentForm ).resetForm();
            this.submitted = {};
            this.prepareForm();
            this.hideErrors();
            this.elements().removeClass( this.settings.errorClass );
        },
        
        numberOfInvalids: function() {
            return this.objectLength(this.invalid);
        },
        
        objectLength: function( obj ) {
            var count = 0;
            for ( var i in obj )
                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 {
                    $(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 && $.grep(this.errorList, function(n) {
                return n.element.name == lastActive.name;
            }).length == 1 && lastActive;
        },
        
        elements: function() {
            var validator = this,
                rulesCache = {};
            
            // select all valid inputs inside the form (no submit or reset buttons)
            // workaround $Query([]).add until http://dev.jquery.com/ticket/2114 is solved
            return $([]).add(this.currentForm.elements)
            .filter(":input")
            .not(":submit, :reset, :image, [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 || !validator.objectLength($(this).rules()) )
                    return false;
                
                rulesCache[this.name] = true;
                return true;
            });
        },
        
        clean: function( selector ) {
            return $( selector )[0];
        },
        
        errors: function() {
            return $( this.settings.errorElement + "." + this.settings.errorClass, this.errorContext );
        },
        
        reset: function() {
            this.successList = [];
            this.errorList = [];
            this.errorMap = {};
            this.toShow = $([]);
            this.toHide = $([]);
            this.formSubmitted = false;
            this.currentElements = $([]);
        },
        
        prepareForm: function() {
            this.reset();
            this.toHide = this.errors().push( this.containers );
        },
        
        prepareElement: function( element ) {
            this.reset();
            this.toHide = this.errorsFor(element);
        },
    
        check: function( element ) {
            element = this.clean( element );
            
            // if radio/checkbox, validate first element in group instead
            if (this.checkable(element)) {
                element = this.findByName( element.name )[0];
            }
            
            var rules = $(element).rules();
            var dependencyMismatch = false;
            for( method in rules ) {
                var rule = { method: method, parameters: rules[method] };
                try {
                    var result = $.validator.methods[method].call( this, element.value, element, rule.parameters );
                    
                    // if a method indicates that the field is optional and therefore valid,
                    // don't mark it as valid when there are no other rules
                    if ( result == "dependency-mismatch" ) {
                        dependencyMismatch = true;
                        continue;
                    }
                    dependencyMismatch = false;
                    
                    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.log("exception occured when checking element " + element.id
                         + ", check the '" + rule.method + "' method");
                    throw e;
                }
            }
            if (dependencyMismatch)
                return;
            if ( this.objectLength(rules) )
                this.successList.push(element);
            return true;
        },
        
        // return the custom message for the given element and validation method
        // specified in the element's "messages" metadata
        customMetaMessage: function(element, method) {
            if (!$.metadata)
                return;
            
            var meta = this.settings.meta
                ? $(element).metadata()[this.settings.meta]
                : $(element).metadata();
            
            return meta && meta.messages && meta.messages[method];
        },
        
        // 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 ),
                this.customMetaMessage( element, method ),
                // title is never undefined, so handle empty string as undefined
                !this.settings.ignoreTitle && element.title || undefined,
                $.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 && 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] );
                }
            }
            if (this.settings.unhighlight) {
                for ( var i = 0, elements = this.validElements(); elements[i]; i++ ) {
                    this.settings.unhighlight.call( this, elements[i], this.settings.errorClass );
                }
            }
            this.toHide = this.toHide.not( this.toShow );
            this.hideErrors();
            this.addWrapper( this.toShow ).show();
        },
        
        validElements: function() {
            return this.currentElements.not(this.invalidElements());
        },
        
        invalidElements: function() {
            return $(this.errorList).map(function() {
                return this.element;
            });
        },
        
        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
                label.attr("generated") && label.html(message);
            } else {
                // create label
                label = $("<" + 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, $(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.groups[element.name] || (this.checkable(element) ? element.name : element.id || element.name);
        },

        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 $(document.getElementsByName(name)).map(function(index, element) {
                return element.form == form && element.name == name && element  || null;
            });
        },
        
        getLength: function(value, element) {
            switch( element.nodeName.toLowerCase() ) {
            case 'select':
                return $("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 !!$(param, element.form).length;
            },
            "function": function(param, element) {
                return param(element);
            }
        },
        
        optional: function(element) {
            return !$.validator.methods.required.call(this, $.trim(element.value), element) && "dependency-mismatch";
        },
        
        startRequest: function(element) {
            if (!this.pending[element.name]) {
                this.pendingRequest++;
                this.pending[element.name] = true;
            }
        },
        
        stopRequest: function(element, valid) {
            this.pendingRequest--;
            // sometimes synchronization fails, make sure pendingRequest is never < 0
            if (this.pendingRequest < 0)
                this.pendingRequest = 0;
            delete this.pending[element.name];
            if ( valid && this.pendingRequest == 0 && this.formSubmitted && this.form() ) {
                $(this.currentForm).submit();
            } else if (!valid && this.pendingRequest == 0 && this.formSubmitted) {
                $(this.currentForm).triggerHandler("invalid-form", [this]);
            }
        },
        
        previousValue: function(element) {
            return $.data(element, "previousValue") || $.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 :
            $.extend(this.classRuleSettings, className);
    },
    
    classRules: function(element) {
        var rules = {};
        var classes = $(element).attr('class');
        classes && $.each(classes.split(' '), function() {
            if (this in $.validator.classRuleSettings) {
                $.extend(rules, $.validator.classRuleSettings[this]);
            }
        });
        return rules;
    },
    
    attributeRules: function(element) {
        var rules = {};
        var $element = $(element);
        
        for (method in $.validator.methods) {
            var value = $element.attr(method);
            if (value) {
                rules[method] = value;
            }
        }
        
        // maxlength may be returned as -1, 2147483647 (IE) and 524288 (safari) for text inputs
        if (rules.maxlength && /-1|2147483647|524288/.test(rules.maxlength)) {
            delete rules.maxlength;
        }
        
        return rules;
    },
    
    metadataRules: function(element) {
        if (!$.metadata) return {};
        
        var meta = $.data(element.form, 'validator').settings.meta;
        return meta ?
            $(element).metadata()[meta] :
            $(element).metadata();
    },
    
    staticRules: function(element) {
        var rules = {};
        var validator = $.data(element.form, 'validator');
        if (validator.settings.rules) {
            rules = $.validator.normalizeRule(validator.settings.rules[element.name]) || {};
        }
        return rules;
    },
    
    normalizeRules: function(rules, element) {
        // handle dependency check
        $.each(rules, function(prop, val) {
            // ignore rule when param is explicitly false, eg. required:false
            if (val === false) {
                delete rules[prop];
                return;
            }
            if (val.param || val.depends) {
                var keepRule = true;
                switch (typeof val.depends) {
                    case "string":
                        keepRule = !!$(val.depends, element.form).length;
                        break;
                    case "function":
                        keepRule = val.depends.call(element, element);
                        break;
                }
                if (keepRule) {
                    rules[prop] = val.param !== undefined ? val.param : true;
                } else {
                    delete rules[prop];
                }
            }
        });
        
        // evaluate parameters
        $.each(rules, function(rule, parameter) {
            rules[rule] = $.isFunction(parameter) ? parameter(element) : parameter;
        });
        
        // clean number parameters
        $.each(['minlength', 'maxlength', 'min', 'max'], function() {
            if (rules[this]) {
                rules[this] = Number(rules[this]);
            }
        });
        $.each(['rangelength', 'range'], function() {
            if (rules[this]) {
                rules[this] = [Number(rules[this][0]), Number(rules[this][1])];
            }
        });
        
        if ($.validator.autoCreateRanges) {
            // 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;
            }
        }
        
        // To support custom messages in metadata ignore rule methods titled "messages"
        if (rules.messages) {
            delete rules.messages
        }
        
        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 = {};
            $.each(data.split(/\s/), function() {
                transformed[this] = true;
            });
            data = transformed;
        }
        return data;
    },
    
    // http://docs.jquery.com/Plugins/Validation/Validator/addMethod
    addMethod: function(name, method, message) {
        $.validator.methods[name] = method;
        $.validator.messages[name] = message;
        if (method.length < 3) {
            $.validator.addClassRules(name, $.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 = $("option:selected", element);
                return options.length > 0 && ( element.type == "select-multiple" || ($.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 $.trim(value).length > 0;
            }
        },
        
        // http://docs.jquery.com/Plugins/Validation/Methods/remote
        remote: function(value, element, param) {
            if ( this.optional(element) )
                return "dependency-mismatch";
            
            var previous = this.previousValue(element);
            
            if (!this.settings.messages[element.name] )
                this.settings.messages[element.name] = {};
            this.settings.messages[element.name].remote = typeof previous.message == "function" ? previous.message(value) : previous.message;
            
            param = typeof param == "string" && {url:param} || param; 
            
            if ( previous.old !== value ) {
                previous.old = value;
                var validator = this;
                this.startRequest(element);
                var data = {};
                data[element.name] = value;
                $.ajax($.extend(true, {
                    url: param,
                    mode: "abort",
                    port: "validate" + element.name,
                    dataType: "json",
                    data: data,
                    success: function(response) {
                        if ( response ) {
                            var submitted = validator.formSubmitted;
                            validator.prepareElement(element);
                            validator.formSubmitted = submitted;
                            validator.successList.push(element);
                            validator.showErrors();
                        } else {
                            var errors = {};
                            errors[element.name] =  response || validator.defaultMessage( element, "remote" );
                            validator.showErrors(errors);
                        }
                        previous.valid = response;
                        validator.stopRequest(element, response);
                    }
                }, param));
                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;
        },
        
        // http://docs.jquery.com/Plugins/Validation/Methods/maxlength
        maxlength: function(value, element, param) {
            return this.optional(element) || this.getLength(value, element) <= param;
        },
        
        // 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] );
        },
        
        // http://docs.jquery.com/Plugins/Validation/Methods/min
        min: function( value, element, param ) {
            return this.optional(element) || value >= param;
        },
        
        // http://docs.jquery.com/Plugins/Validation/Methods/max
        max: function( value, element, param ) {
            return this.optional(element) || value <= param;
        },
        
        // http://docs.jquery.com/Plugins/Validation/Methods/range
        range: function( value, element, param ) {
            return this.optional(element) || ( value >= param[0] && value <= param[1] );
        },
        
        // 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 "dependency-mismatch";
            // accept only digits and dashes
            if (/[^0-9-]+/.test(value))
                return false;
            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 == $(param).val();
        }
        
    }
    
});

})(jQuery);

// ajax mode: abort
// usage: $.ajax({ mode: "abort"[, port: "uniqueport"]});
// if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort() 
;(function($) {
    var ajax = $.ajax;
    var pendingRequests = {};
    $.ajax = function(settings) {
        // create settings for compatibility with ajaxSetup
        settings = $.extend(settings, $.extend({}, $.ajaxSettings, settings));
        var port = settings.port;
        if (settings.mode == "abort") {
            if ( pendingRequests[port] ) {
                pendingRequests[port].abort();
            }
            return (pendingRequests[port] = ajax.apply(this, arguments));
        }
        return ajax.apply(this, arguments);
    };
})(jQuery);

// 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($) {
    $.each({
        focus: 'focusin',
        blur: 'focusout'    
    }, function( original, fix ){
        $.event.special[fix] = {
            setup:function() {
                if ( $.browser.msie ) return false;
                this.addEventListener( original, $.event.special[fix].handler, true );
            },
            teardown:function() {
                if ( $.browser.msie ) return false;
                this.removeEventListener( original,
                $.event.special[fix].handler, true );
            },
            handler: function(e) {
                arguments[0] = $.event.fix(e);
                arguments[0].type = fix;
                return $.event.handle.apply(this, arguments);
            }
        };
    });
    $.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, [$.event.fix({ type: type, target: target })]);
        }
    })
})(jQuery);



/**
 * Flash (http://jquery.lukelutman.com/plugins/flash)
 * A jQuery plugin for embedding Flash movies.
 * 
 * Version 1.0
 * November 9th, 2006
 *
 * Copyright (c) 2006 Luke Lutman (http://www.lukelutman.com)
 * Dual licensed under the MIT and GPL licenses.
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.opensource.org/licenses/gpl-license.php
 * 
 * Inspired by:
 * SWFObject (http://blog.deconcept.com/swfobject/)
 * UFO (http://www.bobbyvandersluis.com/ufo/)
 * sIFR (http://www.mikeindustries.com/sifr/)
 * 
 * IMPORTANT: 
 * The packed version of jQuery breaks ActiveX control
 * activation in Internet Explorer. Use JSMin to minifiy
 * jQuery (see: http://jquery.lukelutman.com/plugins/flash#activex).
 *
 **/ 
;(function(){
    
var $$;

/**
 * 
 * @desc Replace matching elements with a flash movie.
 * @author Luke Lutman
 * @version 1.0.1
 *
 * @name flash
 * @param Hash htmlOptions Options for the embed/object tag.
 * @param Hash pluginOptions Options for detecting/updating the Flash plugin (optional).
 * @param Function replace Custom block called for each matched element if flash is installed (optional).
 * @param Function update Custom block called for each matched if flash isn't installed (optional).
 * @type jQuery
 *
 * @cat plugins/flash
 * 
 * @example $('#hello').flash({ src: 'hello.swf' });
 * @desc Embed a Flash movie.
 *
 * @example $('#hello').flash({ src: 'hello.swf' }, { version: 8 });
 * @desc Embed a Flash 8 movie.
 *
 * @example $('#hello').flash({ src: 'hello.swf' }, { expressInstall: true });
 * @desc Embed a Flash movie using Express Install if flash isn't installed.
 *
 * @example $('#hello').flash({ src: 'hello.swf' }, { update: false });
 * @desc Embed a Flash movie, don't show an update message if Flash isn't installed.
 *
**/
$$ = jQuery.fn.flash = function(htmlOptions, pluginOptions, replace, update) {
    
    // Set the default block.
    var block = replace || $$.replace;
    
    // Merge the default and passed plugin options.
    pluginOptions = $$.copy($$.pluginOptions, pluginOptions);
    
    // Detect Flash.
    if(!$$.hasFlash(pluginOptions.version)) {
        // Use Express Install (if specified and Flash plugin 6,0,65 or higher is installed).
        if(pluginOptions.expressInstall && $$.hasFlash(6,0,65)) {
            // Add the necessary flashvars (merged later).
            var expressInstallOptions = {
                flashvars: {      
                    MMredirectURL: location,
                    MMplayerType: 'PlugIn',
                    MMdoctitle: jQuery('title').text() 
                }                    
            };
        // Ask the user to update (if specified).
        } else if (pluginOptions.update) {
            // Change the block to insert the update message instead of the flash movie.
            block = update || $$.update;
        // Fail
        } else {
            // The required version of flash isn't installed.
            // Express Install is turned off, or flash 6,0,65 isn't installed.
            // Update is turned off.
            // Return without doing anything.
            return this;
        }
    }
    
    // Merge the default, express install and passed html options.
    htmlOptions = $$.copy($$.htmlOptions, expressInstallOptions, htmlOptions);
    
    // Invoke $block (with a copy of the merged html options) for each element.
    return this.each(function(){
        block.call(this, $$.copy(htmlOptions));
    });
    
};
/**
 *
 * @name flash.copy
 * @desc Copy an arbitrary number of objects into a new object.
 * @type Object
 * 
 * @example $$.copy({ foo: 1 }, { bar: 2 });
 * @result { foo: 1, bar: 2 };
 *
**/
$$.copy = function() {
    var options = {}, flashvars = {};
    for(var i = 0; i < arguments.length; i++) {
        var arg = arguments[i];
        if(arg == undefined) continue;
        jQuery.extend(options, arg);
        // don't clobber one flash vars object with another
        // merge them instead
        if(arg.flashvars == undefined) continue;
        jQuery.extend(flashvars, arg.flashvars);
    }
    options.flashvars = flashvars;
    return options;
};
/*
 * @name flash.hasFlash
 * @desc Check if a specific version of the Flash plugin is installed
 * @type Boolean
 *
**/
$$.hasFlash = function() {
    // look for a flag in the query string to bypass flash detection
    if(/hasFlash\=true/.test(location)) return true;
    if(/hasFlash\=false/.test(location)) return false;
    var pv = $$.hasFlash.playerVersion().match(/\d+/g);
    var rv = String([arguments[0], arguments[1], arguments[2]]).match(/\d+/g) || String($$.pluginOptions.version).match(/\d+/g);
    for(var i = 0; i < 3; i++) {
        pv[i] = parseInt(pv[i] || 0);
        rv[i] = parseInt(rv[i] || 0);
        // player is less than required
        if(pv[i] < rv[i]) return false;
        // player is greater than required
        if(pv[i] > rv[i]) return true;
    }
    // major version, minor version and revision match exactly
    return true;
};
/**
 *
 * @name flash.hasFlash.playerVersion
 * @desc Get the version of the installed Flash plugin.
 * @type String
 *
**/
$$.hasFlash.playerVersion = function() {
    // ie
    try {
        try {
            // avoid fp6 minor version lookup issues
            // see: http://blog.deconcept.com/2006/01/11/getvariable-setvariable-crash-internet-explorer-flash-6/
            var axo = new ActiveXObject('ShockwaveFlash.ShockwaveFlash.6');
            try { axo.AllowScriptAccess = 'always';    } 
            catch(e) { return '6,0,0'; }                
        } catch(e) {}
        return new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version').replace(/\D+/g, ',').match(/^,?(.+),?$/)[1];
    // other browsers
    } catch(e) {
        try {
            if(navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin){
                return (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]).description.replace(/\D+/g, ",").match(/^,?(.+),?$/)[1];
            }
        } catch(e) {}        
    }
    return '0,0,0';
};
/**
 *
 * @name flash.htmlOptions
 * @desc The default set of options for the object or embed tag.
 *
**/
$$.htmlOptions = {
    height: 240,
    flashvars: {},
    pluginspage: 'http://www.adobe.com/go/getflashplayer',
    src: '#',
    type: 'application/x-shockwave-flash',
    width: 320        
};
/**
 *
 * @name flash.pluginOptions
 * @desc The default set of options for checking/updating the flash Plugin.
 *
**/
$$.pluginOptions = {
    expressInstall: false,
    update: true,
    version: '6.0.65'
};
/**
 *
 * @name flash.replace
 * @desc The default method for replacing an element with a Flash movie.
 *
**/
$$.replace = function(htmlOptions) {
    this.innerHTML = '<div class="alt">'+this.innerHTML+'</div>';
    jQuery(this)
        .addClass('flash-replaced')
        .prepend($$.transform(htmlOptions));
};
/**
 *
 * @name flash.update
 * @desc The default method for replacing an element with an update message.
 *
**/
$$.update = function(htmlOptions) {
    var url = String(location).split('?');
    url.splice(1,0,'?hasFlash=true&');
    url = url.join('');
    var msg = '<p>This content requires the Flash Player. <a href="http://www.adobe.com/go/getflashplayer">Download Flash Player</a>. Already have Flash Player? <a href="'+url+'">Click here.</a></p>';
    this.innerHTML = '<span class="alt">'+this.innerHTML+'</span>';
    jQuery(this)
        .addClass('flash-update')
        .prepend(msg);
};
/**
 *
 * @desc Convert a hash of html options to a string of attributes, using Function.apply(). 
 * @example toAttributeString.apply(htmlOptions)
 * @result foo="bar" foo="bar"
 *
**/
function toAttributeString() {
    var s = '';
    for(var key in this)
        if(typeof this[key] != 'function')
            s += key+'="'+this[key]+'" ';
    return s;        
};
/**
 *
 * @desc Convert a hash of flashvars to a url-encoded string, using Function.apply(). 
 * @example toFlashvarsString.apply(flashvarsObject)
 * @result foo=bar&foo=bar
 *
**/
function toFlashvarsString() {
    var s = '';
    for(var key in this)
        if(typeof this[key] != 'function')
            s += key+'='+encodeURIComponent(this[key])+'&';
    return s.replace(/&$/, '');        
};
/**
 *
 * @name flash.transform
 * @desc Transform a set of html options into an embed tag.
 * @type String 
 *
 * @example $$.transform(htmlOptions)
 * @result <embed src="foo.swf" ... />
 *
 * Note: The embed tag is NOT standards-compliant, but it 
 * works in all current browsers. flash.transform can be
 * overwritten with a custom function to generate more 
 * standards-compliant markup.
 *
**/
$$.transform = function(htmlOptions) {
    htmlOptions.toString = toAttributeString;
    if(htmlOptions.flashvars) htmlOptions.flashvars.toString = toFlashvarsString;
    return '<embed ' + String(htmlOptions) + '/>';        
};

/**
 *
 * Flash Player 9 Fix (http://blog.deconcept.com/2006/07/28/swfobject-143-released/)
 *
**/
if (window.attachEvent) {
    window.attachEvent("onbeforeunload", function(){
        __flash_unloadHandler = function() {};
        __flash_savedUnloadHandler = function() {};
    });
}
    
})();



