//MooTools, My Object Oriented Javascript Tools. Copyright (c) 2006-2007 Valerio Proietti, <http://mad4milk.net>, MIT Style License.

var MooTools={version:"1.11"};function $defined(A){return(A!=undefined);}function $type(B){if(!$defined(B)){return false;}if(B.htmlElement){return"element";
}var A=typeof B;if(A=="object"&&B.nodeName){switch(B.nodeType){case 1:return"element";case 3:return(/\S/).test(B.nodeValue)?"textnode":"whitespace";}}if(A=="object"||A=="function"){switch(B.constructor){case Array:return"array";
case RegExp:return"regexp";case Class:return"class";}if(typeof B.length=="number"){if(B.item){return"collection";}if(B.callee){return"arguments";}}}return A;
}function $merge(){var C={};for(var B=0;B<arguments.length;B++){for(var E in arguments[B]){var A=arguments[B][E];var D=C[E];if(D&&$type(A)=="object"&&$type(D)=="object"){C[E]=$merge(D,A);
}else{C[E]=A;}}}return C;}var $extend=function(){var A=arguments;if(!A[1]){A=[this,A[0]];}for(var B in A[1]){A[0][B]=A[1][B];}return A[0];};var $native=function(){for(var B=0,A=arguments.length;
B<A;B++){arguments[B].extend=function(C){for(var D in C){if(!this.prototype[D]){this.prototype[D]=C[D];}if(!this[D]){this[D]=$native.generic(D);}}};}};
$native.generic=function(A){return function(B){return this.prototype[A].apply(B,Array.prototype.slice.call(arguments,1));};};$native(Function,Array,String,Number);
function $chk(A){return !!(A||A===0);}function $pick(B,A){return $defined(B)?B:A;}function $random(B,A){return Math.floor(Math.random()*(A-B+1)+B);}function $time(){return new Date().getTime();
}function $clear(A){clearTimeout(A);clearInterval(A);return null;}var Abstract=function(A){A=A||{};A.extend=$extend;return A;};var Window=new Abstract(window);
var Document=new Abstract(document);document.head=document.getElementsByTagName("head")[0];window.xpath=!!(document.evaluate);if(window.ActiveXObject){window.ie=window[window.XMLHttpRequest?"ie7":"ie6"]=true;
}else{if(document.childNodes&&!document.all&&!navigator.taintEnabled){window.webkit=window[window.xpath?"webkit420":"webkit419"]=true;}else{if(document.getBoxObjectFor!=null){window.gecko=true;
}}}window.khtml=window.webkit;Object.extend=$extend;if(typeof HTMLElement=="undefined"){var HTMLElement=function(){};if(window.webkit){document.createElement("iframe");
}HTMLElement.prototype=(window.webkit)?window["[[DOMElement.prototype]]"]:{};}HTMLElement.prototype.htmlElement=function(){};if(window.ie6){try{document.execCommand("BackgroundImageCache",false,true);
}catch(e){}}var Class=function(B){var A=function(){return(arguments[0]!==null&&this.initialize&&$type(this.initialize)=="function")?this.initialize.apply(this,arguments):this;
};$extend(A,this);A.prototype=B;A.constructor=Class;return A;};Class.empty=function(){};Class.prototype={extend:function(B){var C=new this(null);for(var D in B){var A=C[D];
C[D]=Class.Merge(A,B[D]);}return new Class(C);},implement:function(){for(var B=0,A=arguments.length;B<A;B++){$extend(this.prototype,arguments[B]);}}};Class.Merge=function(C,D){if(C&&C!=D){var B=$type(D);
if(B!=$type(C)){return D;}switch(B){case"function":var A=function(){this.parent=arguments.callee.parent;return D.apply(this,arguments);};A.parent=C;return A;
case"object":return $merge(C,D);}}return D;};var Chain=new Class({chain:function(A){this.chains=this.chains||[];this.chains.push(A);return this;},callChain:function(){if(this.chains&&this.chains.length){this.chains.shift().delay(10,this);
}},clearChain:function(){this.chains=[];}});var Events=new Class({addEvent:function(B,A){if(A!=Class.empty){this.$events=this.$events||{};this.$events[B]=this.$events[B]||[];
this.$events[B].include(A);}return this;},fireEvent:function(C,B,A){if(this.$events&&this.$events[C]){this.$events[C].each(function(D){D.create({bind:this,delay:A,"arguments":B})();
},this);}return this;},removeEvent:function(B,A){if(this.$events&&this.$events[B]){this.$events[B].remove(A);}return this;}});var Options=new Class({setOptions:function(){this.options=$merge.apply(null,[this.options].extend(arguments));
if(this.addEvent){for(var A in this.options){if($type(this.options[A]=="function")&&(/^on[A-Z]/).test(A)){this.addEvent(A,this.options[A]);}}}return this;
}});Array.extend({forEach:function(C,D){for(var B=0,A=this.length;B<A;B++){C.call(D,this[B],B,this);}},filter:function(D,E){var C=[];for(var B=0,A=this.length;
B<A;B++){if(D.call(E,this[B],B,this)){C.push(this[B]);}}return C;},map:function(D,E){var C=[];for(var B=0,A=this.length;B<A;B++){C[B]=D.call(E,this[B],B,this);
}return C;},every:function(C,D){for(var B=0,A=this.length;B<A;B++){if(!C.call(D,this[B],B,this)){return false;}}return true;},some:function(C,D){for(var B=0,A=this.length;
B<A;B++){if(C.call(D,this[B],B,this)){return true;}}return false;},indexOf:function(C,D){var A=this.length;for(var B=(D<0)?Math.max(0,A+D):D||0;B<A;B++){if(this[B]===C){return B;
}}return -1;},copy:function(D,C){D=D||0;if(D<0){D=this.length+D;}C=C||(this.length-D);var A=[];for(var B=0;B<C;B++){A[B]=this[D++];}return A;},remove:function(C){var B=0;
var A=this.length;while(B<A){if(this[B]===C){this.splice(B,1);A--;}else{B++;}}return this;},contains:function(A,B){return this.indexOf(A,B)!=-1;},associate:function(C){var D={},B=Math.min(this.length,C.length);
for(var A=0;A<B;A++){D[C[A]]=this[A];}return D;},extend:function(C){for(var B=0,A=C.length;B<A;B++){this.push(C[B]);}return this;},merge:function(C){for(var B=0,A=C.length;
B<A;B++){this.include(C[B]);}return this;},include:function(A){if(!this.contains(A)){this.push(A);}return this;},getRandom:function(){return this[$random(0,this.length-1)]||null;
},getLast:function(){return this[this.length-1]||null;}});Array.prototype.each=Array.prototype.forEach;Array.each=Array.forEach;function $A(A){return Array.copy(A);
}function $each(C,B,D){if(C&&typeof C.length=="number"&&$type(C)!="object"){Array.forEach(C,B,D);}else{for(var A in C){B.call(D||C,C[A],A);}}}Array.prototype.test=Array.prototype.contains;
String.extend({test:function(A,B){return(($type(A)=="string")?new RegExp(A,B):A).test(this);},toInt:function(){return parseInt(this,10);},toFloat:function(){return parseFloat(this);
},camelCase:function(){return this.replace(/-\D/g,function(A){return A.charAt(1).toUpperCase();});},hyphenate:function(){return this.replace(/\w[A-Z]/g,function(A){return(A.charAt(0)+"-"+A.charAt(1).toLowerCase());
});},capitalize:function(){return this.replace(/\b[a-z]/g,function(A){return A.toUpperCase();});},trim:function(){return this.replace(/^\s+|\s+$/g,"");
},clean:function(){return this.replace(/\s{2,}/g," ").trim();},rgbToHex:function(B){var A=this.match(/\d{1,3}/g);return(A)?A.rgbToHex(B):false;},hexToRgb:function(B){var A=this.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/);
return(A)?A.slice(1).hexToRgb(B):false;},contains:function(A,B){return(B)?(B+this+B).indexOf(B+A+B)>-1:this.indexOf(A)>-1;},escapeRegExp:function(){return this.replace(/([.*+?^${}()|[\]\/\\])/g,"\\$1");
}});Array.extend({rgbToHex:function(D){if(this.length<3){return false;}if(this.length==4&&this[3]==0&&!D){return"transparent";}var B=[];for(var A=0;A<3;
A++){var C=(this[A]-0).toString(16);B.push((C.length==1)?"0"+C:C);}return D?B:"#"+B.join("");},hexToRgb:function(C){if(this.length!=3){return false;}var A=[];
for(var B=0;B<3;B++){A.push(parseInt((this[B].length==1)?this[B]+this[B]:this[B],16));}return C?A:"rgb("+A.join(",")+")";}});Function.extend({create:function(A){var B=this;
A=$merge({bind:B,event:false,"arguments":null,delay:false,periodical:false,attempt:false},A);if($chk(A.arguments)&&$type(A.arguments)!="array"){A.arguments=[A.arguments];
}return function(E){var C;if(A.event){E=E||window.event;C=[(A.event===true)?E:new A.event(E)];if(A.arguments){C.extend(A.arguments);}}else{C=A.arguments||arguments;
}var F=function(){return B.apply($pick(A.bind,B),C);};if(A.delay){return setTimeout(F,A.delay);}if(A.periodical){return setInterval(F,A.periodical);}if(A.attempt){try{return F();
}catch(D){return false;}}return F();};},pass:function(A,B){return this.create({"arguments":A,bind:B});},attempt:function(A,B){return this.create({"arguments":A,bind:B,attempt:true})();
},bind:function(B,A){return this.create({bind:B,"arguments":A});},bindAsEventListener:function(B,A){return this.create({bind:B,event:true,"arguments":A});
},delay:function(B,C,A){return this.create({delay:B,bind:C,"arguments":A})();},periodical:function(A,C,B){return this.create({periodical:A,bind:C,"arguments":B})();
}});Number.extend({toInt:function(){return parseInt(this);},toFloat:function(){return parseFloat(this);},limit:function(B,A){return Math.min(A,Math.max(B,this));
},round:function(A){A=Math.pow(10,A||0);return Math.round(this*A)/A;},times:function(B){for(var A=0;A<this;A++){B(A);}}});var Element=new Class({initialize:function(D,C){if($type(D)=="string"){if(window.ie&&C&&(C.name||C.type)){var A=(C.name)?' name="'+C.name+'"':"";
var B=(C.type)?' type="'+C.type+'"':"";delete C.name;delete C.type;D="<"+D+A+B+">";}D=document.createElement(D);}D=$(D);return(!C||!D)?D:D.set(C);}});var Elements=new Class({initialize:function(A){return(A)?$extend(A,this):this;
}});Elements.extend=function(A){for(var B in A){this.prototype[B]=A[B];this[B]=$native.generic(B);}};function $(B){if(!B){return null;}if(B.htmlElement){return Garbage.collect(B);
}if([window,document].contains(B)){return B;}var A=$type(B);if(A=="string"){B=document.getElementById(B);A=(B)?"element":false;}if(A!="element"){return null;
}if(B.htmlElement){return Garbage.collect(B);}if(["object","embed"].contains(B.tagName.toLowerCase())){return B;}$extend(B,Element.prototype);B.htmlElement=function(){};
return Garbage.collect(B);}document.getElementsBySelector=document.getElementsByTagName;function $$(){var D=[];for(var C=0,B=arguments.length;C<B;C++){var A=arguments[C];
switch($type(A)){case"element":D.push(A);case"boolean":break;case false:break;case"string":A=document.getElementsBySelector(A,true);default:D.extend(A);
}}return $$.unique(D);}$$.unique=function(G){var D=[];for(var C=0,A=G.length;C<A;C++){if(G[C].$included){continue;}var B=$(G[C]);if(B&&!B.$included){B.$included=true;
D.push(B);}}for(var F=0,E=D.length;F<E;F++){D[F].$included=null;}return new Elements(D);};Elements.Multi=function(A){return function(){var D=arguments;
var B=[];var G=true;for(var E=0,C=this.length,F;E<C;E++){F=this[E][A].apply(this[E],D);if($type(F)!="element"){G=false;}B.push(F);}return(G)?$$.unique(B):B;
};};Element.extend=function(A){for(var B in A){HTMLElement.prototype[B]=A[B];Element.prototype[B]=A[B];Element[B]=$native.generic(B);var C=(Array.prototype[B])?B+"Elements":B;
Elements.prototype[C]=Elements.Multi(B);}};Element.extend({set:function(A){for(var C in A){var B=A[C];switch(C){case"styles":this.setStyles(B);break;case"events":if(this.addEvents){this.addEvents(B);
}break;case"properties":this.setProperties(B);break;default:this.setProperty(C,B);}}return this;},inject:function(C,A){C=$(C);switch(A){case"before":C.parentNode.insertBefore(this,C);
break;case"after":var B=C.getNext();if(!B){C.parentNode.appendChild(this);}else{C.parentNode.insertBefore(this,B);}break;case"top":var D=C.firstChild;if(D){C.insertBefore(this,D);
break;}default:C.appendChild(this);}return this;},injectBefore:function(A){return this.inject(A,"before");},injectAfter:function(A){return this.inject(A,"after");
},injectInside:function(A){return this.inject(A,"bottom");},injectTop:function(A){return this.inject(A,"top");},adopt:function(){var A=[];$each(arguments,function(B){A=A.concat(B);
});$$(A).inject(this);return this;},remove:function(){return this.parentNode.removeChild(this);},clone:function(C){var B=$(this.cloneNode(C!==false));if(!B.$events){return B;
}B.$events={};for(var A in this.$events){B.$events[A]={keys:$A(this.$events[A].keys),values:$A(this.$events[A].values)};}return B.removeEvents();},replaceWith:function(A){A=$(A);
this.parentNode.replaceChild(A,this);return A;},appendText:function(A){this.appendChild(document.createTextNode(A));return this;},hasClass:function(A){return this.className.contains(A," ");
},addClass:function(A){if(!this.hasClass(A)){this.className=(this.className+" "+A).clean();}return this;},removeClass:function(A){this.className=this.className.replace(new RegExp("(^|\\s)"+A+"(?:\\s|$)"),"$1").clean();
return this;},toggleClass:function(A){return this.hasClass(A)?this.removeClass(A):this.addClass(A);},setStyle:function(B,A){switch(B){case"opacity":return this.setOpacity(parseFloat(A));
case"float":B=(window.ie)?"styleFloat":"cssFloat";}B=B.camelCase();switch($type(A)){case"number":if(!["zIndex","zoom"].contains(B)){A+="px";}break;case"array":A="rgb("+A.join(",")+")";
}this.style[B]=A;return this;},setStyles:function(A){switch($type(A)){case"object":Element.setMany(this,"setStyle",A);break;case"string":this.style.cssText=A;
}return this;},setOpacity:function(A){if(A==0){if(this.style.visibility!="hidden"){this.style.visibility="hidden";}}else{if(this.style.visibility!="visible"){this.style.visibility="visible";
}}if(!this.currentStyle||!this.currentStyle.hasLayout){this.style.zoom=1;}if(window.ie){this.style.filter=(A==1)?"":"alpha(opacity="+A*100+")";}this.style.opacity=this.$tmp.opacity=A;
return this;},getStyle:function(C){C=C.camelCase();var A=this.style[C];if(!$chk(A)){if(C=="opacity"){return this.$tmp.opacity;}A=[];for(var B in Element.Styles){if(C==B){Element.Styles[B].each(function(F){var E=this.getStyle(F);
A.push(parseInt(E)?E:"0px");},this);if(C=="border"){var D=A.every(function(E){return(E==A[0]);});return(D)?A[0]:false;}return A.join(" ");}}if(C.contains("border")){if(Element.Styles.border.contains(C)){return["Width","Style","Color"].map(function(E){return this.getStyle(C+E);
},this).join(" ");}else{if(Element.borderShort.contains(C)){return["Top","Right","Bottom","Left"].map(function(E){return this.getStyle("border"+E+C.replace("border",""));
},this).join(" ");}}}if(document.defaultView){A=document.defaultView.getComputedStyle(this,null).getPropertyValue(C.hyphenate());}else{if(this.currentStyle){A=this.currentStyle[C];
}}}if(window.ie){A=Element.fixStyle(C,A,this);}if(A&&C.test(/color/i)&&A.contains("rgb")){return A.split("rgb").splice(1,4).map(function(E){return E.rgbToHex();
}).join(" ");}return A;},getStyles:function(){return Element.getMany(this,"getStyle",arguments);},walk:function(A,C){A+="Sibling";var B=(C)?this[C]:this[A];
while(B&&$type(B)!="element"){B=B[A];}return $(B);},getPrevious:function(){return this.walk("previous");},getNext:function(){return this.walk("next");},getFirst:function(){return this.walk("next","firstChild");
},getLast:function(){return this.walk("previous","lastChild");},getParent:function(){return $(this.parentNode);},getChildren:function(){return $$(this.childNodes);
},hasChild:function(A){return !!$A(this.getElementsByTagName("*")).contains(A);},getProperty:function(D){var B=Element.Properties[D];if(B){return this[B];
}var A=Element.PropertiesIFlag[D]||0;if(!window.ie||A){return this.getAttribute(D,A);}var C=this.attributes[D];return(C)?C.nodeValue:null;},removeProperty:function(B){var A=Element.Properties[B];
if(A){this[A]="";}else{this.removeAttribute(B);}return this;},getProperties:function(){return Element.getMany(this,"getProperty",arguments);},setProperty:function(C,B){var A=Element.Properties[C];
if(A){this[A]=B;}else{this.setAttribute(C,B);}return this;},setProperties:function(A){return Element.setMany(this,"setProperty",A);},setHTML:function(){this.innerHTML=$A(arguments).join("");
return this;},setText:function(B){var A=this.getTag();if(["style","script"].contains(A)){if(window.ie){if(A=="style"){this.styleSheet.cssText=B;}else{if(A=="script"){this.setProperty("text",B);
}}return this;}else{this.removeChild(this.firstChild);return this.appendText(B);}}this[$defined(this.innerText)?"innerText":"textContent"]=B;return this;
},getText:function(){var A=this.getTag();if(["style","script"].contains(A)){if(window.ie){if(A=="style"){return this.styleSheet.cssText;}else{if(A=="script"){return this.getProperty("text");
}}}else{return this.innerHTML;}}return($pick(this.innerText,this.textContent));},getTag:function(){return this.tagName.toLowerCase();},empty:function(){Garbage.trash(this.getElementsByTagName("*"));
return this.setHTML("");}});Element.fixStyle=function(E,A,D){if($chk(parseInt(A))){return A;}if(["height","width"].contains(E)){var B=(E=="width")?["left","right"]:["top","bottom"];
var C=0;B.each(function(F){C+=D.getStyle("border-"+F+"-width").toInt()+D.getStyle("padding-"+F).toInt();});return D["offset"+E.capitalize()]-C+"px";}else{if(E.test(/border(.+)Width|margin|padding/)){return"0px";
}}return A;};Element.Styles={border:[],padding:[],margin:[]};["Top","Right","Bottom","Left"].each(function(B){for(var A in Element.Styles){Element.Styles[A].push(A+B);
}});Element.borderShort=["borderWidth","borderStyle","borderColor"];Element.getMany=function(B,D,C){var A={};$each(C,function(E){A[E]=B[D](E);});return A;
};Element.setMany=function(B,D,C){for(var A in C){B[D](A,C[A]);}return B;};Element.Properties=new Abstract({"class":"className","for":"htmlFor",colspan:"colSpan",rowspan:"rowSpan",accesskey:"accessKey",tabindex:"tabIndex",maxlength:"maxLength",readonly:"readOnly",frameborder:"frameBorder",value:"value",disabled:"disabled",checked:"checked",multiple:"multiple",selected:"selected"});
Element.PropertiesIFlag={href:2,src:2};Element.Methods={Listeners:{addListener:function(B,A){if(this.addEventListener){this.addEventListener(B,A,false);
}else{this.attachEvent("on"+B,A);}return this;},removeListener:function(B,A){if(this.removeEventListener){this.removeEventListener(B,A,false);}else{this.detachEvent("on"+B,A);
}return this;}}};window.extend(Element.Methods.Listeners);document.extend(Element.Methods.Listeners);Element.extend(Element.Methods.Listeners);var Garbage={elements:[],collect:function(A){if(!A.$tmp){Garbage.elements.push(A);
A.$tmp={opacity:1};}return A;},trash:function(D){for(var B=0,A=D.length,C;B<A;B++){if(!(C=D[B])||!C.$tmp){continue;}if(C.$events){C.fireEvent("trash").removeEvents();
}for(var E in C.$tmp){C.$tmp[E]=null;}for(var F in Element.prototype){C[F]=null;}Garbage.elements[Garbage.elements.indexOf(C)]=null;C.htmlElement=C.$tmp=C=null;
}Garbage.elements.remove(null);},empty:function(){Garbage.collect(window);Garbage.collect(document);Garbage.trash(Garbage.elements);}};window.addListener("beforeunload",function(){window.addListener("unload",Garbage.empty);
if(window.ie){window.addListener("unload",CollectGarbage);}});var Event=new Class({initialize:function(C){if(C&&C.$extended){return C;}this.$extended=true;
C=C||window.event;this.event=C;this.type=C.type;this.target=C.target||C.srcElement;if(this.target.nodeType==3){this.target=this.target.parentNode;}this.shift=C.shiftKey;
this.control=C.ctrlKey;this.alt=C.altKey;this.meta=C.metaKey;if(["DOMMouseScroll","mousewheel"].contains(this.type)){this.wheel=(C.wheelDelta)?C.wheelDelta/120:-(C.detail||0)/3;
}else{if(this.type.contains("key")){this.code=C.which||C.keyCode;for(var B in Event.keys){if(Event.keys[B]==this.code){this.key=B;break;}}if(this.type=="keydown"){var A=this.code-111;
if(A>0&&A<13){this.key="f"+A;}}this.key=this.key||String.fromCharCode(this.code).toLowerCase();}else{if(this.type.test(/(click|mouse|menu)/)){this.page={x:C.pageX||C.clientX+document.documentElement.scrollLeft,y:C.pageY||C.clientY+document.documentElement.scrollTop};
this.client={x:C.pageX?C.pageX-window.pageXOffset:C.clientX,y:C.pageY?C.pageY-window.pageYOffset:C.clientY};this.rightClick=(C.which==3)||(C.button==2);
switch(this.type){case"mouseover":this.relatedTarget=C.relatedTarget||C.fromElement;break;case"mouseout":this.relatedTarget=C.relatedTarget||C.toElement;
}this.fixRelatedTarget();}}}return this;},stop:function(){return this.stopPropagation().preventDefault();},stopPropagation:function(){if(this.event.stopPropagation){this.event.stopPropagation();
}else{this.event.cancelBubble=true;}return this;},preventDefault:function(){if(this.event.preventDefault){this.event.preventDefault();}else{this.event.returnValue=false;
}return this;}});Event.fix={relatedTarget:function(){if(this.relatedTarget&&this.relatedTarget.nodeType==3){this.relatedTarget=this.relatedTarget.parentNode;
}},relatedTargetGecko:function(){try{Event.fix.relatedTarget.call(this);}catch(A){this.relatedTarget=this.target;}}};Event.prototype.fixRelatedTarget=(window.gecko)?Event.fix.relatedTargetGecko:Event.fix.relatedTarget;
Event.keys=new Abstract({enter:13,up:38,down:40,left:37,right:39,esc:27,space:32,backspace:8,tab:9,"delete":46});Element.Methods.Events={addEvent:function(C,B){this.$events=this.$events||{};
this.$events[C]=this.$events[C]||{keys:[],values:[]};if(this.$events[C].keys.contains(B)){return this;}this.$events[C].keys.push(B);var A=C;var D=Element.Events[C];
if(D){if(D.add){D.add.call(this,B);}if(D.map){B=D.map;}if(D.type){A=D.type;}}if(!this.addEventListener){B=B.create({bind:this,event:true});}this.$events[C].values.push(B);
return(Element.NativeEvents.contains(A))?this.addListener(A,B):this;},removeEvent:function(C,B){if(!this.$events||!this.$events[C]){return this;}var F=this.$events[C].keys.indexOf(B);
if(F==-1){return this;}var A=this.$events[C].keys.splice(F,1)[0];var E=this.$events[C].values.splice(F,1)[0];var D=Element.Events[C];if(D){if(D.remove){D.remove.call(this,B);
}if(D.type){C=D.type;}}return(Element.NativeEvents.contains(C))?this.removeListener(C,E):this;},addEvents:function(A){return Element.setMany(this,"addEvent",A);
},removeEvents:function(A){if(!this.$events){return this;}if(!A){for(var B in this.$events){this.removeEvents(B);}this.$events=null;}else{if(this.$events[A]){this.$events[A].keys.each(function(C){this.removeEvent(A,C);
},this);this.$events[A]=null;}}return this;},fireEvent:function(C,B,A){if(this.$events&&this.$events[C]){this.$events[C].keys.each(function(D){D.create({bind:this,delay:A,"arguments":B})();
},this);}return this;},cloneEvents:function(C,A){if(!C.$events){return this;}if(!A){for(var B in C.$events){this.cloneEvents(C,B);}}else{if(C.$events[A]){C.$events[A].keys.each(function(D){this.addEvent(A,D);
},this);}}return this;}};window.extend(Element.Methods.Events);document.extend(Element.Methods.Events);Element.extend(Element.Methods.Events);Element.Events=new Abstract({mouseenter:{type:"mouseover",map:function(A){A=new Event(A);
if(A.relatedTarget!=this&&!this.hasChild(A.relatedTarget)){this.fireEvent("mouseenter",A);}}},mouseleave:{type:"mouseout",map:function(A){A=new Event(A);
if(A.relatedTarget!=this&&!this.hasChild(A.relatedTarget)){this.fireEvent("mouseleave",A);}}},mousewheel:{type:(window.gecko)?"DOMMouseScroll":"mousewheel"}});
Element.NativeEvents=["click","dblclick","mouseup","mousedown","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","keydown","keypress","keyup","load","unload","beforeunload","resize","move","focus","blur","change","submit","reset","select","error","abort","contextmenu","scroll"];
Function.extend({bindWithEvent:function(B,A){return this.create({bind:B,"arguments":A,event:Event});}});Elements.extend({filterByTag:function(A){return new Elements(this.filter(function(B){return(Element.getTag(B)==A);
}));},filterByClass:function(A,C){var B=this.filter(function(D){return(D.className&&D.className.contains(A," "));});return(C)?B:new Elements(B);},filterById:function(C,B){var A=this.filter(function(D){return(D.id==C);
});return(B)?A:new Elements(A);},filterByAttribute:function(B,A,D,E){var C=this.filter(function(F){var G=Element.getProperty(F,B);if(!G){return false;}if(!A){return true;
}switch(A){case"=":return(G==D);case"*=":return(G.contains(D));case"^=":return(G.substr(0,D.length)==D);case"$=":return(G.substr(G.length-D.length)==D);
case"!=":return(G!=D);case"~=":return G.contains(D," ");}return false;});return(E)?C:new Elements(C);}});function $E(A,B){return($(B)||document).getElement(A);
}function $ES(A,B){return($(B)||document).getElementsBySelector(A);}$$.shared={regexp:/^(\w*|\*)(?:#([\w-]+)|\.([\w-]+))?(?:\[(\w+)(?:([!*^$]?=)["']?([^"'\]]*)["']?)?])?$/,xpath:{getParam:function(B,D,E,C){var A=[D.namespaceURI?"xhtml:":"",E[1]];
if(E[2]){A.push('[@id="',E[2],'"]');}if(E[3]){A.push('[contains(concat(" ", @class, " "), " ',E[3],' ")]');}if(E[4]){if(E[5]&&E[6]){switch(E[5]){case"*=":A.push("[contains(@",E[4],', "',E[6],'")]');
break;case"^=":A.push("[starts-with(@",E[4],', "',E[6],'")]');break;case"$=":A.push("[substring(@",E[4],", string-length(@",E[4],") - ",E[6].length,' + 1) = "',E[6],'"]');
break;case"=":A.push("[@",E[4],'="',E[6],'"]');break;case"!=":A.push("[@",E[4],'!="',E[6],'"]');}}else{A.push("[@",E[4],"]");}}B.push(A.join(""));return B;
},getItems:function(B,E,G){var F=[];var A=document.evaluate(".//"+B.join("//"),E,$$.shared.resolver,XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,null);for(var D=0,C=A.snapshotLength;
D<C;D++){F.push(A.snapshotItem(D));}return(G)?F:new Elements(F.map($));}},normal:{getParam:function(A,C,E,B){if(B==0){if(E[2]){var D=C.getElementById(E[2]);
if(!D||((E[1]!="*")&&(Element.getTag(D)!=E[1]))){return false;}A=[D];}else{A=$A(C.getElementsByTagName(E[1]));}}else{A=$$.shared.getElementsByTagName(A,E[1]);
if(E[2]){A=Elements.filterById(A,E[2],true);}}if(E[3]){A=Elements.filterByClass(A,E[3],true);}if(E[4]){A=Elements.filterByAttribute(A,E[4],E[5],E[6],true);
}return A;},getItems:function(A,B,C){return(C)?A:$$.unique(A);}},resolver:function(A){return(A=="xhtml")?"http://www.w3.org/1999/xhtml":false;},getElementsByTagName:function(D,C){var E=[];
for(var B=0,A=D.length;B<A;B++){E.extend(D[B].getElementsByTagName(C));}return E;}};$$.shared.method=(window.xpath)?"xpath":"normal";Element.Methods.Dom={getElements:function(A,H){var C=[];
A=A.trim().split(" ");for(var E=0,D=A.length;E<D;E++){var F=A[E];var G=F.match($$.shared.regexp);if(!G){break;}G[1]=G[1]||"*";var B=$$.shared[$$.shared.method].getParam(C,this,G,E);
if(!B){break;}C=B;}return $$.shared[$$.shared.method].getItems(C,this,H);},getElement:function(A){return $(this.getElements(A,true)[0]||false);},getElementsBySelector:function(A,E){var D=[];
A=A.split(",");for(var C=0,B=A.length;C<B;C++){D=D.concat(this.getElements(A[C],true));}return(E)?D:$$.unique(D);}};Element.extend({getElementById:function(C){var B=document.getElementById(C);
if(!B){return false;}for(var A=B.parentNode;A!=this;A=A.parentNode){if(!A){return false;}}return B;},getElementsByClassName:function(A){return this.getElements("."+A);
}});document.extend(Element.Methods.Dom);Element.extend(Element.Methods.Dom);Element.extend({getValue:function(){switch(this.getTag()){case"select":var A=[];
$each(this.options,function(B){if(B.selected){A.push($pick(B.value,B.text));}});return(this.multiple)?A:A[0];case"input":if(!(this.checked&&["checkbox","radio"].contains(this.type))&&!["hidden","text","password"].contains(this.type)){break;
}case"textarea":return this.value;}return false;},getFormElements:function(){return $$(this.getElementsByTagName("input"),this.getElementsByTagName("select"),this.getElementsByTagName("textarea"));
},toQueryString:function(){var A=[];this.getFormElements().each(function(D){var C=D.name;var E=D.getValue();if(E===false||!C||D.disabled){return ;}var B=function(F){A.push(C+"="+encodeURIComponent(F));
};if($type(E)=="array"){E.each(B);}else{B(E);}});return A.join("&");}});Element.extend({scrollTo:function(A,B){this.scrollLeft=A;this.scrollTop=B;},getSize:function(){return{scroll:{x:this.scrollLeft,y:this.scrollTop},size:{x:this.offsetWidth,y:this.offsetHeight},scrollSize:{x:this.scrollWidth,y:this.scrollHeight}};
},getPosition:function(A){A=A||[];var B=this,D=0,C=0;do{D+=B.offsetLeft||0;C+=B.offsetTop||0;B=B.offsetParent;}while(B);A.each(function(E){D-=E.scrollLeft||0;
C-=E.scrollTop||0;});return{x:D,y:C};},getTop:function(A){return this.getPosition(A).y;},getLeft:function(A){return this.getPosition(A).x;},getCoordinates:function(B){var A=this.getPosition(B);
var C={width:this.offsetWidth,height:this.offsetHeight,left:A.x,top:A.y};C.right=C.left+C.width;C.bottom=C.top+C.height;return C;}});Element.Events.domready={add:function(B){if(window.loaded){B.call(this);
return ;}var A=function(){if(window.loaded){return ;}window.loaded=true;window.timer=$clear(window.timer);this.fireEvent("domready");}.bind(this);if(document.readyState&&window.webkit){window.timer=function(){if(["loaded","complete"].contains(document.readyState)){A();
}}.periodical(50);}else{if(document.readyState&&window.ie){if(!$("ie_ready")){var C=(window.location.protocol=="https:")?"://0":"javascript:void(0)";document.write('<script id="ie_ready" defer src="'+C+'"><\/script>');
$("ie_ready").onreadystatechange=function(){if(this.readyState=="complete"){A();}};}}else{window.addListener("load",A);document.addListener("DOMContentLoaded",A);
}}}};window.onDomReady=function(A){return this.addEvent("domready",A);};window.extend({getWidth:function(){if(this.webkit419){return this.innerWidth;}if(this.opera){return document.body.clientWidth;
}return document.documentElement.clientWidth;},getHeight:function(){if(this.webkit419){return this.innerHeight;}if(this.opera){return document.body.clientHeight;
}return document.documentElement.clientHeight;},getScrollWidth:function(){if(this.ie){return Math.max(document.documentElement.offsetWidth,document.documentElement.scrollWidth);
}if(this.webkit){return document.body.scrollWidth;}return document.documentElement.scrollWidth;},getScrollHeight:function(){if(this.ie){return Math.max(document.documentElement.offsetHeight,document.documentElement.scrollHeight);
}if(this.webkit){return document.body.scrollHeight;}return document.documentElement.scrollHeight;},getScrollLeft:function(){return this.pageXOffset||document.documentElement.scrollLeft;
},getScrollTop:function(){return this.pageYOffset||document.documentElement.scrollTop;},getSize:function(){return{size:{x:this.getWidth(),y:this.getHeight()},scrollSize:{x:this.getScrollWidth(),y:this.getScrollHeight()},scroll:{x:this.getScrollLeft(),y:this.getScrollTop()}};
},getPosition:function(){return{x:0,y:0};}});var Fx={};Fx.Base=new Class({options:{onStart:Class.empty,onComplete:Class.empty,onCancel:Class.empty,transition:function(A){return -(Math.cos(Math.PI*A)-1)/2;
},duration:500,unit:"px",wait:true,fps:50},initialize:function(A){this.element=this.element||null;this.setOptions(A);if(this.options.initialize){this.options.initialize.call(this);
}},step:function(){var A=$time();if(A<this.time+this.options.duration){this.delta=this.options.transition((A-this.time)/this.options.duration);this.setNow();
this.increase();}else{this.stop(true);this.set(this.to);this.fireEvent("onComplete",this.element,10);this.callChain();}},set:function(A){this.now=A;this.increase();
return this;},setNow:function(){this.now=this.compute(this.from,this.to);},compute:function(B,A){return(A-B)*this.delta+B;},start:function(B,A){if(!this.options.wait){this.stop();
}else{if(this.timer){return this;}}this.from=B;this.to=A;this.change=this.to-this.from;this.time=$time();this.timer=this.step.periodical(Math.round(1000/this.options.fps),this);
this.fireEvent("onStart",this.element);return this;},stop:function(A){if(!this.timer){return this;}this.timer=$clear(this.timer);if(!A){this.fireEvent("onCancel",this.element);
}return this;},custom:function(B,A){return this.start(B,A);},clearTimer:function(A){return this.stop(A);}});Fx.Base.implement(new Chain,new Events,new Options);
Fx.CSS={select:function(B,C){if(B.test(/color/i)){return this.Color;}var A=$type(C);if((A=="array")||(A=="string"&&C.contains(" "))){return this.Multi;
}return this.Single;},parse:function(C,D,A){if(!A.push){A=[A];}var F=A[0],E=A[1];if(!$chk(E)){E=F;F=C.getStyle(D);}var B=this.select(D,E);return{from:B.parse(F),to:B.parse(E),css:B};
}};Fx.CSS.Single={parse:function(A){return parseFloat(A);},getNow:function(C,B,A){return A.compute(C,B);},getValue:function(C,A,B){if(A=="px"&&B!="opacity"){C=Math.round(C);
}return C+A;}};Fx.CSS.Multi={parse:function(A){return A.push?A:A.split(" ").map(function(B){return parseFloat(B);});},getNow:function(E,D,C){var A=[];for(var B=0;
B<E.length;B++){A[B]=C.compute(E[B],D[B]);}return A;},getValue:function(C,A,B){if(A=="px"&&B!="opacity"){C=C.map(Math.round);}return C.join(A+" ")+A;}};
Fx.CSS.Color={parse:function(A){return A.push?A:A.hexToRgb(true);},getNow:function(E,D,C){var A=[];for(var B=0;B<E.length;B++){A[B]=Math.round(C.compute(E[B],D[B]));
}return A;},getValue:function(A){return"rgb("+A.join(",")+")";}};Fx.Style=Fx.Base.extend({initialize:function(B,C,A){this.element=$(B);this.property=C;
this.parent(A);},hide:function(){return this.set(0);},setNow:function(){this.now=this.css.getNow(this.from,this.to,this);},set:function(A){this.css=Fx.CSS.select(this.property,A);
return this.parent(this.css.parse(A));},start:function(C,B){if(this.timer&&this.options.wait){return this;}var A=Fx.CSS.parse(this.element,this.property,[C,B]);
this.css=A.css;return this.parent(A.from,A.to);},increase:function(){this.element.setStyle(this.property,this.css.getValue(this.now,this.options.unit,this.property));
}});Element.extend({effect:function(B,A){return new Fx.Style(this,B,A);}});Fx.Elements=Fx.Base.extend({initialize:function(B,A){this.elements=$$(B);this.parent(A);
},setNow:function(){for(var C in this.from){var F=this.from[C],E=this.to[C],B=this.css[C],A=this.now[C]={};for(var D in F){A[D]=B[D].getNow(F[D],E[D],this);
}}},set:function(G){var B={};this.css={};for(var D in G){var F=G[D],C=this.css[D]={},A=B[D]={};for(var E in F){C[E]=Fx.CSS.select(E,F[E]);A[E]=C[E].parse(F[E]);
}}return this.parent(B);},start:function(D){if(this.timer&&this.options.wait){return this;}this.now={};this.css={};var I={},J={};for(var E in D){var G=D[E],A=I[E]={},H=J[E]={},C=this.css[E]={};
for(var B in G){var F=Fx.CSS.parse(this.elements[E],B,G[B]);A[B]=F.from;H[B]=F.to;C[B]=F.css;}}return this.parent(I,J);},increase:function(){for(var C in this.now){var A=this.now[C],B=this.css[C];
for(var D in A){this.elements[C].setStyle(D,B[D].getValue(A[D],this.options.unit,D));}}}});Fx.Slide=Fx.Base.extend({options:{mode:"vertical"},initialize:function(B,A){this.element=$(B);
this.wrapper=new Element("div",{styles:$extend(this.element.getStyles("margin"),{overflow:"hidden"})}).injectAfter(this.element).adopt(this.element);this.element.setStyle("margin",0);
this.setOptions(A);this.now=[];this.parent(this.options);this.open=true;this.addEvent("onComplete",function(){this.open=(this.now[0]===0);});if(window.webkit419){this.addEvent("onComplete",function(){if(this.open){this.element.remove().inject(this.wrapper);
}});}},setNow:function(){for(var A=0;A<2;A++){this.now[A]=this.compute(this.from[A],this.to[A]);}},vertical:function(){this.margin="margin-top";this.layout="height";
this.offset=this.element.offsetHeight;},horizontal:function(){this.margin="margin-left";this.layout="width";this.offset=this.element.offsetWidth;},slideIn:function(A){this[A||this.options.mode]();
return this.start([this.element.getStyle(this.margin).toInt(),this.wrapper.getStyle(this.layout).toInt()],[0,this.offset]);},slideOut:function(A){this[A||this.options.mode]();
return this.start([this.element.getStyle(this.margin).toInt(),this.wrapper.getStyle(this.layout).toInt()],[-this.offset,0]);},hide:function(A){this[A||this.options.mode]();
this.open=false;return this.set([-this.offset,0]);},show:function(A){this[A||this.options.mode]();this.open=true;return this.set([0,this.offset]);},toggle:function(A){if(this.wrapper.offsetHeight==0||this.wrapper.offsetWidth==0){return this.slideIn(A);
}return this.slideOut(A);},increase:function(){this.element.setStyle(this.margin,this.now[0]+this.options.unit);this.wrapper.setStyle(this.layout,this.now[1]+this.options.unit);
}});Fx.Transition=function(B,A){A=A||[];if($type(A)!="array"){A=[A];}return $extend(B,{easeIn:function(C){return B(C,A);},easeOut:function(C){return 1-B(1-C,A);
},easeInOut:function(C){return(C<=0.5)?B(2*C,A)/2:(2-B(2*(1-C),A))/2;}});};Fx.Transitions=new Abstract({linear:function(A){return A;}});Fx.Transitions.extend=function(A){for(var B in A){Fx.Transitions[B]=new Fx.Transition(A[B]);
Fx.Transitions.compat(B);}};Fx.Transitions.compat=function(A){["In","Out","InOut"].each(function(B){Fx.Transitions[A.toLowerCase()+B]=Fx.Transitions[A]["ease"+B];
});};Fx.Transitions.extend({Pow:function(B,A){return Math.pow(B,A[0]||6);},Expo:function(A){return Math.pow(2,8*(A-1));},Circ:function(A){return 1-Math.sin(Math.acos(A));
},Sine:function(A){return 1-Math.sin((1-A)*Math.PI/2);},Back:function(B,A){A=A[0]||1.618;return Math.pow(B,2)*((A+1)*B-A);},Bounce:function(D){var C;for(var B=0,A=1;
1;B+=A,A/=2){if(D>=(7-4*B)/11){C=-Math.pow((11-6*B-11*D)/4,2)+A*A;break;}}return C;},Elastic:function(B,A){return Math.pow(2,10*--B)*Math.cos(20*B*Math.PI*(A[0]||1)/3);
}});["Quad","Cubic","Quart","Quint"].each(function(B,A){Fx.Transitions[B]=new Fx.Transition(function(C){return Math.pow(C,[A+2]);});Fx.Transitions.compat(B);
});var Drag={};Drag.Base=new Class({options:{handle:false,unit:"px",onStart:Class.empty,onBeforeStart:Class.empty,onComplete:Class.empty,onSnap:Class.empty,onDrag:Class.empty,limit:false,modifiers:{x:"left",y:"top"},grid:false,snap:6},initialize:function(B,A){this.setOptions(A);
this.element=$(B);this.handle=$(this.options.handle)||this.element;this.mouse={now:{},pos:{}};this.value={start:{},now:{}};this.bound={start:this.start.bindWithEvent(this),check:this.check.bindWithEvent(this),drag:this.drag.bindWithEvent(this),stop:this.stop.bind(this)};
this.attach();if(this.options.initialize){this.options.initialize.call(this);}},attach:function(){this.handle.addEvent("mousedown",this.bound.start);return this;
},detach:function(){this.handle.removeEvent("mousedown",this.bound.start);return this;},start:function(C){this.fireEvent("onBeforeStart",this.element);
this.mouse.start=C.page;var A=this.options.limit;this.limit={x:[],y:[]};for(var D in this.options.modifiers){if(!this.options.modifiers[D]){continue;}this.value.now[D]=this.element.getStyle(this.options.modifiers[D]).toInt();
this.mouse.pos[D]=C.page[D]-this.value.now[D];if(A&&A[D]){for(var B=0;B<2;B++){if($chk(A[D][B])){this.limit[D][B]=($type(A[D][B])=="function")?A[D][B]():A[D][B];
}}}}if($type(this.options.grid)=="number"){this.options.grid={x:this.options.grid,y:this.options.grid};}document.addListener("mousemove",this.bound.check);
document.addListener("mouseup",this.bound.stop);this.fireEvent("onStart",this.element);C.stop();},check:function(A){var B=Math.round(Math.sqrt(Math.pow(A.page.x-this.mouse.start.x,2)+Math.pow(A.page.y-this.mouse.start.y,2)));
if(B>this.options.snap){document.removeListener("mousemove",this.bound.check);document.addListener("mousemove",this.bound.drag);this.drag(A);this.fireEvent("onSnap",this.element);
}A.stop();},drag:function(A){this.out=false;this.mouse.now=A.page;for(var B in this.options.modifiers){if(!this.options.modifiers[B]){continue;}this.value.now[B]=this.mouse.now[B]-this.mouse.pos[B];
if(this.limit[B]){if($chk(this.limit[B][1])&&(this.value.now[B]>this.limit[B][1])){this.value.now[B]=this.limit[B][1];this.out=true;}else{if($chk(this.limit[B][0])&&(this.value.now[B]<this.limit[B][0])){this.value.now[B]=this.limit[B][0];
this.out=true;}}}if(this.options.grid[B]){this.value.now[B]-=(this.value.now[B]%this.options.grid[B]);}this.element.setStyle(this.options.modifiers[B],this.value.now[B]+this.options.unit);
}this.fireEvent("onDrag",this.element);A.stop();},stop:function(){document.removeListener("mousemove",this.bound.check);document.removeListener("mousemove",this.bound.drag);
document.removeListener("mouseup",this.bound.stop);this.fireEvent("onComplete",this.element);}});Drag.Base.implement(new Events,new Options);Element.extend({makeResizable:function(A){return new Drag.Base(this,$merge({modifiers:{x:"width",y:"height"}},A));
}});Drag.Move=Drag.Base.extend({options:{droppables:[],container:false,overflown:[]},initialize:function(B,A){this.setOptions(A);this.element=$(B);this.droppables=$$(this.options.droppables);
this.container=$(this.options.container);this.position={element:this.element.getStyle("position"),container:false};if(this.container){this.position.container=this.container.getStyle("position");
}if(!["relative","absolute","fixed"].contains(this.position.element)){this.position.element="absolute";}var D=this.element.getStyle("top").toInt();var C=this.element.getStyle("left").toInt();
if(this.position.element=="absolute"&&!["relative","absolute","fixed"].contains(this.position.container)){D=$chk(D)?D:this.element.getTop(this.options.overflown);
C=$chk(C)?C:this.element.getLeft(this.options.overflown);}else{D=$chk(D)?D:0;C=$chk(C)?C:0;}this.element.setStyles({top:D,left:C,position:this.position.element});
this.parent(this.element);},start:function(C){this.overed=null;if(this.container){var A=this.container.getCoordinates();var B=this.element.getCoordinates();
if(this.position.element=="absolute"&&!["relative","absolute","fixed"].contains(this.position.container)){this.options.limit={x:[A.left,A.right-B.width],y:[A.top,A.bottom-B.height]};
}else{this.options.limit={y:[0,A.height-B.height],x:[0,A.width-B.width]};}}this.parent(C);},drag:function(A){this.parent(A);var B=this.out?false:this.droppables.filter(this.checkAgainst,this).getLast();
if(this.overed!=B){if(this.overed){this.overed.fireEvent("leave",[this.element,this]);}this.overed=B?B.fireEvent("over",[this.element,this]):null;}return this;
},checkAgainst:function(B){B=B.getCoordinates(this.options.overflown);var A=this.mouse.now;return(A.x>B.left&&A.x<B.right&&A.y<B.bottom&&A.y>B.top);},stop:function(){if(this.overed&&!this.out){this.overed.fireEvent("drop",[this.element,this]);
}else{this.element.fireEvent("emptydrop",this);}this.parent();return this;}});Element.extend({makeDraggable:function(A){return new Drag.Move(this,A);}});
var XHR=new Class({options:{method:"post",async:true,onRequest:Class.empty,onSuccess:Class.empty,onFailure:Class.empty,urlEncoded:true,encoding:"utf-8",autoCancel:false,headers:{}},setTransport:function(){this.transport=(window.XMLHttpRequest)?new XMLHttpRequest():(window.ie?new ActiveXObject("Microsoft.XMLHTTP"):false);
return this;},initialize:function(A){this.setTransport().setOptions(A);this.options.isSuccess=this.options.isSuccess||this.isSuccess;this.headers={};if(this.options.urlEncoded&&this.options.method=="post"){var B=(this.options.encoding)?"; charset="+this.options.encoding:"";
this.setHeader("Content-type","application/x-www-form-urlencoded"+B);}if(this.options.initialize){this.options.initialize.call(this);}},onStateChange:function(){if(this.transport.readyState!=4||!this.running){return ;
}this.running=false;var A=0;try{A=this.transport.status;}catch(B){}if(this.options.isSuccess.call(this,A)){this.onSuccess();}else{this.onFailure();}this.transport.onreadystatechange=Class.empty;
},isSuccess:function(A){return((A>=200)&&(A<300));},onSuccess:function(){this.response={text:this.transport.responseText,xml:this.transport.responseXML};
this.fireEvent("onSuccess",[this.response.text,this.response.xml]);this.callChain();},onFailure:function(){this.fireEvent("onFailure",this.transport);},setHeader:function(A,B){this.headers[A]=B;
return this;},send:function(A,C){if(this.options.autoCancel){this.cancel();}else{if(this.running){return this;}}this.running=true;if(C&&this.options.method=="get"){A=A+(A.contains("?")?"&":"?")+C;
C=null;}this.transport.open(this.options.method.toUpperCase(),A,this.options.async);this.transport.onreadystatechange=this.onStateChange.bind(this);if((this.options.method=="post")&&this.transport.overrideMimeType){this.setHeader("Connection","close");
}$extend(this.headers,this.options.headers);for(var B in this.headers){try{this.transport.setRequestHeader(B,this.headers[B]);}catch(D){}}this.fireEvent("onRequest");
this.transport.send($pick(C,null));return this;},cancel:function(){if(!this.running){return this;}this.running=false;this.transport.abort();this.transport.onreadystatechange=Class.empty;
this.setTransport();this.fireEvent("onCancel");return this;}});XHR.implement(new Chain,new Events,new Options);var Ajax=XHR.extend({options:{data:null,update:null,onComplete:Class.empty,evalScripts:false,evalResponse:false},initialize:function(B,A){this.addEvent("onSuccess",this.onComplete);
this.setOptions(A);this.options.data=this.options.data||this.options.postBody;if(!["post","get"].contains(this.options.method)){this._method="_method="+this.options.method;
this.options.method="post";}this.parent();this.setHeader("X-Requested-With","XMLHttpRequest");this.setHeader("Accept","text/javascript, text/html, application/xml, text/xml, */*");
this.url=B;},onComplete:function(){if(this.options.update){$(this.options.update).empty().setHTML(this.response.text);}if(this.options.evalScripts||this.options.evalResponse){this.evalScripts();
}this.fireEvent("onComplete",[this.response.text,this.response.xml],20);},request:function(A){A=A||this.options.data;switch($type(A)){case"element":A=$(A).toQueryString();
break;case"object":A=Object.toQueryString(A);}if(this._method){A=(A)?[this._method,A].join("&"):this._method;}return this.send(this.url,A);},evalScripts:function(){var B,A;
if(this.options.evalResponse||(/(ecma|java)script/).test(this.getHeader("Content-type"))){A=this.response.text;}else{A=[];var C=/<script[^>]*>([\s\S]*?)<\/script>/gi;
while((B=C.exec(this.response.text))){A.push(B[1]);}A=A.join("\n");}if(A){(window.execScript)?window.execScript(A):window.setTimeout(A,0);}},getHeader:function(A){try{return this.transport.getResponseHeader(A);
}catch(B){}return null;}});Object.toQueryString=function(B){var C=[];for(var A in B){C.push(encodeURIComponent(A)+"="+encodeURIComponent(B[A]));}return C.join("&");
};Element.extend({send:function(A){return new Ajax(this.getProperty("action"),$merge({data:this.toQueryString()},A,{method:"post"})).request();}});var Cookie=new Abstract({options:{domain:false,path:false,duration:false,secure:false},set:function(C,D,B){B=$merge(this.options,B);
D=encodeURIComponent(D);if(B.domain){D+="; domain="+B.domain;}if(B.path){D+="; path="+B.path;}if(B.duration){var A=new Date();A.setTime(A.getTime()+B.duration*24*60*60*1000);
D+="; expires="+A.toGMTString();}if(B.secure){D+="; secure";}document.cookie=C+"="+D;return $extend(B,{key:C,value:D});},get:function(A){var B=document.cookie.match("(?:^|;)\\s*"+A.escapeRegExp()+"=([^;]*)");
return B?decodeURIComponent(B[1]):false;},remove:function(B,A){if($type(B)=="object"){this.set(B.key,"",$merge(B,{duration:-1}));}else{this.set(B,"",$merge(A,{duration:-1}));
}}});var Json={toString:function(C){switch($type(C)){case"string":return'"'+C.replace(/(["\\])/g,"\\$1")+'"';case"array":return"["+C.map(Json.toString).join(",")+"]";
case"object":var A=[];for(var B in C){A.push(Json.toString(B)+":"+Json.toString(C[B]));}return"{"+A.join(",")+"}";case"number":if(isFinite(C)){break;}case false:return"null";
}return String(C);},evaluate:function(str,secure){return(($type(str)!="string")||(secure&&!str.test(/^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/)))?null:eval("("+str+")");
}};Json.Remote=XHR.extend({initialize:function(B,A){this.url=B;this.addEvent("onSuccess",this.onComplete);this.parent(A);this.setHeader("X-Request","JSON");
},send:function(A){return this.parent(this.url,"json="+Json.toString(A));},onComplete:function(){this.fireEvent("onComplete",[Json.evaluate(this.response.text,this.options.secure)]);
}});var Asset=new Abstract({javascript:function(C,B){B=$merge({onload:Class.empty},B);var A=new Element("script",{src:C}).addEvents({load:B.onload,readystatechange:function(){if(this.readyState=="complete"){this.fireEvent("load");
}}});delete B.onload;return A.setProperties(B).inject(document.head);},css:function(B,A){return new Element("link",$merge({rel:"stylesheet",media:"screen",type:"text/css",href:B},A)).inject(document.head);
},image:function(C,B){B=$merge({onload:Class.empty,onabort:Class.empty,onerror:Class.empty},B);var D=new Image();D.src=C;var A=new Element("img",{src:C});
["load","abort","error"].each(function(E){var F=B["on"+E];delete B["on"+E];A.addEvent(E,function(){this.removeEvent(E,arguments.callee);F.call(this);});
});if(D.width&&D.height){A.fireEvent("load",A,1);}return A.setProperties(B);},images:function(D,C){C=$merge({onComplete:Class.empty,onProgress:Class.empty},C);
if(!D.push){D=[D];}var A=[];var B=0;D.each(function(F){var E=new Asset.image(F,{onload:function(){C.onProgress.call(this,B);B++;if(B==D.length){C.onComplete();
}}});A.push(E);});return new Elements(A);}});var Accordion=Fx.Elements.extend({options:{onActive:Class.empty,onBackground:Class.empty,display:0,show:false,height:true,width:false,opacity:true,fixedHeight:false,fixedWidth:false,wait:false,alwaysHide:false},initialize:function(){var C,E,F,B;
$each(arguments,function(I,H){switch($type(I)){case"object":C=I;break;case"element":B=$(I);break;default:var G=$$(I);if(!E){E=G;}else{F=G;}}});this.togglers=E||[];
this.elements=F||[];this.container=$(B);this.setOptions(C);this.previous=-1;if(this.options.alwaysHide){this.options.wait=true;}if($chk(this.options.show)){this.options.display=false;
this.previous=this.options.show;}if(this.options.start){this.options.display=false;this.options.show=false;}this.effects={};if(this.options.opacity){this.effects.opacity="fullOpacity";
}if(this.options.width){this.effects.width=this.options.fixedWidth?"fullWidth":"offsetWidth";}if(this.options.height){this.effects.height=this.options.fixedHeight?"fullHeight":"scrollHeight";
}for(var D=0,A=this.togglers.length;D<A;D++){this.addSection(this.togglers[D],this.elements[D]);}this.elements.each(function(H,G){if(this.options.show===G){this.fireEvent("onActive",[this.togglers[G],H]);
}else{for(var I in this.effects){H.setStyle(I,0);}}},this);this.parent(this.elements);if($chk(this.options.display)){this.display(this.options.display);
}},addSection:function(E,C,G){E=$(E);C=$(C);var F=this.togglers.contains(E);var B=this.togglers.length;this.togglers.include(E);this.elements.include(C);
if(B&&(!F||G)){G=$pick(G,B-1);E.injectBefore(this.togglers[G]);C.injectAfter(E);}else{if(this.container&&!F){E.inject(this.container);C.inject(this.container);
}}var A=this.togglers.indexOf(E);E.addEvent("click",this.display.bind(this,A));if(this.options.height){C.setStyles({"padding-top":0,"border-top":"none","padding-bottom":0,"border-bottom":"none"});
}if(this.options.width){C.setStyles({"padding-left":0,"border-left":"none","padding-right":0,"border-right":"none"});}C.fullOpacity=1;if(this.options.fixedWidth){C.fullWidth=this.options.fixedWidth;
}if(this.options.fixedHeight){C.fullHeight=this.options.fixedHeight;}C.setStyle("overflow","hidden");if(!F){for(var D in this.effects){C.setStyle(D,0);
}}return this;},display:function(A){A=($type(A)=="element")?this.elements.indexOf(A):A;if((this.timer&&this.options.wait)||(A===this.previous&&!this.options.alwaysHide)){return this;
}this.previous=A;var B={};this.elements.each(function(E,D){B[D]={};var C=(D!=A)||(this.options.alwaysHide&&(E.offsetHeight>0));this.fireEvent(C?"onBackground":"onActive",[this.togglers[D],E]);
for(var F in this.effects){B[D][F]=C?0:E[this.effects[F]];}},this);return this.start(B);},showThisHideOpen:function(A){return this.display(A);}});Fx.Accordion=Accordion;
/*
Script: Hash.js
	Contains the class Hash.

License:
	MIT-style license.
*/

/*
Class: Hash
	It wraps an object that it uses internally as a map. The user must use set(), get(), and remove() to add/change, retrieve and remove values, it must not access the internal object directly. null/undefined values are allowed.

Note:
	Each hash instance has the length property.

Arguments:
	obj - an object to convert into a Hash instance.

Example:
	(start code)
	var hash = new Hash({a: 'hi', b: 'world', c: 'howdy'});
	hash.remove('b'); // b is removed.
	hash.set('c', 'hello');
	hash.get('c'); // returns 'hello'
	hash.length // returns 2 (a and c)
	(end)
*/

var Hash = new Class({

	length: 0,

	initialize: function(object){
		this.obj = object || {};
		this.setLength();
	},

	/*
	Property: get
		Retrieves a value from the hash.

	Arguments:
		key - The key

	Returns:
		The value
	*/

	get: function(key){
		return (this.hasKey(key)) ? this.obj[key] : null;
	},

	/*
	Property: hasKey
		Check the presence of a specified key-value pair in the hash.

	Arguments:
		key - The key

	Returns:
		True if the Hash contains a value for the specified key, otherwise false
	*/

	hasKey: function(key){
		return (key in this.obj);
	},

	/*
	Property: set
		Adds a key-value pair to the hash or replaces a previous value associated with the key.

	Arguments:
		key - The key
		value - The value
	*/

	set: function(key, value){
		if (!this.hasKey(key)) this.length++;
		this.obj[key] = value;
		return this;
	},

	setLength: function(){
		this.length = 0;
		for (var p in this.obj) this.length++;
		return this;
	},

	/*
	Property: remove
		Removes a key-value pair from the hash.

	Arguments:
		key - The key
	*/

	remove: function(key){
		if (this.hasKey(key)){
			delete this.obj[key];
			this.length--;
		}
		return this;
	},

	/*
	Property: each
		Calls a function for each key-value pair. The first argument passed to the function will be the value, the second one will be the key, like $each.

	Arguments:
		fn - The function to call for each key-value pair
		bind - Optional, the object that will be referred to as "this" in the function
	*/

	each: function(fn, bind){
		$each(this.obj, fn, bind);
	},

	/*
	Property: extend
		Extends the current hash with an object containing key-value pairs. Values for duplicate keys will be replaced by the new ones.

	Arguments:
		obj - An object containing key-value pairs
	*/

	extend: function(obj){
		$extend(this.obj, obj);
		return this.setLength();
	},

	/*
	Property: merge
		Merges the current hash with multiple objects.
	*/

	merge: function(){
		this.obj = $merge.apply(null, [this.obj].extend(arguments));
		return this.setLength();
	},

	/*
	Property: empty
		Empties all hash values properties and values.
	*/

	empty: function(){
		this.obj = {};
		this.length = 0;
		return this;
	},

	/*
	Property: keys
		Returns an array containing all the keys, in the same order as the values returned by <Hash.values>.

	Returns:
		An array containing all the keys of the hash
	*/

	keys: function(){
		var keys = [];
		for (var property in this.obj) keys.push(property);
		return keys;
	},

	/*
	Property: values
		Returns an array containing all the values, in the same order as the keys returned by <Hash.keys>.

	Returns:
		An array containing all the values of the hash
	*/

	values: function(){
		var values = [];
		for (var property in this.obj) values.push(this.obj[property]);
		return values;
	}

});

/* Section: Utility Functions */

/*
Function: $H
	Shortcut to create a Hash from an Object.
*/

function $H(obj){
	return new Hash(obj);
};/**
 * @class
 * @name Hash
 */
Hash.implement({
  /**
   * Converts this Hash to an array by calling a function once for each key-value pair.
   * @param {Function} fn The function to call for each key-value pair
   * @returns {Array} The resulting array.
   */
  collect: function(fn) {
    var result = [];
    this.each(function(v, k){
      result.push(fn(v, k));
    });
    return result;
  },
  
  /**
   * Modifies this Hash by calling a function once for each key-value pair and updating the value
   * to the return value of the function.
   * @example
   *   Uppercase all values:
   *   myHash.map(function(v, k) { return v.toUpperCase(); });
   * @param {Function} fn The function to call for each key-value pair
   * @returns {Hash} This Hash
   */
  map: function(fn) {
    this.keys().each(function(k) {
      this.set(k, fn(this.get(k), k));
    }, this);
    return this;
  }
});if (!$defined(IS_DEBUG)) var IS_DEBUG = false;
if (!$defined(VERSION_MAP)) var VERSION_MAP = {};

/**
 * Top level namespace.
 * @namespace
 */
var ta = {};

/**
 * Google Maps extensions and related.
 * @namespace
 */
ta.maps = {};

/**
  Shared functionality
  @namespace
*/
ta.common = {};

/**
  Servlet specific support functions.
  @namespace
*/
ta.servlet = {};

/**
 * Support classes.
 * @namespace
 */
ta.support = {};

/**
 * Utililty methods and classes.
 * @namespace
 */
ta.util = {};

/**
 * Common UI widgets.
 * @namespace
 */
ta.widgets = {};

/**
  Commerce related methods and classes.
  @namespace
*/
ta.commerce = {};


/*

  Event Delegation

*/

/**
 * Call the specified behavior handler function.
 * @example onclick="ta.call('ta.namespace.Class.function', event)"
 * @example ta.namespace.Class.function = function(evnt, elmt);
 * @param {String} funcName Name of the function to call
 * @param {Event} evnt The event
 * @returns {boolean} The return value of the function.
 */
ta.call = function(funcName, evnt) {
  if (!$defined(evnt)) {
    if (IS_DEBUG) alert("You must pass the event.\n\nUsage:\nta.call('ta.namespace.Class.function', event);");
    return false;
  }
  if (!/^ta\.[\w\d\.]+$/.test(funcName)) {
    if (IS_DEBUG) alert("Invalid function name. Must be of the form: ta.namespace.Class.function");
    return false;
  }

  var e     = new Event(evnt || window.event);
  var elmt  = $(e.target);

  // try to find and run the function
  try {
    var fn = eval(funcName);
    if ($defined(fn) && $type(fn) == "function") return fn(e, elmt);
  }
  catch (_ex) {
    if (IS_DEBUG) alert("ERROR:\n"+_ex.message);
    // do nothing
  }
  
  // function not available, try to load dependency
  e.preventDefault(); // function deferred, prevent default event
  if (ta.load(funcName.split('.').slice(0,-1))) {
    ta.util.pending.waitForHandler(funcName.split('.').slice(-1), funcName, e, elmt);
  }
  return false;
}

/**
 * Dynamically loads the javascript necessary to include the given class.
 * @param {String} cl Name of class to load
 */
ta.load = function(cl) {
  if ($type(cl) == "string") cl = cl.split('.');
  var file = cl.join('-')+'.js';
  if (!VERSION_MAP[file]) file = cl.slice(0,-1).join('-')+'.js';
  if (!VERSION_MAP[file]) {
    return false;
  }
  return ta.loadFile(file);
}

/**
 * Dynamically loads a javascript file. File must be defined in the VERSION_MAP, usually by specifying
 * $onDemandScript in Velocity.
 * @example #set( $onDemandScript = ['ta-maps.js'] )
 * @param {String} file Name of file to load
 * @returns {Boolean} true if file can be loaded, false if not
 */
ta.loadFile = function(file) {
  if (!VERSION_MAP[file]) {
    if (IS_DEBUG) alert("File not found in version map: "+file);
    return false;
  }
  file = VERSION_MAP[file];
  if (IS_DEBUG) file += "?nocache=" + new Date().getTime();
  new Asset.javascript(file);
  return true;
}


/*

  On Load Queue

*/

/**
 * @private
 */
ta._loadQ = [];

/**
 * Add a function to be run when the page loads.
 * @param {function} fn function to run
 */
ta.queueForLoad = function(fn) {
  ta._loadQ.push(fn);
}

/**
 * Runs any functions in the on load queue.
 */
ta.onLoad = function() {
  for (var i = 0; i < ta._loadQ.length; i++) {
    ta._loadQ[i]();
  }
}
window.addEvent('load', ta.onLoad);


/*

  Variable Store

*/

/**
 * @private
 */
ta._store = new Hash();

/**
 * Stores a variable in the variable store.
 * @param {String} name variable name
 * @param {mixed} val value
 */
ta.store = function(name, val) {
  ta._store.set(name, val);
}

/**
 * Check to see if a variable is defined.
 * @param {String} name variable name
 * @returns {boolean} true if variable exists
 * @retruns {boolean} false if variable is not present
 */
ta.has = function(name) {
  return ta._store.hasKey(name);
}

/**
 * Return the value of a variable.
 * @param {String} name variable name
 * @returns {mixed} the variable value
 */
ta.retrieve = function(name) {
  return ta._store.get(name);
}

/**
 * Return the value of a variable as an integer.
 * @param {String} name variable name
 * @param {integer} [dfltVal=0] return value if parsing fails
 * @returns {integer} the variable value as an int
 * @returns {mixed} dfltVal
 */
ta.asInt = function(name, dfltVal) {
  var i = parseInt(ta.retrieve(name));
  return isNaN(i) ? (dfltVal || 0) : i;
}

/**
 * Return the value of a variable as a float.
 * @param {String} name variable name
 * @param {float} [dfltVal=0] return value if parsing fails
 * @returns {float} the variable value as a float
 * @returns {mixed} dfltVal
 */
ta.asFloat = function(name, dfltVal) {
  var f = parseFloat(ta.retrieve(name));
  return isNaN(f) ? (dfltVal || 0) : f;
}

/**
 * Removes a variable from the variable store and returns it.
 * @param {String} name variable name
 * @returns {mixed} the variable
 */
ta.remove = function(name) {
  var tmp = ta._store.get(name);
  ta._store.remove(name);
  return tmp;
}


/** @namespace */
ta.util.cookie = {};

/**
  Standard call for setting the PID based on a click action.
  @example <a href="..." class="pid_123" onclick="ta.call('ta.util.cookie.setPID', event)">Click</a>
  @param {Event} evnt The event
  @param {Element} container Element that will contain the map
*/
ta.util.cookie.setPID = function(e, elmt){  
  if ($(elmt).getTag() != "a") elmt = elmt.getParent("a");
  if (pid = elmt.className.match(/pid(\d+)/)) {
    ta.util.cookie.setPIDCookie(pid[1]);
  }
}

ta.util.cookie.setPIDCookie = function(pid){
	var taDomain = ta.retrieve('util.cookie.cookieDomain');
	Cookie.set('NPID', pid, {domain: taDomain, time:5, path: "/"});
}/** @namespace */
ta.util.pending = {};

/**
 * Calls a function after a delay. Resets the timer if it is already active.
 * @param {String} id timer name
 * @param {Function} fn function to call when timer is up
 * @param {integer} limit time to wait in ms
 */
ta.util.pending.waitForMore = function(id, fn, limit) {
  if (ta.has('pending.'+id)) ta.util.pending.cancel(id);
  ta.store('pending.'+id, {timer: fn.delay(limit), 'fn': fn, t:'m', n: limit});
}

/**
 * Waits until a function is loaded, then calls it.
 * @param {String} id timer name
 * @param {String} fn function name
 */
ta.util.pending.waitForFn = function(id, fn) {
  // TODO assert that fn is a valid function name, i.e. only letters and periods.
  try {
    var tmp = eval(fn);
    if ($defined(tmp)) {
      if ($type(tmp) == 'function') {
        if (ta.has('pending.'+id)) {
          var data = ta.retrieve('pending.'+id);
          if (data.evnt) {
            tmp.attempt([data.evnt, data.elmt]);
          }
          else tmp.attempt();
        }
        else tmp.attempt();
      }
      else if (IS_DEBUG) {
        alert("fn is not a function: " + $type(tmp));
      }
    }
    else {
      ta.util.pending.waitForFnAgain(id, fn);
    }
  }
  catch (e) {
    ta.util.pending.waitForFnAgain(id, fn);
  }
}

/**
 * Time interval between checks.
 * @private
 */
ta.util.pending.WAIT_DELAY = 100;
/**
 * Maximum times to run check.
 * @private
 */
ta.util.pending.WAIT_TIMEOUT = 50;

/** @private */
ta.util.pending.waitForFnAgain = function(id, fn) {
  var data = ta.has('pending.'+id) ? ta.retrieve('pending.'+id) : {t:'f', 'fn':fn, count:1};
  if (data.count < ta.util.pending.WAIT_TIMEOUT) {
    data.count++;
    data.timer = ta.util.pending.waitForFn.delay(ta.util.pending.WAIT_DELAY, null, [id, fn]);
    ta.store('pending.'+id, data);
  }
  else if (IS_DEBUG)
    alert('timed out (' +
      (ta.util.pending.WAIT_TIMEOUT * ta.util.pending.WAIT_DELAY) +
      'ms) waiting for function: ' + fn
    );
}

/**
 * Attempts to load a file dynamically, then runs the callback function.
 * @param {String} id timer name
 * @param {String} file Name of file to load
 * @param {String} fn Function name
 */
ta.util.pending.waitForFile = function(id, file, fn) {
  if (ta.loadFile(file)) {
    ta.util.pending.waitForFn(id, fn);
  }
}

/**
 * Calls an event handler function after its loaded.
 * @param {String} id timer name
 * @param {String} fn Function name
 * @param {Event} evnt The Event
 * @param {Element} elmt The Element
 */
ta.util.pending.waitForHandler = function(id, fn, evnt, elmt) {
  ta.store('pending.'+id, {
    count: 0,
    t: 'f',
    'fn': fn,
    'evnt': evnt,
    'elmt': elmt
  });
  ta.util.pending.waitForFn(id, fn);
}

/**
 * Cancels a timer.
 * @param {String} id timer name
 */
ta.util.pending.cancel = function(id) {
  var p = ta.remove('pending.'+id);
  if (p && p.timer) $clear(p.timer);
}

/**
 * Prevents an action from occurring if it is locked.
 * @param {String} id lock name
 * @param {Function} fn function to run
 * @param {integer} [timer] automatically unlock after this many ms
 * @param {mixed} [fail=false] return value if action is locked
 * @returns {mixed} function result if not locked, fail parameter otherwise
 */
ta.util.pending.lock = function(id, fn, timer, fail) {
  if (ta.has('pending.'+id)) return $pick(fail, false);
  ta.store('pending.'+id, true);
  if ($defined(timer)) ta.util.pending.unlock.delay(timer, null, id);
  return fn();
}

/**
 * Unlocks an action.
 * @param {String} id lock name
 */
ta.util.pending.unlock = function(id) {
  ta.remove('pending.'+id);
}
/**
  Dynamic loading and dependancy support.
  @namespace
*/
ta.util.load = {};

/**
 * Load the Google Maps API. Uses the following settings if not passed in:
 *   * _maps.callback_ - Function to call when maps api is loaded.
 * @param {Function} [callback] Function to call when maps api is loaded.
 * @returns {boolean} true if maps api is already loaded
 * @returns {boolean} false if waiting for maps api to load
 * @author wasche
 * @since 2009.02.09
 */
ta.util.load.GMaps = function(callback) {
  callback = $pick(callback, ta.retrieve('maps.callback'));
  if ($defined(window['GUnload']) && callback) {
    callback(); // already loaded
    return true;
  }
  if (callback) ta.store('gmaps.callback', callback);
  new Asset.javascript('http://maps.google.com/maps?file=api&v=2.118&key=' + gKey + '&c&async=2&callback=ta.util.load.GMapsCallback');
  return false;
}

/**
 * @private
 * Sets up the GUnload method to run when the page is unloaded and runs the callback method, if defined.
 * @author wasche
 * @since 2009.02.09
 */
ta.util.load.GMapsCallback = function() {
  if (!GBrowserIsCompatible()) return; // Maps not supported
  window.addListener('beforeunload', function(){
    window.addListener('unload', GUnload);
  });
  if (ta.has('gmaps.callback')) {
    ta.util.pending.waitForFn('gmaps.callback', ta.remove('gmaps.callback'));
  }
}

ta.util.load.GoogleLoader = function(callback) {
  if (ta.has("googleloader.state")) {
    if (ta.retrieve("googleloader.state") == "loaded") {
      return callback();
    }
    else {
      return ta.util.load.GoogleLoader.delay(500, this, callback);
    }
  }
  else {
    ta.store("googleloader.state", "loading");
    ta.store("googleloader.callback", callback);
    new Asset.javascript('http://www.google.com/jsapi?key=' + gKey + "&callback=ta.util.load.GoogleLoaderCallback");
  }
}

ta.util.load.GoogleLoaderCallback = function() {
  ta.store("googleloader.state", "loaded");
  var callback = ta.remove("googleloader.callback");
  callback();
}

/**
 * Load the Google Local Search API.
 * @author hhwang
 * @since  8 Apr 2009
 */
ta.util.load.LocalSearch = function(callback) {
  ta.util.load.GoogleLoader(function() {
                              google.load("search", "1", {callback: function() {}});
                            });
};
ta.maps.floatmap = {

  deferFM: function(e) {
    new Asset.javascript(mapsJs);
    new Event(e).stop();
  },

  setupFloatMap: function() {
    var floatMap = $("FLOATMAP");
    fmThumb = floatMap.getElement(".js_floatMap");
    fmThumb.myDeferFn = function(e) { eval('ta.maps.floatmap.deferFM')(e); };
    fmThumb.addtl = new Array();
    fmThumb.addtl.push(floatMap.getElement('div.all a').addEvent('click', fmThumb.myDeferFn));
    var ln = $('LEFTNAV').getElement('a.k_maps');
    if (ln)
    {
      fmThumb.addtl.push(ln.addEvent('click', fmThumb.myDeferFn));
    }
    fmThumb.addEvent('click', fmThumb.myDeferFn);
  },
  
  setupCNFloatMap: function() {
    var cnFloatMapLink = $('CNFLOATMAP').getElement('a');
    var floatMapThumb  = $('FLOATMAP').getElement('.js_floatMap');
    floatMapThumb.addtl.push(cnFloatMapLink.addEvent('click', floatMapThumb.myDeferFn));    
  },
  
  termsPopup: function(event, elmt) {
    popup(elmt, ['terms', 300, 300, 30, 25]);
    return false;
  }

};ta.common.search = {

  langSelect: function(event, elmt) {
    if (elmt.form.elements['q'].value.length > 0)
    {
        elmt.form.submit();
    }
  },
  
  clearOnFocus: function(event, elmt) {
    if (elmt.value == elmt.defaultValue)
    {
      elmt.value = '';
      elmt.removeClass('focusClear');
    }
  }
  
};ta.common.flyout = {

  intlPopup: function(event, elmt) {
    var intlpop = $('INTLPOP');
    if (!intlpop.flyout) {
      intlpop.flyout = new Flyout(intlpop, {offsets: {x:12, y:14}, remoteCallback: true});
      intlpop.flyout.toggle(event);
    }
    return false;
  },

  myTA: function(event, elmt) {
    return ta.common.flyout.memberFlyout(event, $("myTA"));
  },

  myTrips: function(event, elmt) {
    return ta.common.flyout.memberFlyout(event, $("showLastSavesRD"));
  },

  register: function(event, elmt) {
    return ta.common.flyout.memberFlyout(event, $("register"));
  },

  memberFlyout: function(event, elmt) {
    if (!elmt.flyout) {
      elmt.flyout = new Flyout(elmt, {offsets: {x:4, y:8}});
      elmt.flyout.toggle(event);
    }
    return false;
  },
  
  whatIsTopValueFlyout:function(event, element)
  {
    //  if we do not already have a flyout
    if (!element.flyout)
    {
        //  grab the type class
        var typeClass = element.className.match(/\sb?(bv\S*)/);
        typeClass = typeClass.length > 0 ? typeClass[1] : null;
        if (typeClass)
        {
            var offsets = element.getParent('#TOPVALUEBOX') ? {x:20, y:12} : {x:5, y:11};
            
            //  create a copy of the type class info for this flyout
            element.adopt($$('.' + typeClass + 'Info')[0].clone());
            element.flyout = new Flyout(element, {'offsets':offsets});
            element.flyout.toggle(event);
            new Ajax('/ActionRecord').request();
        }
    }
  },
  
  flipKeyOwnerTypeFlyout:function(event, element)
  {
      //  if we do not already have a flyout
      if (!element.flyout)
      {
          //  grab the type class
          var typeClass = element.className.match(/\sb?(vr\S*)/);
          typeClass = typeClass.length > 0 ? typeClass[1] : null;
          if (typeClass)
          {
              var offsets = element.getParent('#ACCOM_OVERVIEW') ? {x:20, y:12} : {x:5, y:11};
              
              //  create a copy of the type class info for this flyout
              element.adopt($$('.' + typeClass + 'Info')[0].clone());
              element.flyout = new Flyout(element, {'offsets':offsets});
              element.flyout.toggle(event);
          }
      }
  },
  
  vrWhatToExpectFlyout:function(event, element)
  {
      //  if we do not already have a flyout
      if (!element.flyout)
      {
          element.flyout = new Flyout(element, {offsets:{x:0, y:12}, remoteContent:'/vpages/vacation_renters_tips.html'});
          element.flyout.toggle(event);
      }
  },
  
  destinationsPopup: function(event, elmt) {
    var destinationsPop = $('DESTINATIONSPOP');
    if (!destinationsPop.flyout) {
      destinationsPop.flyout = new Flyout(destinationsPop, {offsets: {x:12, y:14}, flyoutClass: 'flyoutMapContents', remoteContent: '/vpages/destinationsFly.html?lt=evt'});
      destinationsPop.flyout.toggle(event);
    }
    return false;
  },
  
  funStuffPopup: function(event, elmt) {
    var funStuffPop = $('FUNSTUFFPOP');
    if (!funStuffPop.flyout) {
      funStuffPop.flyout = new Flyout(funStuffPop, {offsets: {x:14, y:16}, remoteContent: '/vpages/funStuffFly.html?lt=evt'});
      funStuffPop.flyout.toggle(event);
    }
    return false;    
  },

  memberOverlay: function(event, elmt) {
    elmt = $(elmt);
    if ( !elmt.hasClass('username') ) {
      elmt = elmt.getParent('.username');
    }
    if (elmt && !elmt.flyout) {
	  var uid = "";
      var catid = "";
	  if (elmt.id.match(/\bUID_([0-9A-F]+)\b/)) {
        uid = RegExp.$1;
      }
      else if (elmt.id.match(/\bCATID_(\d+)\b/)) {
        catid = RegExp.$1;
      }
      new Asset.css(memoverlayCSS);
      elmt.flyout = new Flyout(elmt, {offsets: {x:0, y:8}, showArrow: false, bound: true, cancelBoundOnClick: true, remoteContent: '/MemberOverlay?uid='+uid+'&c='+catid});
	  elmt.flyout.toggle(event);
    }
    return false;
  },

  guideOverlay: function(event, elmt) {
    elmt = elmt.getParent('li');
    if (elmt && !elmt.flyout) {
      // Set guide id
      var gid = "";
      if (elmt.id) {
        gid = elmt.id;
      }
      new Asset.css(guideoverlayCSS);
      elmt.flyout = new Flyout(elmt, {offsets: {x:0, y:10}, remoteContent: '/vpages/travelGuidesFly.html?gid='+gid});
      elmt.flyout.toggle(event);
    }
    return false;
  },

  bestValue: function(event, elmt, offsets) {
    if (!elmt.flyout) {
      elmt.flyout = new Flyout(elmt, {arrowPosition: POS.BOTTOM, offsets: offsets, bound: true, showClose: false, remoteContent: '/vpages/bestValueFly.html?log=false'});
      elmt.flyout.toggle(event);
    }
    return false;
  },
  
  bestValuePopup: function(event, elmt) {
    return ta.common.flyout.bestValue(event, $(elmt), {x:12, y:12});
  },

  bestValuePopupSmall: function(event, elmt) {
    return ta.common.flyout.bestValue(event, $('BV_SMALL'), {x:0, y:18});
  },
  
  reisePopup: function(event, elmt) {
    var reisePop = $('reisePop');
    if (!reisePop.flyout) {
      reisePop.flyout = new Flyout(reisePop, {offsets: {x:-374, y:30}, flyoutClass: 'flyoutAwardContents', remoteContent: '/vpages/reise.html?lt=evt'});
      reisePop.flyout.toggle(event);
    }
    return false;
  },

  sisAccordion: function(event, elmt, arrowPosition) {
    // elmt may be deeper in the DOM than the desired element since it is inferred from the event,
    // so walk back up the DOM until we find the tr.flyout or tr.flyoutL element
    elmt = $(elmt);
    while (elmt.getTag() != 'tr' || ( !elmt.hasClass('flyout') && !elmt.hasClass('flyoutL') )) {
      elmt = elmt.getParent();
    }

    if (!elmt.flyout) {
      elmt.flyout = new Flyout(elmt, {offsets: {x:0, y:0}, arrowPosition: arrowPosition});
      elmt.flyout.toggle(event);
    }
    return false;
  },
  
  sisAccordionFlyout: function(event, elmt) {
    return ta.common.flyout.sisAccordion(event, elmt, POS.RIGHT);
  },
  
  sisAccordionFlyoutLeft: function(event, elmt) {
    return ta.common.flyout.sisAccordion(event, elmt, POS.LEFT);
  },
  
  thumbnailFlyout: function(event, elmt) {
    // elmt may be deeper in the DOM than the desired element since it is inferred from the event,
    // so walk back up the DOM until we find the li element
    elmt = $(elmt);
    while (elmt.getTag() != 'li') {
      elmt = elmt.getParent();
    }

    if (!elmt.flyout) {
      elmt.flyout = new Flyout(elmt, {offsets: {x:4, y:9}, limit:14, showClose: false, bound: true, flyoutClass: 'mediaBox', centerArrow: true});
      elmt.flyout.toggle(event);
    }
    return false;  
  },
  
  recordPropertyTypeClick: function(event, elmt) {
    if (propertyTypeClicked == false) {
      new Ajax("/ActionRecord?action=propertyTypeClicked").request();
      propertyTypeClicked = true;
    }
  }
};
ta.servlet.Inspiration = {

  sortPopularity: function(event, elmt) {
    sort('popularity');
  },

  sortAlphabetical: function(event, elmt) {
    sort('alphabetical');
  }
};
ta.servlet.Reviews = {

  findLink: function(event, elmt) {
    // if link has a class starting with t, take rest of class name
    // as the id of link and follow that link
    if (/\bt([\w\d]+)\b/.test(elmt.className)) window.location = $(RegExp.$1).href;
  },

  mtSubmitOnClick: function(event, elmt) {
    elmt.form.submit();
  }
};

ta.servlet.Location = {

  /**
   * function to switch km distances to mi distances.  Used for nearby locations.
   */
  showMi: function() {
    $$('#NEARBY .milesOption').each(function(item, index)
    {
      item.checked = true;
    });
        
    $$('#NEARBY .milesLabel').each(function(item, index)
    {
      $(item).addClass('selected');
    });
                                        
    $$('#NEARBY .kmLabel').each(function(item, index)
    {
      $(item).removeClass('selected');
    });
    
    $$('#NEARBY .distanceMiles').show();
    $$('#NEARBY .distanceKm').hide();
    Cookie.set(distanceUnitsCookieName, 0);
  },

  /**
   * function to switch mi distances to km distances.  Used for nearby locations.
   */
  showKm: function() {
    $$('#NEARBY .kmOption').each(function(item, index)
    {
      item.checked = true;
    });
    
    $$('#NEARBY .milesLabel').each(function(item, index)
    {
      $(item).removeClass('selected');
    });

    $$('#NEARBY .kmLabel').each(function(item, index)
    {
      $(item).addClass('selected');
    });	
    
    $$('#NEARBY .distanceMiles').hide();
    $$('#NEARBY .distanceKm').show();
    Cookie.set(distanceUnitsCookieName, 1);
  },

  bookNow: function(event, element) {
    bookPopEventHelper(event);
  }
}
ta.servlet.Member = {

  memberBenefitsSubscribe: function(event) {
    processMOSubscribeRequest(event);
    return false;
  },
  
  memberGuideRequest: function(event) {
    processGuideRequest(event);
  },

  memberTOGForm: function(event) {
    processTOGForm(event);
  }

};
ta.servlet.Misc = {
  
  /**
   * callback for CIV selector on FunStuff page
   */
  civRedirOnChange: function(event, element) {
    element = $('civSelect');
    ta.servlet.Misc.openValueInNew.apply(element, [ event ]);
    return false;
  },

  /**
   * callback for LP selector on FunStuff page
   */
  lpRedirOnChange: function(event, element) {
    element = $('localPicksSelect');
    ta.servlet.Misc.openValueInNew.apply(element, [ event ]);
    return false;
  },

  /**
   * get value of a select and use it to open a new window
   */
  openValueInNew: function(e) {
    // call bound to a SELECT
    var uri = this.options[this.selectedIndex].value;
    if (uri.length == 0) return;
    var parts = uri.match(/(\d+):(.*)/);
    if (parts) {
      setPID(parseInt(parts[1]));
      uri = parts[2];
    }
    var w = window.open(uri, "p"+window.name+(popupIndex++));
    if (w != null)
    {
      w.opener = self;
      w.focus();
    }
  }

};
ta.servlet.Tourism = {

  bbOfferClicked: function(event, element) {
    event.preventDefault();
    element = $(element);
    if (element.getTag() != 'tr' || !element.hasClass('offerRow')) {
      element = element.getParent('tr.offerRow');
    }
    offerLink = element.getElement('a');
    popCommFN = linkMap['js_popComm'];
    popCommFN(offerLink,event);
  }

};
/**
 * Popup related functions.
 * @namespace
 */
ta.servlet.Popup = {
  index: 0,

  /**
   * Opens a popup window. Note that the allOptions option takes precedense over noScroll.
   * @param {String} url Location to open in the new window
   * @param {String} [name] Name of the new window
   * @param {integer} [width] Width of the new window
   * @param {integer} [height] Height of the new window
   * @param {integer} [x] X position
   * @param {integer} [y] Y position
   * @param {boolean} [noScroll] If false, set turns all options off, if true only scroll bars are enabled
   * @param {boolean} [allOptions=false] If true all options are turned on, false uses browser defaults
   */
  open: function(url, name, width, height, x, y, noScroll, allOptions)
  {
    var ops = "";
    if (url.indexOf("p=HotelsCom") > -1) {
      width = Math.max(width, 960);
      height = Math.max(height, window.getHeight(), 600);
    }
    if (width) ops += ",width="+width;
    if (height) ops += ",height="+height;
    if (x) ops += ",screenX="+x+",left="+x;
    if (y) ops += ",screenY="+y+",top="+y;
    if (ops != "") {
      if (allOptions) {
        ops = "toolbar=1,resizable=1,menubar=1,location=1,status=1,scrollbars=1" + ops;
      }
      else {
        ops = "toolbar=0,resizable=1,menubar=0,location=0,status=0,scrollbars=" + (noScroll ? 0 : 1) + ops;
      }
    }
    var w = window.open(url, name || "p"+window.name+(ta.servlet.Popup.index++), ops);
    if (w != null)
    {
      try {w.opener = self;} catch (exc) {}
      w.focus();
    }
  },

  /**
   * Opens a check rates popup window using the href of the element.
   */
  checkrates: function(evnt, elmt) {
    evnt.preventDefault();
    if (elmt.getTag() != 'a') elmt = elmt.getParent('a');
    ta.servlet.Popup.open(elmt.href, 'cr', 245, 610, 5, 5);
  },

  /**
   * Opens a sponsored check rates window.
   */
  sponsorCheckRates: function(evnt, elmt) {
    evnt.preventDefault();
    if (elmt.getTag() != 'span') elmt = elmt.getParent('span');
    var accomId = elmt.className.match(/id_(\d+)/)[1];
    var srcUrl = "/HotelDateSearch?d=" + accomId + "&fromPop=false&sponsid=" + ta.retrieve('sponsor.id') + '&area=QC_Button_Map&from=HACSearchButton&returnTo=__2F__GMapsLocationController&sponsdet=mapsHacBottom';
    ta.servlet.Popup.open(srcUrl, 'cr', 245, 610, 5, 5);
  },

  /**
   * Opens a terms window.
   */
  termsPopup: function(event, elmt) {
    popup.apply(elmt, [event, 'terms', 300, 300, 30, 25]);
    return false;
  },

  /**
   * applies to a link in a popup window - opens the url in the parent
   * AND closes the popup
   */
  openInParent: function(event, elmt) {
      if(window.opener) {
          var url = '';
          if(elmt.getTag() == 'form') {
              url = elmt.action + '?' + elmt.toQueryString();
          }
          else if (elmt.getTag() == 'a') {
              url = elmt.href;
          }
          else {
              elmt = elmt.getParent('a');
              url = elmt.href;
          }
          if(url != '') {
              event.preventDefault();
              window.opener.location = url;
              window.close();
          }
      }
      else
      {
        return true;
      }
  },

  /**
   * Opens an appropriate sized window for a photo gallery.
   * The url of the photo viewer needs to be supplied.
   */
  photoGallery: function(event, elmt) {
    if (elmt.getTag() != 'a'){
        elmt = elmt.getParent('a');
    }
    var url = elmt.className.match(/u_([^ ]*)/)[1];
    ta.servlet.Popup.open(url, 'media', 780, 800);
    return false;
  },
  
  /**
   * 
   */
  voviciSurveyPopunder:function(event, elmt)
  {
    //  record the action and pid
    new Ajax("/ActionRecord?action=AcceptSatisfactionSurvey&pid=1798").request();
    
    //  supress all other popunders for the rest of the session
    var commercePopunder = Cookie.getRaw('CommercePopunder');
    if (!commercePopunder || (commercePopunder != 'SuppressAll'))
    {
      Cookie.set("CommercePopunder", "SuppressAll", {domain: cookieDomain}); //  no duration = session cookie
    }

    var popunderslot = getOpenSlot(0, popunderSlots);

    var surveyWindow = window.open("", 'voviciSurvey', "toolbar=0,resizable=1,menubar=0,location=0,status=0,scrollbars=1,width="+popunderslot.tw+",height="+popunderslot.th+",left="+popunderslot.tx+",top="+popunderslot.ty);
    if(surveyWindow && isTAWindow(surveyWindow) )
    {
      surveyWindow.blur();
      window.focus();
      surveyWindow.location = voviciUrl;
      popunderslot.occupied = surveyWindow;
      surveyWindow.opener = self;
      surveyWindow.moveTo(popunderslot.x, popunderslot.y);
      surveyWindow.resizeTo(780,670);
    }
    else if( surveyWindow && unusedPopunderCount < 20) //window already used for commerce
    {
      popunderLaunch(voviciUrl);
    }
    removeDHTMLPopup();
  }
};ta.servlet.Hotel = {

  /**
   * Callback for when the check rates button is pressed.
   */
  checkRatesClicked: function(event, elmt) {
    ta.servlet.Hotel.displayVendors.apply(elmt);
  },

  /**
   * Open a series of windows with rate information for each selected vendor 
   */
  displayVendors: function(customArea) {
    var tempVal = $('HotelDateSearch');
    if(typeof tempVal == "undefined" || typeof tempVal.checkIn == "undefined") return;
    var valid = validateDates.bind($('HotelDateSearch'))();
    if (!valid) return;
    else
    {
      $('HotelDateSearch').getElement('span.error_msg').hide();
    }
    
    if(window.lightbox && window.lightbox.trigger.className && window.lightbox.trigger.className.match(/custom_area_(\w+)/))
    {
      var customArea = window.lightbox.trigger.className.match(/custom_area_(\w+)/);
      window.qcCustomArea = customArea[1];
    }
    else if(window.crFlyout && window.crFlyout.elmt.className && window.crFlyout.elmt.className.match(/custom_area_(\w+)/))
    {
      var customArea = window.crFlyout.elmt.className.match(/custom_area_(\w+)/);
      window.qcCustomArea = customArea[1];
    }
    else
    {
      window.qcCustomArea = "QC_Inline";
    }
    try {
      popwindows(this);
//      if( ! $(this).hasClass('providerWin'))
//      {
//        new Ajax('/ActionRecord?action=QC_Inline_' + pageServlet).request();
//      }
    } catch(e) { }
    return false;
  },

  /**
   * Callback for the compare prices button.
   */
  bookNow: function(event, element) {
    ta.servlet.Hotel.bookPopEventHelper(event);
  },

  /**
   * Open a lightbox with a dialog for doing checkrates
   */
  bookPopEventHelper: function(e) {
    if(!bookPopEvent) {
      bookPopEvent = true;
      var pos = $('BOOKPOP').getPosition();
      $('BOOKPOP').addClass('relPos');
      var lb  = new Lightbox($('BOOKPOP'), {
        contentId: 'lbContentCR',
        centerOnScreen: false,
        top: pos.y,
        left: pos.x,
        source: 'http://' + document.domain + '/vpages/bookit.html?lt=evt'
      });
      lb.activate(e);
    }
  },

  /**
   * Start timer for recording hover over amenity.  Used in amenity bar.
   */
  amenityMouseOver: function(event, elmt) {
    // if we haven't already recorded a hover for this page view...
    if (amenityFiredHoverEvent == false)
    {
      // set a timer at 750ms to record the user hovering
      elmt.hoverTimeout = setTimeout ("recordAmenityIconHover()", 750);
    }
  },

  /**
   * Clear timer for recording hover over amenity.  Used in amenity bar.
   */
  amenityMouseOut: function(event, elmt) {
    // stop the timeout
    clearTimeout (elmt.hoverTimeout);
        
    // remove any references to it
    elmt.hoverTimeout = null;
  },

  detailsTabClicked: function(event, elmt) {
    var tab = $('tabDetails');
    showTab(locationId,'details', tab);
  },

  photosTabClicked: function(event, elmt) {
    var tab = $('tabPhotos');
    showTab(locationId,'photos',tab);
  },

  mapTabClicked: function(event, elmt) {
    var tab = $('tabMap');
    showTab(locationId,'map',tab);
  },

  ratingsTabClicked: function(event, elmt) {
    var tab = $('tabRatings');
    showTab(locationId,'ratings',tab);
  },
  
  setPid:function(pid) {
    Cookie.set('NPID', pid, {domain: cookieDomain, time: 5});
    return true;
  }

};
/**
 * Observer - Observe formelements for changes
 *
 * @version		1.0rc1
 *
 * @license		MIT-style license
 * @author		Harald Kirschner <mail [at] digitarald.de>
 * @copyright	Author
 */
Function.extend({
  // same as delay, but FF 1.0 has issues with the name delay
	invokeLater: function(delay, bind, args){
		return this.create({'delay': delay, 'bind': bind, 'arguments': args})();
	}
});

var Observer = new Class({

	options: {
		periodical: false,
		delay: 1000
	},

	initialize: function(el, onFired, options){
		this.setOptions(options);
		this.addEvent('onFired', onFired);
		this.element = $(el);
		this.listener = this.fired.bind(this);
		this.value = this.element.getValue();
		if (this.options.periodical) this.timer = this.listener.periodical(this.options.periodical);
		else this.element.addEvent('keyup', this.listener);
	},

	fired: function() {
		var value = this.element.getValue();
		if (this.value == value) return;
		this.clear();
		this.value = value;
		this.timeout = this.fireEvent.invokeLater(this.options.delay, this, ['onFired', [value]]);
	},

	clear: function() {
		$clear(this.timeout);
		return this;
	}
});

Observer.implement(new Options);
Observer.implement(new Events);
/**
 * Autocompleter
 *
 * @version		1.0rc4
 *
 * @license		MIT-style license
 * @author		Harald Kirschner <mail [at] digitarald.de>
 * @copyright	Author
 */
var Autocompleter = {};

Autocompleter.Base = new Class({

	options: {
		minLength: 1,
		useSelection: true,
		markQuery: true,
		inheritWidth: true,
		maxChoices: 10,
		injectChoice: null,
		onSelect: Class.empty,
		onShow: Class.empty,
		onHide: Class.empty,
		customTarget: null,
		className: 'autocompleter-choices',
		zIndex: 42,
		observerOptions: {},
		fxOptions: {},
		overflown: [],
		selectOnBlur: false
	},

	initialize: function(el, options) {
		this.setOptions(options);
		this.element = $(el);
		this.build();
		this.observer = new Observer(this.element, this.prefetch.bind(this), $merge({
			delay: 100
		}, this.options.observerOptions));
		this.value = this.observer.value;
		this.queryValue = null;
	},

	/**
	 * build - Initialize DOM
	 *
	 * Builds the html structure for choices and appends the events to the element.
	 * Override this function to modify the html generation.
	 */
	build: function() {
		if ($(this.options.customTarget)) this.choices = this.options.customTarget;
		else {
			this.choices = new Element('ul', {
				'class': this.options.className,
				styles: {zIndex: this.options.zIndex}
			}).injectInside(document.body);
			this.fix = new OverlayFix(this.choices);
		}
		this.fx = this.choices.effect('opacity', $merge({
			wait: false,
			duration: 200
		}, this.options.fxOptions))
			.addEvent('onStart', function() {
				if (this.fx.now) return;
				this.choices.setStyle('display', '');
				this.fix.show();
			}.bind(this))
			.addEvent('onComplete', function() {
				if (this.fx.now) return;
				this.choices.setStyle('display', 'none');
				this.fix.hide();
			}.bind(this)).set(0)
      .addEvent('onShow', function() {
				this.fix.show();
      }.bind(this));
		this.element.setProperty('autocomplete', 'off')
			.addEvent(window.ie6 ? 'keydown' : 'keypress', this.onCommand.bindWithEvent(this))
			.addEvent('mousedown', this.onCommand.bindWithEvent(this, [true]))
			.addEvent('focus', this.toggleFocus.bind(this, [true]))
			.addEvent('blur', this.toggleFocus.bind(this, [false]))
			.addEvent('trash', this.destroy.bind(this));
	},

	destroy: function() {
		this.choices.remove();
	},

	toggleFocus: function(state) {
		if (!state && this.focussed && this.options.selectOnBlur && this.selected && this.visible) {
			// losing focus, accept current selection
			this.choiceSelect(this.selected);
		}
		this.focussed = state;
		if (!state) this.hideChoices();
	},

	onCommand: function(e, mouse) {
		if (mouse && this.focussed) this.prefetch();
		if (e.key && !e.shift) switch (e.key) {
			case 'enter':
				if (this.selected && this.visible) {
					this.choiceSelect(this.selected);
					e.stop();
				} return;
			case 'up': case 'down':
				if (this.observer.value != (this.value || this.queryValue)) this.prefetch();
				else if (this.queryValue === null) break;
				else if (!this.visible) this.showChoices();
				else {
					this.choiceOver((e.key == 'up')
						? this.selected.getPrevious() || this.choices.getLast()
						: this.selected.getNext() || this.choices.getFirst() );
					this.setSelection();
				}
				e.stop(); return;
			case 'esc': this.hideChoices(); return;
		}
		this.value = false;
	},

	setSelection: function() {
		if (!this.options.useSelection) return;
		var startLength = this.queryValue.length;
		if (this.element.value.indexOf(this.queryValue) != 0) return;
		var insert = this.selected.inputValue.substr(startLength);
		if (document.getSelection) {
			this.element.value = this.queryValue + insert;
			this.element.selectionStart = startLength;
			this.element.selectionEnd = this.element.value.length;
		} else if (document.selection) {
			var sel = document.selection.createRange();
			sel.text = insert;
			sel.move("character", - insert.length);
			sel.findText(insert);
			sel.select();
		}
		this.value = this.observer.value = this.element.value;
	},

	hideChoices: function() {
		if (!this.visible) return;
		this.visible = this.value = false;
		this.observer.clear();
		this.fx.start(0);
		this.fireEvent('onHide', [this.element, this.choices]);
	},

	showChoices: function() {
		if (this.visible || !this.choices.getFirst()) return;
		this.visible = true;
		var pos = this.element.getCoordinates(this.options.overflown);
		this.choices.setStyles({
			left: pos.left,
			top: pos.bottom
		});
		if (this.options.inheritWidth) this.choices.setStyle('width', pos.width);
		this.fx.start(1);
		this.choiceOver(this.choices.getFirst());
		this.fireEvent('onShow', [this.element, this.choices]);
	},

	prefetch: function() {
		if (this.element.value.length < this.options.minLength) this.hideChoices();
		else if (this.element.value == this.queryValue) this.showChoices();
		else this.query();
	},

	updateChoices: function(choices) {
		this.choices.empty();
		this.selected = null;
		if (!choices || !choices.length) return;
		if (this.options.maxChoices < choices.length) choices.length = this.options.maxChoices;
		choices.each(this.options.injectChoice || function(choice, i){
			var el = new Element('li').setHTML(this.markQueryValue(choice));
			el.inputValue = choice;
			this.addChoiceEvents(el).injectInside(this.choices);
		}, this);
		this.showChoices();
	},

	choiceOver: function(el) {
		if (this.selected) this.selected.removeClass('autocompleter-selected');
		this.selected = el.addClass('autocompleter-selected');
	},

	choiceSelect: function(el) {
		this.observer.value = this.element.value = el.inputValue;
		this.hideChoices();
		this.fireEvent('onSelect', [this.element], 20);
	},

	/**
	 * markQueryValue
	 *
	 * Marks the queried word in the given string with <span class="autocompleter-queried">*</span>
	 * Call this i.e. from your custom parseChoices, same for addChoiceEvents
	 *
	 * @param		{String} Text
	 * @return		{String} Text
	 */
	markQueryValue: function(txt) {
		return (this.options.markQuery && this.queryValue) ? txt.replace(new RegExp('^(' + this.queryValue.escapeRegExp() + ')', 'i'), '<span class="autocompleter-queried">$1</span>') : txt;
	},

	/**
	 * addChoiceEvents
	 *
	 * Appends the needed event handlers for a choice-entry to the given element.
	 *
	 * @param		{Element} Choice entry
	 * @return		{Element} Choice entry
	 */
	addChoiceEvents: function(el) {
		return el.addEvents({
			mouseover: this.choiceOver.bind(this, [el]),
			mousedown: this.choiceSelect.bind(this, [el])
		});
	}
});

Autocompleter.Base.implement(new Events);
Autocompleter.Base.implement(new Options);

Autocompleter.Local = Autocompleter.Base.extend({

	options: {
		minLength: 0,
		filterTokens : null
	},

	initialize: function(el, tokens, options) {
		this.parent(el, options);
		this.tokens = tokens;
		if (this.options.filterTokens) this.filterTokens = this.options.filterTokens.bind(this);
	},

	query: function() {
		this.hideChoices();
		this.queryValue = this.element.value;
		this.updateChoices(this.filterTokens());
	},

	filterTokens: function(token) {
		var regex = new RegExp('^' + this.queryValue.escapeRegExp(), 'i');
		return this.tokens.filter(function(token) {
			return regex.test(token);
		});
	}

});

Autocompleter.Ajax = {};

Autocompleter.Ajax.Base = Autocompleter.Base.extend({

	options: {
		postVar: 'value',
		postData: {},
		ajaxOptions: {},
		onRequest: Class.empty,
		onComplete: Class.empty
	},

	initialize: function(el, url, options) {
		this.parent(el, options);
		this.ajax = new Ajax(url, $merge({
			autoCancel: true
		}, this.options.ajaxOptions));
		this.ajax.addEvent('onComplete', this.queryResponse.bind(this));
		this.ajax.addEvent('onFailure', this.queryResponse.bind(this, [false]));
	},

	query: function(){
		var data = $extend({}, this.options.postData);
		data[this.options.postVar] = this.element.value;
		this.fireEvent('onRequest', [this.element, this.ajax]);
		this.ajax.request(data);
	},

	/**
	 * queryResponse - abstract
	 *
	 * Inherated classes have to extend this function and use this.parent(resp)
	 *
	 * @param		{String} Response
	 */
	queryResponse: function(resp) {
		this.value = this.queryValue = this.element.value;
		this.selected = false;
		this.hideChoices();
		this.fireEvent(resp ? 'onComplete' : 'onFailure', [this.element, this.ajax], 20);
	}

});

Autocompleter.Ajax.Json = Autocompleter.Ajax.Base.extend({

	queryResponse: function(resp) {
		this.parent(resp);
		var choices = Json.evaluate(resp || false);
		if (!choices || !choices.length) return;
		this.updateChoices(choices);
	}

});

Autocompleter.Ajax.Xhtml = Autocompleter.Ajax.Base.extend({

	options: {
		parseChoices: null
	},

	queryResponse: function(resp) {
		this.parent(resp);
		if (!resp) return;
		this.choices.setHTML(resp).getChildren().each(this.options.parseChoices || this.parseChoices, this);
		this.showChoices();
	},

	parseChoices: function(el) {
		var value = el.innerHTML;
		el.inputValue = value;
		el.setHTML(this.markQueryValue(value));
	}

});


var OverlayFix = new Class({

	initialize: function(el) {
		this.element = $(el);
		if (window.ie6){
			this.element.addEvent('trash', this.destroy.bind(this));
			this.fix = new Element('iframe', {
				properties: {
					frameborder: '0',
					scrolling: 'no',
					src: 'javascript:false;'
				},
				styles: {
					position: 'absolute',
					border: 'none',
					display: 'none',
					filter: 'progid:DXImageTransform.Microsoft.Alpha(opacity=0)'
				}
			}).injectAfter(this.element);
		}
	},

	show: function() {
		if (this.fix) this.fix.setStyles($extend(
			this.element.getCoordinates(), {
				display: '',
				zIndex: (this.element.getStyle('zIndex') || 1) - 1
			}));
		return this;
	},

	hide: function() {
		if (this.fix) this.fix.setStyle('display', 'none');
		return this;
	},

	destroy: function() {
		this.fix.remove();
	}

});
/*
Script: extensions.js
  Contains <StringBuffer>, <Table>, <Autocompleter.Ajax.Json2>, <Autocompleter.Ajax.Flights>, <TabSet>

License:
  not free for public use
*/

/*
Class: StringBuffer
  Small implementation of a string buffer.
*/
var StringBuffer = new Class({
  initialize: function(str) {
    this.strings = new Array();
    if (str) this.append(str);
  },

  append: function(str) {
    this.strings.push(str);
    return this;
  },

  toString: function() {
    return this.strings.join('');
  },

  isEmpty: function () {
    return this.strings.length == 0;
  }
});

Cookie.extend({
	set: function(key, value, options){
    Cookie.setRaw(key, encodeURIComponent(value), options);
	},

  setRaw: function(key, value, options){
    options = $merge(this.options, options);
    if (options.domain) value += '; domain=' + options.domain;
    if (options.path) value += '; path=' + options.path;
    if (options.duration){
      var date = new Date();
      date.setTime(date.getTime() + options.duration * 24 * 60 * 60 * 1000);
      value += '; expires=' + date.toGMTString();
    }
    if (options.time){
      var date = new Date();
      date.setTime(date.getTime() + options.time * 1000);
      value += '; expires=' + date.toGMTString();
    }
    if (options.secure) value += '; secure';
    document.cookie = key + '=' + value;
    return $extend(options, {'key': key, 'value': value});
  },

	exist: function(key){
		return document.cookie.match('(?:^|;)\\s*' + key.escapeRegExp() + '=([^;]*)') != null;
	},

    // Like Cookie.get, but doesn't try to decodeURIComponent (fails on some of our cookies)
    getRaw: function(key) {
        var val = document.cookie.match('(?:^|;)\\s*' + key.escapeRegExp() + '=([^;]*)');
        return val ? val[1] : false;
    }
});

Array.extend({
  toQueryString: function() {
    var data = this.map(function(item, idx) {
      switch($type(item)){
        case 'element': return $(item).toQueryString(); break;
        case 'object': return Object.toQueryString(item);
      }
		});
		return data.join('&');
  }
});

Ajax.prototype._initialize = Ajax.prototype.initialize;
Ajax.prototype.initialize = function(url, options){
  // force URLs to be absolute to fix issue with BASE tag on geo-hostnames
  if (!/^http/.test(url)) {
    url = window.location.protocol + '//' + window.location.host + url;
  }
  else if (/^(\w+):\/\/([\w.\-]+)\/(.*)/.test(url) &&  RegExp.$2 != window.location.host) {
    url = RegExp.$1 + '://' + window.location.host + '/' + RegExp.$3;
  }
  // support data as an array
  if (options && options.data && options.data.constructor && options.data.constructor == Array) {
    options.data = options.data.toQueryString();
  }
  
  // continue with normal initialization
  return this._initialize(url, options);
}

Element.extend({
  getParents: function(selector){
    return $$(selector || '').filter(function(el){
      return (el.hasChild(this));}, this).reverse();
  },

  getParent: function(selector){
    if (!selector) return $(this.parentNode);
    return this.getParents(selector)[0] || null;
  },

  getLastElement: function(selector){
    return $(this.getElements(selector, true).reverse()[0] || false);
  },

  centerOnScreen: function(){
    var s = this.getCoordinates();
    this.style.left = Math.round((Window.getWidth() - s.width) / 2) + Window.getScrollLeft() + 'px';
    this.style.top  = Math.round((Window.getHeight() - s.height) / 2) + Window.getScrollTop() + 'px';
  },

  positionOnScreen: function(left, top){
    this.style.left = Window.getScrollLeft() + left + 'px';
    this.style.top  = Window.getScrollTop() + top + 'px';
  },

  contains: function(evnt){
    evnt = new Event(evnt);
    var s = this.getCoordinates();
    return (evnt.page.y >= s.top &&
            evnt.page.y <= s.bottom &&
            evnt.page.x >= s.left &&
            evnt.page.x <= s.right);
  },

  overlaps: function(elmt){
    var c = this.getCoordinates();
    var e = elmt.getCoordinates();
    var inH = (e.left > c.left && e.left < c.right) || (e.right > c.left && e.right < c.right);
    var top = e.top > c.top && e.top < c.bottom;
    var btm = e.bottom > c.top && e.bottom < c.bottom;
    return (top && inH) || (btm && inH);
  },

  // linkify caries the class from the element being replaced forward to the new 'a' tag
  linkify: function(){
    var a = this.replaceWith(new Element('a', {'class': this.className, href: 'javascript:;'})).setHTML(this.innerHTML);
    _processLink(a);
    return a;
  },

  setContent: function(content) {
    if (content instanceof Array) content.each( function(v) { this.adopt($(v)); }, this );
    // IDs are case insensitive in IE
    // don't get an element by id, just check if its already an element
    else if ($type(content) == 'element') this.adopt($(content));
    else this.setHTML(content);
    return this;
  },

  hidden: function() {
    return this.getStyle('display') == 'none';
  },

  show: function() {
    return this.setStyle('display', 'block');
  },

  hide: function() {
    return this.setStyle('display', 'none');
  },
  
  toggle: function() {
    if (this.hidden()) this.show();
    else this.hide();
  },

  inDocument: function() {
    return this.parentNode != null && this.parentNode.nodeType != 11;
  }
});

/*
Class: Table

Options:
  properties - (object) properties to set on the table
  rows - (array) table contents
*/
// TODO should this extend element with overrides so it can be injected and so forth?
var Table = new Class({
  options: {
    properties: {
      cellpadding: 0,
      cellspacing: 0,
      border: 0
    },
    rows: []
  },

  initialize: function(options) {
    this.setOptions(options);
    this.table = new Element('table').setProperties(this.options.properties);
    this.tbody = new Element('tbody').injectInside(this.table);
    this.options.rows.each(this.push.bind(this));
  },

  /*
  Property: push
    Add contents to a section of the table.

  Arguments:
    row - (array) content to be added. Each item is a cell.
    section - thead or tfoot, defaults to tbody
    head - (boolean) true to use th instead of td, default is false
  */
  push: function(row, section, head) {
    var tr = new Element('tr').injectInside(section || this.tbody);
    row.each(function (v) {
      var td = new Element(head ? 'th' : 'td').injectInside(tr);
      if (v.properties) td.setProperties(v.properties);
      if (v.content)    td.setContent(v.content);
      else              td.setContent(v);
    });
    return this;
  },

  /*
  Property: pushHead
    Add a row of content to the thead. Uses TRs instead of TDs.

  Arguments:
    row - (array) content to be added. Each item is a cell.
  */
  pushHead: function(row) {
    if (!this.thead) this.thead = new Element('thead').injectTop(this.table);
    this.push(row, this.thead, true);
    return this;
  },

  /*
  Property: pushFoot
    Add a row of content to the tfoot.

  Arguments:
    row - (array) content to be added. Each item is a cell.
  */
  pushFoot: function(row) {
    if (!this.tfoot) this.tfoot = new Element('tfoot').injectInside(this.table);
    this.push(row, this.tfoot);
    return this;
  },

  /*
  Property: pushCaption
  */
  // TODO should be set caption and only allow one
  pushCaption: function(content) {
    new Element('caption').setContent(content).injectTop(this.table);
    return this;
  }
});
Table.implement(new Options);

/*
Class: Autocompleter.Ajax.Json2
  Modified version of Autocompleter.Ajax.Json that uses objects for the response
  instead of a string array.
*/
Autocompleter.Ajax.Json2 = Autocompleter.Ajax.Json.extend({
  updateChoices: function(choices) {
    this.choices.empty();
    this.selected = null;
    if (!choices || !choices.length) return;
    if (this.options.maxChoices < choices.length) choices.length = this.options.maxChoices;
    choices.each(this.options.injectChoice || function(choice, i){
      var el = new Element('li').setHTML(this.markQueryValue(choice.name));
      el.responseObj = choice;
      el.inputValue = choice.name;
      this.addChoiceEvents(el).injectInside(this.choices);
    }, this);
    this.showChoices();
  },

  choiceSelect: function(el) {
    if (el.responseObj.notFound) { this.hideChoices(); return; }
    this.observer.value = this.element.value = el.inputValue;
    this.hideChoices();
    this.fireEvent('onSelect', [this.element, el.responseObj], 20);
  },

  queryResponse: function(resp) {
    //  if the input does not have focus any more then just return
    if (!this.focussed)
    {
        return;
    }
    this.value = this.queryValue = this.element.value;
    this.selected = false;
    this.hideChoices();
    this.fireEvent(resp ? 'onComplete' : 'onFailure', [this.element, this.ajax], 20);
    var choices = Json.evaluate(resp || false);
    if (!choices || !choices.length) {
      choices = [{ name : JS_location_not_found, value: JS_location_not_found, notFound: true}];
    }
    this.updateChoices(choices);
  }
});

// subclass the autocomplete to make it more closely match noreaster behavior
Autocompleter.Ajax.Flights = Autocompleter.Ajax.Json2.extend(
{
  initialize: function(el, url, options) {
    this.parent(el, url, options);
    this.verifyAjax = new Ajax(url, {autoCancel: true, method: 'get'});
    this.verifyAjax.addEvent('onComplete', this.verifyResponse.bind(this));
    this.verifyAjax.addEvent('onFailure', this.verifyResponse.bind(this, [false]));
  },

  // override escape key so that it doesn't hide the list
  onCommand: function(e, mouse) {
    if (e.key && !e.shift && e.key == 'esc') {
      if (mouse && this.focussed) {
        this.prefetch();
      }
      e.stop();
      return;
    } else {
      this.parent(e, mouse);
    }
  },

  // make sure that we capture text in the hidden field
  toggleFocus: function(state) {
    this.parent(state);
    if (!state) {
      if (this.element.value.length) {
        // verify that we have a legal airport
        var data = $extend({}, this.options.postData);
        data[this.options.postVar] = this.element.value;
        this.verifyAjax.request(data);
      } else {
        // make sure to clear all fields
        this.fireEvent('onSelect', [this.element, {name:'',value:''}], false);
      }
    }
  },

  verifyResponse: function(resp) {
    var choices = Json.evaluate(resp || false);
    if (choices && choices.length) {
      this.fireEvent('onSelect', [this.element, choices[0]], false);
      this.element.fireEvent('airportupdate');
    } else {
      this.fireEvent('onSelect', [this.element, {name:'',value:''}], false);
    }
  }
});

/*
Class: TabSet
  The TabSet class creates a group of elements that are toggled when their handles are clicked. When one element toggles in, the others toggle back.

Arguments:
  togglers - required, a collection of elements, the elements handlers that will be clickable.
  elements - required, a collection of elements the transitions will be applied to.
  options - optional, see options below, and <Fx.Base> options and events.

Options:
  show - integer, the Index of the element to show at start.

Events:
  onActive - function to execute when an element starts to show
  onBackground - function to execute when an element starts to hide
*/
var TabSet = new Class({
  options: {
    onActive: Class.empty,
    onBackground: Class.empty,
    show: 0,
    collapsable: false
  },

  initialize: function() {
    var options, togglers, elements;
    $each(arguments, function(argument, i){
      switch($type(argument)){
        case 'object': options = argument; break;
        default:
          var temp = $$(argument);
          if (!togglers) togglers = temp;
          else elements = temp;
      }
    });
    this.togglers = togglers || [];
    this.elements = elements || [];
    this.setOptions(options);
    this.elements.each(function(el, i){
      this.togglers[i].addEvent('click', this.display.bindWithEvent(this, i));
      if (this.options.show === i){
        el.show();
        this.previous = i;
        this.fireEvent('onActive', [null, this.togglers[i], el]);
      } else {
        el.hide();
      }
    }, this);
  },

  /*
  Property: display
    Shows a specific section and hides all others. Useful when triggering a tab from outside.

  Arguments:
    index - integer, the index of the item to show, or the actual element to show.
  */

  display: function(event, index) {
    if (this.options.collapsable && index == this.previous) { // clicked on currently active tab
      if (this.elements[index].hidden()) {
        this.fireEvent('onActive', [event, this.togglers[index], this.elements[index]]);
        this.elements[index].show();
      }
      else {
        this.fireEvent('onBackground', [event, this.togglers[index], this.elements[index]]);
        this.elements[index].hide();
      }
      return this;
    }
    if (this.previous || this.previous === 0) {
      this.elements[this.previous].hide();
      this.fireEvent('onBackground', [event, this.togglers[this.previous], this.elements[this.previous]]);
    }
    this.previous = index;
    this.elements[index].show();
    this.fireEvent('onActive', [event, this.togglers[index], this.elements[index]]);
    return this;
  }
});
TabSet.implement(new Events, new Options);

/*
Class: ToggleSet
  The ToggleSet class creates a group of elements that are toggled when their handles are clicked. When one element toggles in, the others toggle back.
  
Arguments:
  togglers - required, a collection of elements, the elements handlers that will be clickable.
  elements - required, a collection of elements the transistions will be applied to
*/
var ToggleSet = new Class({
  initialize: function(togglers, elements, index) {
    this.index    = index || 0;
    this.togglers = togglers || [];
    this.elements = elements || [];
    this.togglers.each(function(el, i) {
      this.togglers[i].addEvent('click', this.display.bind(this, i));
      this.elements[i].hide();
    }, this);
  },
  
  add: function(toggler, element) {
      var i = this.togglers.length;
      this.togglers.push(toggler);
      this.elements.push(element);
      toggler.addEvent('click', this.display.bind(this, i));
      element.hide();
  },
  
  expand: function(index) {
    this.togglers[index].addClass('open');
    this.elements[index].show();
    return this;
  },
  
  collapse: function(index) {
    this.elements[index].hide();
    this.togglers[index].removeClass('open');
    return this;
  },
  
  display: function(index) {
    if (this.previous == index) {
      if (this.elements[index].hidden()) this.expand(index);
      else this.collapse(index);
    }
    else {
      if (this.previous || this.previous === 0) {
        this.collapse(this.previous);
      }
      this.previous = index;
      this.expand(index);
    }
    return this;
  }
});



/**************************************************************

	Script		: Slider
	Version		: 1.0
	Authors		: Samuel Birch
	Desc		: Slider bar.
	Licence		: Open Source MIT Licence
	Website		: http://www.phatfusion.net/index.htm
	
**************************************************************/

var Slider = new Class({

	options: {
		onChange: Class.empty,
		onComplete: Class.empty,
		onTick: function(pos){
			this.knob.setStyle(this.p, pos);
		},
		mode: 'horizontal',
		steps: 100,
		offset: 0
	},

	initialize: function(el, knob, options){
		this.element = $(el);
		this.knob = $(knob);
		this.setOptions(options);
		this.previousChange = -1;
		this.previousEnd = -1;
		this.step = -1;
		this.element.addEvent('mousedown', this.clickedElement.bindWithEvent(this));
		var mod, offset;
		switch(this.options.mode){
			case 'horizontal':
				this.z = 'x';
				this.p = 'left';
				mod = {'x': 'left', 'y': false};
				offset = 'offsetWidth';
				break;
			case 'vertical':
				this.z = 'y';
				this.p = 'top';
				mod = {'x': false, 'y': 'top'};
				offset = 'offsetHeight';
		}
		this.max = this.element[offset] - this.knob[offset] + (this.options.offset * 2);
		this.half = this.knob[offset]/2;
		this.getPos = this.element['get' + this.p.capitalize()].bind(this.element);
		this.knob.setStyle('position', 'relative').setStyle(this.p, - this.options.offset);
		var lim = {};
		lim[this.z] = [- this.options.offset, this.max - this.options.offset];
		this.drag = new Drag.Base(this.knob, {
			limit: lim,
			modifiers: mod,
			snap: 0,
			onStart: function(){
				this.draggedKnob();
			}.bind(this),
			onDrag: function(){
				this.draggedKnob();
			}.bind(this),
			onComplete: function(){
				this.draggedKnob();
				this.end();
			}.bind(this)
		});
		if (this.options.initialize) this.options.initialize.call(this);
	},

	/*
	Property: set
		The slider will get the step you pass.

	Arguments:
		step - one integer
	*/

	set: function(step){
		this.step = step.limit(0, this.options.steps);
		this.checkStep();
		this.end();
		this.fireEvent('onTick', this.toPosition(this.step));
		return this;
	},
	
	setDefault: function(step){
		if (step > this.options.steps) step = this.options.steps;
		else if (step < 0) step = 0;
		this.step = step;
		//this.checkStep();
		this.end();
		this.knob.setStyle(this.p, this.toPosition(this.step)+'px');
		return this;
	},

	scrolledElement: function(event){
		if (event.wheel < 0) this.set(this.step + 1);
		else if (event.wheel > 0) this.set(this.step - 1);
		event.stop();
	},

	clickedElement: function(event){
		var position = event.page[this.z] - this.getPos() - this.half;
		position = position.limit(-this.options.offset, this.max -this.options.offset);
		this.step = this.toStep(position);
		this.checkStep();
		this.end();
		//this.fireEvent('onTick', position);
		this.set(this.step);
	},

	draggedKnob: function(){
		this.step = this.toStep(this.drag.value.now[this.z]);
		this.checkStep();
		this.setDefault(this.step);
	},

	checkStep: function(){
		if (this.previousChange != this.step){
			this.previousChange = this.step;
			this.fireEvent('onChange', this.step);
		}
	},

	end: function(){
		if (this.previousEnd !== this.step){
			this.previousEnd = this.step;
			this.fireEvent('onComplete', this.step + '');
		}
	},

	toStep: function(position){
		return Math.round((position + this.options.offset) / this.max * this.options.steps);
	},

	toPosition: function(step){
		return this.max * step / this.options.steps;
	}

});

Slider.implement(new Events);
Slider.implement(new Options);
/*
Script: Behavior.js
  Behavior rules and related functions.
  Contains: <Behavior>
*/

var rules = {};
var rulesN = {};
var ajaxRules = {};

/*
Class: Behavior
  Custom class to help manage behavior stylish rules. Use register to register
  rules at page loading. Use reload to re-apply rules on element updated after
  an AJAX update.
 */
var Behavior = new Class({
  /*
  Property: register
    Applies the rules to the current DOM.

  Arguments:
    rules - (array) map of selectors to the functions that operate on them
  */
  register: function(rules){
    this.rules = rules;
    for (var i in this.rules) {
      this.reload(i);
    }

    for (var id in rulesN) {
      this.reloadN(id);
    }

    return this;
  },

  /*
  Property: reload
    Applies a single rule to the current DOM

  Arguments:
    rule - (string) selector that should be applied
  */
  reload: function(rule){
    elements = $$(rule);
    for(y=0;y<elements.length;y++){
      this.rules[rule](elements[y]);
    }
    return elements.length;
  },
  
  reloadN: function(id){
    var i = 0;
    while (n=$(id+(i++))) {
      rulesN[id](n);
    }
    return i - 1;
  },

  /*
  Property: apply
    Applies all registered rules to a subset of the DOM
  
  Arguments:
    elmt - (Element) DOM node to apply rules to
   */
  apply: function(elmt){
    // Process links - don't use rules[] because it is too slow for links.
    processLinks(elmt);

    for (var rule in this.rules) {
      window.applyLastRule = rule;
      elmt.getElements(rule).each(function(e){
        this.rules[rule](e);
      }, this);
    }

    for (var rule in ajaxRules) {
      window.applyLastRule = rule;
      elmt.getElements(rule).each(function(e){
        ajaxRules[rule](e);
      }, this);
    }
  }
});
window.behavior = new Behavior();


// func: doCookieCheck
//   Checks whether session cookies are accepted
//
// Returns:
//   true if session cookies are allowed
//
function doCookieCheck()
{
	// Session cookies not accepted
  Cookie.set('SessionTest', 'true', {duration: 0});
  if (Cookie.get('SessionTest')) {
    Cookie.remove('SessionTest');
    return true;
  }
  return false;
}
if (window.showPopup) showPopup();

window.addEvent('load', function() {
  Cookie.remove('NPID');

  //internet explorer fires onload event for every iframe, we only want top window
  if(window == window.top) {  
    var c = Cookie.get('ajaxAction');
    if (c) {
      Cookie.remove('ajaxAction', {domain:cookieDomain, path:"/"});
      c = c.split('|');
      if (window[c[0]]) window[c[0]].attempt(c.slice(1));// 0 - function to call, 1..N - parameters as a strings
    }
  }

  // Firefox and Safari calculate the scroll offset before content is collapsed
  // so make sure to scroll to the proper place once everything is loaded
  if (window.gecko || window.webkit) { 
    var id = window.location.hash;
    if (id.length > 1) id = id.substring(1);
    var t = $(id);
    if (t && t.getTop() != window.getScrollTop()) window.scrollTo(0, t.getTop());
  }
  
  // show any DHTML popup from the PopupManager.java
  if (typeof showDHTMLPopupOnLoad != "undefined") {
      showDHTMLPopupOnLoad();
  }
  
  if (typeof cpu_run != "undefined") cpu_run();
  
  if (/^#save/.test(location.hash)) { // saves post login popup
    doSavesPostLoginPopup();
  }
});

// Define the ready event - the point at which to load the behavior.
// This may need to be load instead of domready with cerain badly-behaving ads.
TAReadyEvent = window.TAReadyEvent || "domready";

// apply the rules when the DOM is ready.
window.addEvent(TAReadyEvent, behaviorFunction);

var bfCount = 0;
function behaviorFunction()
{
  if (window.ie &&  (!$('FOOT') || !$('FOOT').readyState || $('FOOT').readyState != 'complete') && bfCount < 10) {
    bfCount++;
    behaviorFunction.delay(30);
    return;
  }
  
  // hide some elements
  if (window.hideOnLoad) $A(hideOnLoad).each(function(v){ var x = $(v); if (x) x.hide(); });

  // grab focus of the search bar
  searchFocus();
  
  // setup popunder slots
  makePopunderSlots();
  
  // Process links - don't use rules[] because it is too slow for links.
  processLinks(document);

  // register the rules
  behavior.register(rules);
  
  //  If the location hash is set to '#Calculator' and we are on a valid
  //  servlet, open the calculator
  var main = $('MAIN');
  if ((window.location.hash == '#Calculator') &&
      ($('HOMEPAGE') ||                               //  Home Page
       (main && main.hasClass('VacationRentals')) ||  //  /VacationRentals
       $('HOTEL_LANDER')))                            //  /Hotels
  {
      //  this is a bit hacky, but don't allow other popups to open on page load.
      //  it has already been added to an onload queue so we will replace it
      //  with a no-op function.  The downside here is that we still have a cookie
      //  set as if they saw the popup but they never do.  Based on the usage of 
      //  this direct link PM (Theresa) said it is ok.
      showDHTMLPopupOnLoad = function(){};

      //  open the calculator
      vrCalculator();
  }
  
  // setup the accordion if need be
  var tabs = $$('#DEST_HOME #DEST_ACCORDION .window');
  if (tabs.length > 0) {
    var elmts = $$('#DEST_HOME #DEST_ACCORDION .pane');
    new TabSet(tabs, elmts, {
      show: 0,
      collapsable: true,
      onActive: function(event, toggler, element) {
        //if (!toggler.hasClass('first')) new Ajax('/ActionRecord?action='+toggler.id).request();
        toggler.addClass('active');
      },
      onBackground: function(event, toggler, element) {
        toggler.removeClass('active');
      }
    });
  }
  
  // setup SIS Accordion ( no preview )
  // this needs to happen after the preview accordion above for IE6 to render correctly
  // used signed-in or not
  var sisAccordionElements = $$('#SIS_ACCORDION .pane');
  if ( sisAccordionElements.length > 0 )
  {
	
	// get the orignal heights of each pane
  	var overflowElements = {};
  	sisAccordionElements.each(function(elmt,x){
  		overflowElements[x] = elmt.getStyle('height').toInt();
	});
	
	// show the first pane with content
	var showIndex = 0;
	for (var i=0; i<sisAccordionElements.length; i++)
	{
		if (sisAccordionElements[i].getElement('.sisContribution'))
		{
			showIndex = i;
			break;			
		}
	}

	window.sisAccordion = new Accordion('#SIS_ACCORDION .window', sisAccordionElements, {
	  show: showIndex,
      opacity: false, // use opacity transition
      fixedHeight: 160,
      onActive: function(toggler, element) {
        toggler.addClass('active');
        element.addClass('active');
      },
      onBackground: function(toggler, element) {
        toggler.removeClass('active');
        element.removeClass('active');
      }
  });
	
	// Change overflow and height dynamically
	window.sisAccordion.elements.each(function(elmt,x){
		// give it a scroll bar
		if (overflowElements[x] > window.sisAccordion.options.fixedHeight)
		{
			elmt.setStyle('overflow-y', 'auto');
			elmt.setStyle('overflow-x', 'hidden');
		}
		// make the height the size of the content
		else
		{
			elmt.fullHeight = overflowElements[x];
		}
		
		// make sure the initial pane is the right height
		if (x == window.sisAccordion.options.show)
		{
			elmt.setStyle('height', elmt.fullHeight);
		}
		
		// BUG 22422
		// IE6 sucks so we have to apply the offset after the DEST_HOME accordion
		// or else it doesn't refresh the preview pane for some elements.
		// Even accessing the offsetTop property earlier than this causes this bug	
		/*var flyoutsL = $$('#SIS_ACCORDION .flyoutL');
		flyoutsL.each(function(f,i){
		  f.flyout.setOptions({offsets: {x:0, y:-1*f.offsetTop-16}});
		});
		
		var flyouts = $$('#SIS_ACCORDION .flyout');
		flyouts.each(function(f,i){
			f.flyout.setOptions({offsets: {x:4, y:-1*f.offsetTop-16}});
		});*/
	});
	
	// pad if we're in the left nav and have overflow
	var sisPaddingElements = $$('#LEFTNAV #SIS_ACCORDION .pane');
	sisPaddingElements.each(function(elmt, x){
		if (overflowElements[x] > window.sisAccordion.options.fixedHeight)
		{
			elmt.setStyle('width', '166px');
			var sisPaddingNums = elmt.getElements('.num');
			sisPaddingNums.each(function(num, i)
			{
				num.setStyle('padding-right', '20px');
			});
		}
 	});

  }

  // Check for a fresh VS cookie
  // bug: 29564  gbelote
  if( typeof freshVSTrackingCookie != 'undefined' && freshVSTrackingCookie )
  {
    // Check to see if VS tracking cookie exists
    var hasVSCookie = Cookie.getRaw ('v1st');
    if (hasVSCookie)
    {
        // Fire an AJAX request
        new Ajax ('/VSCookieRequest').request ();
    }
  }
}

// Setup email replacement. e.g. #eobf( 'dmosales'  '.com')  -> mailto: 
rulesN['EOBF'] = function(elmt) {
  var e = elmt.innerHTML+'@tripadvisor'+elmt.title;
  elmt.replaceWith(new Element('a', {href: 'mailto:'+e}).setContent(e));
}

/*
Function: popup
  Show a poup window. The event target (or one of its ancestors) should be a
  link. The href of the link will be used as the URL of the popup

Arguments:
  e       - the event
  width   - width of the popup
  height  - height of the popup
  x       - horizontal screen offset
  y       - vertical screen offset
 */
var popupIndex = 0;
function popup(e, name, width, height, x, y, noScroll, buildUrl, allOptions)
{
  new Event(e).preventDefault();
  var ops = "";
  if (sz = this.className.match(/sz(\d+)x(\d+)/)) {
    width = sz[1];
    height = sz[2];
  }
  if (this.href.indexOf("p=HotelsCom") > -1) {
    width = Math.max(width, 960);
    height = Math.max(height, window.getHeight(), 600);
  }
  if (width) ops += ",width="+width;
  if (height) ops += ",height="+height;
  if (x) ops += ",screenX="+x+",left="+x;
  if (y) ops += ",screenY="+y+",top="+y;
  if (ops != "") {
    if (allOptions) {
      ops = "toolbar=1,resizable=1,menubar=1,location=1,status=1,scrollbars=1" + ops;
    }
    else {
      ops = "toolbar=0,resizable=1,menubar=0,location=0,status=0,scrollbars=" + (noScroll ? 0 : 1) + ops;
    }
  }
  var w = window.open(buildUrl ? buildUrl : this.href, name || "p"+window.name+(popupIndex++), ops);
  if (w != null)
  {
    try {w.opener = self;} catch (exc) {}
    w.focus();
  }
}

// 'this' is the element
function formSubmit(e)
{
  new Event(e).preventDefault();
  this.click();
}

function unobf(uri)
{
  return (uri.substring(0,8) == "NOFOLLOW" ? "http://" + uri.substring(8) : "/" + uri) + ".html";
}
/*
Function: toggle
  Toggle the class (default: 'off') of the element this function is bound to.
*/
function toggle(e) {new Event(e).preventDefault(); this.toggleClass('off');}

/* Some generic rules
   ---------------------------------------------------------------------------------------------- */

// called when a link with a js_ class is clicked.
var doBehavior = function(e) {
  var e = new Event(e || window.event);
  var elmt = $(e.target);
  if (elmt.getTag() != "a") elmt = elmt.getParent("a");
  if (/pid(\d+)/.test(elmt.className)) Cookie.set('NPID', RegExp.$1, {domain: cookieDomain, time:5});
  $pick(elmt.className.match(/(js_\w+)/g), []).each(function(c) {
    linkMap[c](elmt, e);
  });
}

function _processLink(elmt) {
  if (elmt.className.indexOf('js_') >= 0 || elmt.className.indexOf('pid') >= 0) {
    if (elmt.addEventListener) elmt.addEventListener('click', doBehavior, false);
    else elmt.attachEvent('onclick', doBehavior);
  }
}

var setPID = function(pid) {
   Cookie.set('NPID', pid, {domain: cookieDomain, time:5})
}

/* All Link rules in one function for performance */
function processLinks(root) 
{
  var aTags = $A(root.getElementsByTagName('a'));
  aTags.each(_processLink);
  return aTags.length;
}

function searchFocus()
{
  if($('mainSearch'))
  {
    try {
      $('mainSearch').focus();
    } catch(e) { }
  }
}

var linkMap = {};

function removeDHTMLPopup()
{
  // refresh if our dhtml popup has a child with the refreshOnClose class
  $$('#DHTMLPOPUP .refreshOnClose').each( function(item,index) {
    document.location.reload();
    return;
  });
  
  // otherwise just get rid of it
  if($('DHTMLPOPUP'))$('DHTMLPOPUP').remove();
  if($('dhtmlPopupIframe'))$('dhtmlPopupIframe').remove(); 
  if($('DHTMLPOPUP_LIGHTBOX'))
  {
    window.removeEvent('scroll', moveDHTMLPopupToScrollPosition);
    window.removeEvent('resize', resizeToWindow);
    $('DHTMLPOPUP_LIGHTBOX').remove();
    $$('select').setStyle('visibility', 'visible');
  } 
}

ajaxRules['a.dhtmlclose'] = function(elmt) {
  elmt.addEvent('click', removeDHTMLPopup);
};

// submit forms via AJAX
linkMap['js_ajaxSubmit'] = function(elmt, e) {
  var uri = elmt.href;
    if (!elmt.className.match(/\bform_(\w+)\b/)) return;
    var form = $(RegExp.$1);
    var ops = {
        data: form,
        onFailure: function(e)
        {
            if (form) form.removeClass('ajaxInFlight');
            alert(JS_Ajax_failed);
        }
    }
    var cbfn = window['callback'+form.id]; 
    if (elmt.className.match(/\method_(\w+)\b/)) ops.method = RegExp["$1"];
    if (elmt.className.match(/\btgt_(\w+)\b/)) ops.update = RegExp["$1"];
    else ops.onComplete = function(text, xml)
    {
        if (form) form.removeClass('ajaxInFlight');
        showInLightbox(text, xml);
        if (
          $defined(cbfn) &&
          $type(cbfn) == "function" )
        {
          cbfn();
        }
    }
  new Event(e).preventDefault();
  var fn = window['validate'+form.id]; 
  if (
    $defined(fn) &&
    $type(fn) == "function" &&
    fn.apply(form) == false )
        return;
  form.addClass('ajaxInFlight');
  if (elmt.className.match(/\bevalScripts\b/)) ops.evalScripts = true;  
  new Ajax(uri, ops).request();
};

// used in translations: newsletter_9b5, newsletter_9b6
linkMap['js_ajax'] = function(elmt, e) {
  new Event(e).preventDefault();
  if (!(tgt = elmt.className.match(/\btgt_(\w+)\b/))) return;// target is required
  tgt = $(tgt[1]);
  new Ajax(elmt.href, {
    update: tgt,
    onFailure: function(e) { alert(JS_Ajax_failed); }
  }).request();
};

// like 'ajax', but expected to log-in first
linkMap['js_ajaxlogin'] = function(elmt, e) {
  new Event(e).preventDefault();
  if (!(tgt = elmt.className.match(/\btgt_(\w+)\b/))) return;// target is required
  var alHref = elmt.href;
  tgt = $(tgt[1]);
  new Ajax(elmt.href, {
    onComplete: function(txt, xml) {
      var bWasLoggedIn = (txt.indexOf('<!--nologin-->')<0);
      if(!bWasLoggedIn)
      {
          login(['tt','ajax','returnTo', alHref + "&rd=1", 'greeting', 'showuserreviews_vote_25ee' ]);
      }
      else
      {
          tgt.innerHTML = txt;
      }
    },
    onFailure: function(e) { alert(JS_Ajax_failed); }
  }).request();
};


linkMap['js_ajaxMsg'] = function(elmt, e) {
  if (elmt.className.match(/\bcallback_ShowRecaptcha\b/))
  {
    new Asset.javascript('http://api.recaptcha.net/js/recaptcha_ajax.js');
  }
  ajaxMsg.attempt(e, elmt);
};

linkMap['js_ajaxReport'] = function(elmt, e) {
  ajaxReport.attempt(e, elmt);
};

linkMap['js_popdoshoot'] = function(elmt, e) { popup.attempt([e, 'review', 813, 600, 80, 50], elmt); };
linkMap['js_popdoshootslide'] = function(elmt, e) { popup.attempt([e, 'review', window.screen.width, window.screen.height, 80, 50], elmt); };

// open links in popups of various sizes
linkMap['js_popup'] = function(elmt, e) { popup.attempt(e, elmt); };
linkMap['js_popComm'] = function(elmt, e) { if (typeof pageTracker != "undefined") { var utmp = "/"+elmt.href.replace(/^http:\/\/.+\//i, ""); pageTracker._trackPageview(utmp); } popup.attempt([e, null, 950, 610, null, null, null, null, true], elmt); };
// FIXME: tourism-narrow only
linkMap['js_popNoScroll'] = function(elmt, e) { popup.attempt([e, null, null, null, null, null, true], elmt); };
linkMap['js_popCR'] = function(elmt, e) { popup.attempt([e, 'cr', 245, 610, 5, 5], elmt); };
linkMap['js_email'] = function(elmt, e) {  popup.attempt([e, 'email', 580, 460, 30, 25], elmt); };
// FIXME: SUR only
linkMap['js_popReview'] = function(elmt, e) { popup.attempt([e, 'review', 550, 395, 30, 25], elmt); };
linkMap['js_popPhoto'] = function(elmt, e) { popup.attempt([e, 'photo', 650, 350], elmt); };
linkMap['js_popGallery'] =  function(elmt, e) { popup.attempt([e, 'media', 782, 820], elmt); };
linkMap['js_popGalleryComm'] = function(elmt, e) { popup.attempt([e, 'media', 780, 950], elmt); };
linkMap['js_popDMO'] = function(elmt, e) { popup.attempt([e, 'dmo', 400, 400], elmt); };
// FIXME: nexus only
linkMap['js_popNxTall'] = function(elmt, e) { popup.attempt([e, 330, 680], elmt); };
linkMap['js_popNxWide'] = function(elmt, e) { popup.attempt([e, 730, 380], elmt); };
linkMap['js_popNxLogin'] = function(elmt, e) { popup.attempt([e, 'login', 795, 645], elmt); };
linkMap['js_popFraud'] = function(elmt, e) { popup.attempt([e, 'fraud', 640, 460], elmt); };
linkMap['js_popDestGd'] = function(elmt, e) { popup.attempt([e, 'dest_guide', 565, 700, (screen.width-700)/2, (screen.height-600)/2], elmt); };
linkMap['js_tamgSubsDestGd'] = function(elmt, e) {
  window.showTamgSubsLB = function() { 
    new Ajax('/TAMGSubOffers?t=DG_LB', {
      onComplete: function(txt, xml) { showInLightbox(txt, null, null, null, null); },
      method: 'get',
      evalScripts: true
    }).request(); };
};

linkMap['js_popPromo'] = function(elmt, e) { popup.attempt([e, 'promo', 600, 700, 30, 25], elmt) };

linkMap['js_popSmall'] = function(elmt, e) {
  if (screen.width > 1024)     { popup.attempt([e, null, 800, 600, 240, 5, false, false, true], elmt); }
  else if (screen.width > 800) { popup.attempt([e, null, 620, 500, 240, 5, false, false, true], elmt); }
  else                         { popup.attempt([e, null, 475, 390, 210, 5, false, false, true], elmt); }
  return elmt;
};

linkMap['js_popProfPhoto'] = function(elmt, e) {
  if (screen.width > 1024)     { popup.attempt([e, null, 800, 500, 240, 5, false, false, true], elmt); }
  else if (screen.width > 800) { popup.attempt([e, null, 620, 450, 240, 5, false, false, true], elmt); }
  else                         { popup.attempt([e, null, 475, 390, 210, 5, false, false, true], elmt); }
  return elmt;
};

linkMap['js_popPartner'] = function(elmt, e) {
  if (screen.width > 1024)     { popup.attempt([e, null, 980, 500, 240, 5, false, false, true], elmt); }
  else if (screen.width > 800) { popup.attempt([e, null, 800, 500, 240, 5, false, false, true], elmt); }
  else                         { popup.attempt([e, null, 620, 450, 210, 5, false, false, true], elmt); }
  return elmt;
};

linkMap['js_noTAPD'] = function(elmt, e) { Cookie.remove('TAPD', {domain: cookieDomain}); };

// FIXME: only used on nexus
linkMap['js_modifySub'] = function(elmt, e) { modifySub.apply(elmt, [e]); };

// FIXME: only used in compose/send message lightbox layer - THIS DOES NOT WORK W/ LINK ASSUMPTION
ajaxRules['a.js_delay'] = function(elmt) {
  if (!(ms = elmt.className.match(/\b(\d+)ms\b/))) return;
  ms = parseInt(ms[1]);
  elmt.fireEvent('click', null, ms);
};

// TODO: remove this once the new dhtml popup framework gets out of pool testing
ajaxRules['a.figsSurveyLink']=function(elmt, e) {
  Cookie.set('TAPanelSurveyPopup', '-1', {domain:cookieDomain, path:"/", duration:365});
}


rules['a#TERMS'] = function(elmt) {  elmt.addEvent('click', popup.bindAsEventListener(elmt, ['terms',       300, 300, 30, 25]));};

// IE6 does not support :hover on elements other than <A>
// use .hvrIE6 and style with .hvrIE6.mseOvr
if (window.ie6 && window.pageServlet != 'Hotel_Review')
{
  rules['span.hvrIE6, label.hvrIE6, h2.hvrIE6']=function(elmt)
  {
    elmt.addEvent('mouseenter', function() { elmt.addClass('mseOvr'); });
    elmt.addEvent('mouseleave', function() { elmt.removeClass('mseOvr'); });
  }
}


// Disabled - For next sponsorship, target using an ID and move to page-specific JS file(s)
/*rules['area.js_popSmall'] = function(elmt) {
  elmt.addEvent('click', function() {
    if (screen.width > 1024)     { popup.attempt([null, 800, 600, 240, 5, false, false, true], elmt); }
    else if (screen.width > 800) { popup.attempt([null, 620, 500, 240, 5, false, false, true], elmt); }
    else                         { popup.attempt([null, 475, 390, 210, 5, false, false, true], elmt); }
  });
}*/

// used by TW and MU callouts on LHS, TCH2009
// text elements with class 'focusClear' have their value cleared on focus if it is the default value
//rules['#NEWSLETTER_CALLOUT input.focusClear[type=text]'] = 
rules['#causeRadioLander input.focusClear[type=text]'] = rules['#USER_REVIEW_FORM input.focusClear[type=text]'] = rules['#TCH input.focusClear[type=text]'] = rules['#TCH_POP_FRM input.focusClear[type=text]'] = rules['#TCH2009_WIDGET input.focusClear[type=text]'] = rules['#HOMEPAGE input.focusClear[type=text]'] = rules['#homePageVRCalcPromo input.focusClear[type=text]'] = rules['#DBV input.focusClear[type=text]'] =function(elmt) {

  elmt.addEvent('focus', function()
  {
    if (elmt.value == elmt.defaultValue)
    {
      elmt.value = '';
      elmt.removeClass('focusClear');
    }
  });
}

rules['#NEWSLETTER_CALLOUT input.memberUpdateEmail[type=text]'] = function(elmt) {
  $('memberUpdatesEmailDefault').hide();
  $(elmt.form).addEvent('submit', function(e) {
  	if(elmt.value == $('memberUpdatesEmailDefault').innerHTML)
  	{
  		elmt.value = ""; 		
  	}
  });
}

// don't try to gain focus of search box on any forum servlets
/* bug 28219  gbelote
rules['#SEARCH_LHN'] = function(elmt) {
  if(pageServlet != 'ShowForum' 
    && pageServlet != 'ShowTopic'
    && pageServlet != 'ForumHome'
    && pageServlet != 'ListForums' 
    && pageServlet != 'NewTopic' 
    && pageServlet != 'PostReply')
  {
	  window.addEvent('load', function() {
		  try { elmt.getElement('input[type=text]').focus(); } catch(e) { }
	  });
  }
  elmt.getElement('form').addEvent('submit', function(e) {if (elmt.value == '') (new Event(e)).stop();});
}
*/

// text elements with class 'alertIfEmpty' cause form submission to fail and an alert to be shown if the value is empty
// not targetted better because form can occur twice on BYG
var alertIfEmpty = function(elmt) {
  $(elmt.form).addEvent('submit', function(e) { if (elmt.value == '') {
     if(msg = elmt.className.match(/\bmsg_([\w\d]+)\b/)) {
        alert(window[msg[1]]);
     } else {
        alert('The field can not be empty'); // input fields should instead use a localization key
     }
     (new Event(e)).stop();
   }});
}
rules['#NX_NEW_TITLE input, #NX_NEW_TITLE2 input'] = alertIfEmpty;

rules['select.submitOnChange'] = function(elmt) {
  elmt.addEvent('change', function() {elmt.form.submit();});
}

// MOVE - only used on Fun Stuff landing page
// rules['select.redirOnChange'] = function(elmt) {
//   elmt.addEvent('change', openValueInNew.bindAsEventListener(elmt));
// }

// clicking the 'search within' checkbox should set the 'exc' form field to 'n' when selected, 'y' otherwise
//rules['.navSrch input#geo'] = function(elmt) {
//  elmt.addEvent('change', function() {$('exc').value = elmt.checked ? 'n' : 'y';});
//}

// collapsible content - hide initially
var toggleMeRule = function(elmt) {
  if( false == elmt.hasClass('defaultOpen') ) {
    elmt.addClass('off');
  }

  elmt.getElement('.show').addEvent('click', toggle.bindAsEventListener(elmt));
  elmt.getElements('.hide').addEvent('click', toggle.bindAsEventListener(elmt));
}
rules['#TOGGLEME'] = toggleMeRule; // to appease FF's XPath
rules['#TOGGLEME2'] = toggleMeRule;

// used by DHTML pop-ups
// .js_swapBlocks is an open-only toggle
ajaxRules['div.js_swapBlocks'] = function(elmt) {
  var swapOut = elmt.getElement('.js_swapOut');
  var swapIn = elmt.getElement('.js_swapIn');
  var swapTrigger = elmt.getElement('a.js_swapTrigger');
  var swapBackTrigger = elmt.getElement('a.js_swapBackTrigger');
  if(swapOut && swapIn && swapTrigger) 
  {
     swapTrigger.addEvent('click',  function(e) { new Event(e).preventDefault(); window.removedBit = swapOut.remove(); swapIn.show(); });
     swapTrigger.removeClass('js_swapTrigger');
  }
  if(swapOut && swapIn && swapBackTrigger) 
  {
     swapBackTrigger.addEvent('click',  function(e) { new Event(e).preventDefault(); swapIn.hide(); $('parentOfSwapOut').appendChild(window.removedBit); });
     swapBackTrigger.removeClass('js_swapBackTrigger');
  }
}

// MOVE - only used by nexus
// Nexus - subscribe/unsubscribe
var modifySub = function(e) {
  (new Event(e)).preventDefault();
  var elmt = this;
  new Json.Remote(this.href, {
    onFailure: function(e) { alert(JS_Ajax_failed); },
    onComplete: function(rslt) {
      if (rslt && rslt.debug && rslt.editErrorTag)
        alert("Error during ajax call, \nTag: " + rslt.editErrorTag + "\nMsg: " + rslt.editErrorMessage + "\nContent: " + data.editErrorContent);
      else if (rslt.readonly) document.location = rslt.maintenanceUrl;
      else if (rslt.loginUrl) document.location = rslt.loginUrl;
      else {
        var i = elmt.getParent().id;
        if (/^un/.test(i)) i = i.substring(2);
        else i = "un" + i;
        elmt.getParent().hide();
        $(i).show();
      }
    }
  }).send();
}

// MOVE - only used by a couple servlets
// type ahead
rules['input.typeAhead[type=text]'] = function(elmt) {
 if (action = elmt.className.match(/\bact(\w+)\b/)) {
   var onSelectFunc = elmt.className.match(/\bonSel-(\w+)\b/);
   if ((onSelectFunc != null) && (onSelectFunc.length > 0))
   {
       onSelectFunc = window[onSelectFunc[1]];
   }
   
   //  check if we have a custom zIndex
   var zIndex = 42; //  42 is the default in Autocompleter.js
   var zIndexClass = elmt.className.match(/zIndex-(\d+)/);
   if (zIndexClass != null)
   {
       zIndex = zIndexClass[1];
   }
   
   new Autocompleter.Ajax.Json2(elmt, "/TypeAheadJson?action="+action[1], {
     ajaxOptions: {method:'get'},
     postVar: 'query',
     inheritWidth: false,
     'zIndex':zIndex,
     onSelect: function(elemt, resObj) {
       if (onSelectFunc) {
         onSelectFunc(elemt, resObj, elmt);
       }
     }
   });
 }
}

// used in DHTML pop-up
ajaxRules['#PM_UNBLOCK'] = function(elmt) {
  elmt.addEvent('submit', function(e) {
    new Event(e).stop();
    var form = $('PM_UNBLOCK');
    if (form.unblock.value == '1') {
      new Ajax('/SendMessageRD', {
        data: form,
        onComplete: showInLightbox,
        onFailure: function(e) { alert(JS_Ajax_failed); }
      }).request();
    }
    else {
      $('unblock-intercept').hide();
      $('blockedreply').show();
      form.unblock.value = '1';
    }
  });
}

// Tank-Of-Gas city type ahead form
//rules['#togGeoSearch'] = function(elmt) {
//  elmt.addEvent('click', function(e) {
//    var form = $("TOG_FORM");
//    if (form.elements.q.value == "Enter City")
//    {
//        form.elements.q.value = "";
//    }
//  });
//}

// members only (member benefits) tank-of-gas form
//rules['#TRAVEL_GUIDES_LANDER #TOG_FORM'] = function(elmt) {
//  elmt.addEvent('submit', function(e) {
//    processTOGForm(e);
//  });
//}

// members only (member benefits) guide request form
//rules['#MOG_FORM'] = function(elmt) {
//  elmt.addEvent('submit', function(e) {
//      processGuideRequest(e);
//  });
//}

// members only (member benefits) subscription form
// rules['#MEMONLY_SUBS_FORM'] = function(elmt) {
//   elmt.addEvent('submit', function(e) {
//       processMOSubscribeRequest(e);
//   });
// }

var showInLightbox = function(txt, customContentId, topPos, leftPos, onActivate) {
  // hide any flyout that's open
  if (window.flyout) window.flyout.hide();
  // if there is a currently visible lightbox, use it
  if (window.lightbox && window.lightbox.inner) {
    window.lightbox.inner.setContent(txt);
    window.lightbox.actions();
  } else {
    var ops = {};
    if ($defined(customContentId) && typeof customContentId == 'string') ops.contentId = customContentId;
    if ($defined(topPos)) ops.top = topPos;
    if ($defined(leftPos)) ops.left = leftPos;
    if ($defined(topPos) || $defined(leftPos)) ops.centerOnScreen = false;
    if ($defined(onActivate)) ops.onActivate = onActivate;
    new Lightbox(txt, ops).activate();
  }
}

function enableCommunity(callback, noHandle)
{
  var res = callback;
  if (!noHandle) res = function(r) {enableCommunityResponse(r, callback);}
  new Ajax("/CommunityAjax?action=CommunitySet&set=on", {
    onComplete: res,
    onFailure: function(e) { alert(JS_Ajax_failed); }
  }).request();
}

function enableCommunityResponse(res, callback) {
  var in_data = eval("(" + res.responseText + ")");
  if (in_data.error) {
    document.getElementById('inviteStatusField').innerHTML = in_data.error;
    document.getElementById('inviteStatusField').style.display='block';
  } else if (in_data.response) {
    document.getElementById('inviteStatusField').innerHTML = in_data.response;
    document.getElementById('inviteStatusField').style.display='block';
    //setTimeout(function() {hide('confirmBubble'); callback();}, 1000);
  }
}

var communityLightbox = function(uri, sCBFuncName) {
  if (!userLoggedIn || migrationMember) return;
  if (!communityEnabled) {
    window['callback_communityLightboxEnable'] = function() {communityEnabled = true; window.lightbox.deactivate(); communityLightbox(uri, sCBFuncName);};
    var aSMC = new StringBuffer();
    aSMC.append('<p id="inviteStatusField" style="display: none; color: red;"></p>');
    aSMC.append('<p>'+JS_mem_travelnet_friends_disabledM2M+'.</p>'); // You have disabled member-to-member communications
    aSMC.append('<p><a href="javascript:void(0)" onclick="enableCommunity(window[\'callback_communityLightboxEnable\'], true); return false;">'+JS_common_Clickhere+'</a> '+JS_mem_travelnet_friends_turnOn+'.</p>'); // Click here to turn the feature back on and send your message
    showInLightbox(aSMC.toString());
    return;
  }
  if (sCBFuncName)
  {
    var callback_communityLightbox = function(r) {
      showInLightbox(r);
      var cbfn = window[sCBFuncName];
      if (
          $defined(cbfn) &&
          $type(cbfn) == "function" )
      {
        cbfn();
      }
    };
  }
  else
  {
    var callback_communityLightbox = showInLightbox;
  };

  var ops = {
      onComplete: callback_communityLightbox,
      evalScripts: true,
      onFailure: function(e)
      {
        alert(JS_Ajax_failed);
      }
  };
  new Ajax(uri, ops).request();
}

function getRelativeURL() {
  return window.location.pathname + window.location.search + (window.location.hash.length > 0 ? '#' : '') + window.location.hash;
}

var ajaxMsg = function(e) {
  new Event(e).preventDefault();
  var sCBFuncName;
  if (this.className.match(/\b(callback_ShowRecaptcha)\b/))
  {
    sCBFuncName = RegExp["$1"];
  }
  if (!userLoggedIn || migrationMember) {
    if (!(ops = this.className.match(/\bpm(\d)([A-F0-9]+)\b/))) return;
    var msgType = parseInt(ops[1]) == 1 ? "cc" : "cm";
    var greeting = msgType == "cm" ? "m2m_singin_greeting_d99" : "";
    var uid = ops[2];
    var cookieVal = "communityLightbox|" + this.href;
    if (sCBFuncName)
    {
      cookieVal += "|" + sCBFuncName;
    }
    Cookie.set('ajaxAction', cookieVal, {domain:cookieDomain, path:"/"});
    var func = !userLoggedIn ? login : migrate;
    func(['tt',msgType,'greeting',greeting,'returnTo', getRelativeURL()]);
    return;
  }
  communityLightbox(this.href, sCBFuncName);
}

var ajaxLightbox = function(uri, onActivate) {
  new Ajax(uri, {
    onComplete: function(txt, xml) { showInLightbox(txt, null, null, null, onActivate); },
    onFailure: function(e) { alert(JS_Ajax_failed); }
  }).request();
	
}

var ajaxReport = function(e) {
  new Event(e).preventDefault();
  ajaxLightbox(this.href);
}

var follow = function(id) {return function(){window.location = $(id).href;}}
//rules['#REVIEWS span.fkLnk,#PERSPECTIVES span.fkLnk,#TOURISMREVIEWS span.fkLnk'] = function(elmt) {
//  if (/\bt([\w\d]+)\b/.test(elmt.className)) elmt.addEvent('click', follow(RegExp.$1));
//}

rules['#dhtmlPopupClose']=function(elmt) {
  elmt.addEvent('click', function() {
  	 $('DHTMLPOPUP').remove();
     $('dhtmlPopupIframe').remove();
   });
}

var reviewRating = new Class(
{
	initialize: function(userId, rating) 
	{
		this.userId = userId;
		this.rating = rating;
	}
});

var dualSliderRule = function(elmt) 
{
  var sDivOne = elmt.getElement('.sOne');
  var sDivTwo = elmt.getElement('.sTwo');
  var minMax = elmt.getElement('.minMax');
  var sMin = elmt.getElement('.rangeMin');
  var sMax = elmt.getElement('.rangeMax');
  var sLeft = elmt.getElement('.sLeft');
  var sRight = elmt.getElement('.sRight');

  var sldrSteps = parseInt(elmt.className.match(/s(\d+)/)[1]);
  var sldrMin = parseFloat(elmt.className.match(/mn([\d.]+)/)[1]);
  var sldrMax = parseFloat(elmt.className.match(/mx([\d.]+)/)[1]);
  var selMin = parseFloat(elmt.className.match(/smin([\d.]+)/)[1]);
  var selMax = parseFloat(elmt.className.match(/smax([\d.]+)/)[1]);
  var sName = elmt.className.match(/name(\w+)/)[1];
  var maxAllInclusive = elmt.hasClass('maxAllInclusive');
  var sOffset = /off(\d+)/.test(elmt.className) ? parseInt(RegExp.$1) : 1;

  if(elmt.className.match(/cur(\d+)/))
  {
    crncy = currencyCodes[ elmt.className.match(/cur(\d+)/)[1] ];
  }

  var doRounding = elmt.className.match(/(round)/);
  if(doRounding) doRounding = true;

  if (sDivOne && sDivTwo)
  {
    var slider = new DualSlider(elmt, sDivOne, sDivTwo, {
      "maxAllInclusive":maxAllInclusive,
      
      onChange: function() {
        var valOne = sliderStepToValue(sldrMin, sldrMax, sldrSteps, slider.knobOne.step, slider.options.round);
        var valTwo = sliderStepToValue(sldrMin, sldrMax, sldrSteps, slider.knobTwo.step, slider.options.round);
        
        //  if the values have not changed then mark the hidden field value accordingly (since we use 0 & 999999 to 
        //  indicate no selection as opposed to the boundary values which imply an explicit selection).
        var minMaxLow = valOne < valTwo ? valOne : valTwo;
        var minMaxHigh = valTwo < valOne ? valOne : valTwo;
        if (minMaxLow == sldrMin) minMaxLow = 0;
        if (minMaxHigh == sldrMax) minMaxHigh = 999999;
        minMax.value = minMaxLow + "," + minMaxHigh;

        var sLower = (valOne <= valTwo) ? valOne : valTwo;
        var sUpper = (valOne <= valTwo) ? valTwo : valOne;

        //  currency slider
        if(slider.options.name == 'pslider')
        {
          sMin.innerHTML = getCurrencyFormat(sLower);
          sMax.innerHTML = getCurrencyFormat(sUpper);
        }
        //  rating slider
        else if(slider.options.name == 'rslider')
        {
          if( (sLower+"").length == 1) sLower = sLower + ".0";
          sMin.innerHTML = sLower;
          if( (sUpper+"").length == 1) sUpper = sUpper + ".0";
          sMax.innerHTML = sUpper;

          var pattern = /(^.*)(\d\.\d)(.gif)/;
          updateRatingSrc(sLeft, pattern, true, sLower);
          updateRatingSrc(sRight, pattern, true, sUpper);
        }
        //  star slider
        else if(slider.options.name == 'sslider')
        {
          sMin.innerHTML = sLower;
          sMax.innerHTML = sUpper;

          var pattern = /(^.*)(\d)(.gif)/;
          if(sLower >= 1 && sLower <= 5) //bug 27384
          {
            updateRatingSrc(sLeft, pattern, false, sLower);
          }
          if(sUpper >= 1 && sUpper <= 5) //bug 27384
          {
            updateRatingSrc(sRight, pattern, false, sUpper);
          }
        }
        //  integer slider
        else if (slider.options.name == 'islider')
        {
          sMin.innerHTML = sLower;
          sMax.innerHTML = slider.options.maxAllInclusive && (sUpper == sldrMax) ? 
                           sUpper + "+" :
                           sUpper;
        }
      },
      onComplete: ($defined(window['sliderMoved']) ? sliderMoved : Class.empty),
      steps: sldrSteps-1,
      offset: sOffset,
      round: doRounding,
      name: sName
    });
    slider.setKnobFromValue(sDivOne, selMin, sldrMin, sldrMax, sldrSteps);
    slider.setKnobFromValue(sDivTwo, selMax, sldrMin, sldrMax, sldrSteps);
    slider.sliderOptions = {
      knobs: [sDivOne, sDivTwo],
      min: sldrMin,
      max: sldrMax,
      step: sldrSteps
    };
    elmt.slider = slider;
  }
}
rules['#LEFTNAV .fltr div.dualSliderTest'] = dualSliderRule;
rules['#HAC_FORM div.dualSliderTest'] = dualSliderRule;

function updateRatingSrc(elem, pattern, isDec, newVal)
{
  var elemMatch = elem.getElement('.lmtImg').src.match(pattern);
  if(elemMatch)
  {
    if( (newVal+"").length == 1 && isDec)
      newVal = newVal + ".0";
    elem.getElement('.lmtImg').src = elemMatch[1] + newVal + elemMatch[3];
  }
}

function getCurrencyFormat(num)
{
  var selCurrency = typeof crncy != "undefined" ? crncy : 'USD';
  var curOptions = currencySymbol[selCurrency];
  var tempNum = formatThousands(num);
  if(!curOptions[1])
  {
    return curOptions[0] + tempNum;
  }
  else
  {
    return tempNum + curOptions[0];
  }
}

//note this assumes num is an integer - no decimals
function formatThousands(num)
{
    if(typeof groupingSize == "undefined" || typeof groupingSeparator == "undefined" || groupingSize < 1)
    {
        return num;
    }
    var result = "";
    var tempString = "" + num;
    for(var i = 1; i <= tempString.length; i++)
    {
        result = tempString.charAt(tempString.length - i) + result;
        if(i % groupingSize == 0 && i < tempString.length)
        {
            result = groupingSeparator + result;
        }
    }
    return result;
}

function sliderStepToValue(min, max, totalSteps, currentStep, round)
{
  if(round)
    return Math.round( currentStep * ( (max - min) / (totalSteps - 1) ) ) + min;
  return currentStep * ( (max - min) / (totalSteps - 1) ) + min;
}

var currencyHash = new Object();
function buildCurrencyHash(ind, min, max, selMin, selMax, steps)
{
  currencyHash[ind] = { 'min' : min, 'max' : max,'selMin' : selMin,'selMax' : selMax, 'steps' : steps};
}

var weeklyCurrencyHash = new Object();
function buildWeeklyCurrencyHash(ind, min, max, selMin, selMax, steps)
{
  weeklyCurrencyHash[ind] = { 'min' : min, 'max' : max,'selMin' : selMin,'selMax' : selMax, 'steps' : steps};
}


// used to submit the page when the user toggles "Original in <language>" or "Automatic Translation" radio buttons
// have to use the onclick event because IE6 doesn't handle onChange properly with radio buttons
//rules['input.submitOnClick[type=radio]'] = function(elmt)
//{
//  elmt.addEvent('click', function() 
//  	{
//  		elmt.form.submit();
//  	});
//}

// Name of the cookie used to track the distance units for "Nearby Locations"
var distanceUnitsCookieName = "TAdistanceCookie";

// rules['#NEARBY .js_miOp']=function(elmt)
// {
//   elmt.addEvent('click', showMi.bindAsEventListener(elmt));
// }

// rules['#NEARBY .js_kmOp']=function(elmt)
// {
//   elmt.addEvent('click', showKm.bindAsEventListener(elmt));
// }

rules['#NEARBY #nearbyDistanceUnits']=function(elmt) 
{
	Cookie.set(distanceUnitsCookieName, $(elmt).value);
}

// Attempt a popUp on window load, on failure show link in lightbox -dkw
rules['#js_tryPop'] = function(tryPop) 
{
  var lnk = tryPop.getElement('a.js_popLink');
  var ops = "toolbar=0,resizable=1,menubar=0,location=0,status=0,scrollbars=1";
 
 //link to try
  if(lnk) {
   if(!window.open( lnk.href, lnk.name, ops)) {
    // lightbox message
    if(tryPop.getElement('div.js_lightBoxMsg')) 
     window.addEvent( 'load', function() {  showInLightbox(tryPop.getElement('div.js_lightBoxMsg').innerHTML) } );
    }
  } 
 }

// Log a Review Link click for reporting
rules['#REVIEW_LINK']=function(elmt) { elmt.addEvent('click', reviewLinkClick.bindAsEventListener(elmt));};
function reviewLinkClick(pid) 
{
  var pid = $('REVIEW_LINK').className.match(/pid(\d+)/) ;
  if (pid && pid[1])
  {
    Cookie.set('NPID', pid[1], {domain: cookieDomain, time:5});
    new Ajax('/ActionRecord?action=review_click').request();
  }
}

rules['#memberFlyout .memberBenefitsPopup'] =function(elmt) {
  elmt.addEvent('click', function(e) { 
    new Event(e).preventDefault();
    showDHTMLPopup('MemberBenefitsPopup', '/MemberBenefitsPopup', true) 
  } );
}

// this must be declared here
var popupConfig = {};

function addNonMember(e, elmt) {
        if (!elmt) elmt = this;
  	popupConfig.clickedElement = elmt;
  	new Event(e).preventDefault();
  	
  	// if the clicked element has a pid then add that to the url
  	var url = '/MemberBenefitsPopup';
  	if (/pid(\d+)/.test(elmt.className)) {
  	  url += '?pid='+RegExp.$1;
  	}
  	
  	showDHTMLPopup('MemberBenefitsPopup', url, true);
}
  
function clickNonMember() {

  setTimeout("removeDHTMLPopup()", 500);
  
  if (popupConfig.clickedElement == null) return;
  
  var c = popupConfig.clickedElement;
  popupConfig.clickedElement = null;
  
  $$('#TRAVEL_GUIDES_LANDER .clickNonMember').each( function(el, i) {
    el.removeEvent('click', addNonMember);
  });

  $$('#TRAVEL_GUIDES_FLY .clickNonMember').each( function(el, i) {
    el.removeEvent('click', addNonMember);
  });

  if (c.className.match(/\bclickPopDestMOGLink\b/))
    processPopDestMOGLink(null, c);
  else if (c.getTag() == "a")
    window.location= c.getProperty('href');
  else
    c.click();
}

function processPopDestMOGLink(e, elmt) {
  if (!elmt) elmt = this;
  if (!loggedIn)
    addNonMember(e,elmt);
  else 
    processGuideLink(e,elmt);
}

// members only non-member click
rules['#TRAVEL_GUIDES_LANDER .clickNonMember'] = rules['#TRAVEL_GUIDES_FLY .clickNonMember'] = function(elmt) {
  if (elmt.getTag() != 'a' || ! elmt.className.match(/\bskipATag\b/)) {
    elmt.addEvent('click', addNonMember);
  };
}

// members only popular destination guide link click
rules['#TRAVEL_GUIDES_LANDER .clickPopDestMOGLink'] = function(elmt) {
  elmt.addEvent('click', processPopDestMOGLink);
}

// When clicked we go back to our last eligible URL as defined in FullServlet.handleReturnTo.
// If we have no cookie go to the homepage
linkMap['js_back']=function(elmt, e) {
     var matches = document.cookie.match('(?:^|;)\\s*TAReturnTo=\%1\%([^;]*)');
     if (matches)
     {
     	window.location = decodeURIComponent(matches[1]);
     }
     else
     {
     	window.location = "/";
     }
}

// This is the preferred way of showing a Dhtml Popup
// PopupManager.java uses these functions along with some velocty stuff in header_popup.vm
function showDHTMLPopup(popupServlet, popupServletUrl, popupLightbox, ops, e)
{
    popupConfig.servlet = popupServlet;
    popupConfig.servletUrl = popupServletUrl;
    popupConfig.lightbox = popupLightbox;
    popupConfig.options = ops;
    
    if (ops && ops.loading && e) {
      e = new Event(e);
      $(ops.loading).show().injectInside(document.body).setStyles({
        left: e.page.x + 20, // to the right of the mouse
        top: e.page.y
      });
    }
    
    DHTMLPopupRequest("Open", DHTMLPopupResponse, null, ops ? ops.data : null);
}

  
function popupResponseSuccess(content)
{
}

function popupResponeError(e)
{
}
  
var DHTMLPopupResponse = function(content) {

  if (popupConfig.options && popupConfig.options.forward && window.popupForward)
  {
    window.location = window.popupForward;
  }

  // make sure we're not showing a flyout, if so destroy it!!!
  $$('#FLYOUT').each(function(item, index)
  {
    item.remove();
  });

  // make sure we're not showing a popup already, if so destroy it!!!
  $$('#DHTMLPOPUP').each(function(item, index)
  {
    item.remove();
  });
  
  // make sure we're not showing a lighbox already, if so destroy it!!!
  $$('#DHTMLPOPUP_LIGHTBOX').each(function(item, index)
  {
    item.remove();
  });
  
  $$('#dhtmlPopupIframe').each(function(item, index)
  {
    item.remove();
  });
  
  if (popupConfig.options && popupConfig.options.loading) $(popupConfig.options.loading).hide();
  
  // DHTML lightbox
  var lightbox;
  if (popupConfig.lightbox)
  {
    lightbox = new Element('div', {id: 'DHTMLPOPUP_LIGHTBOX'}).injectInside(document.body);
	var pageSize = Math.max( window.getHeight(), window.getScrollHeight() );
	lightbox.setStyle('height', pageSize + 'px');
  }
  
  // create container elements
  var ctnr = new Element('div', {id: 'DHTMLPOPUP'}).injectInside(document.body);
  
  // rounded corners
  var top  = new Element('div', {'class': 'cnrR5 top'}).injectInside(ctnr);
  var tl   = new Element('div', {'class': 'lft'}).setContent("<!--Lft Corner-->").injectInside(top);
  var tm   = new Element('div', {'class': 'mid'}).setContent("<!--Mid Border-->").injectInside(top);
  var tr   = new Element('div', {'class': 'rgt'}).setContent("<!--Rgt Corner-->").injectInside(top);
  var btm  = new Element('div', {'class': 'cnrR5 btm'}).injectInside(ctnr);
  var bl   = new Element('div', {'class': 'lft'}).setContent("<!--Lft Corner-->").injectInside(btm);
  var bm   = new Element('div', {'class': 'mid'}).setContent("<!--Mid Border-->").injectInside(btm);
  var br   = new Element('div', {'class': 'rgt'}).setContent("<!--Rgt Corner-->").injectInside(btm);

  var div  = new Element('div', {'class': 'close'}).injectInside(ctnr);
  
  new Element('span', {'class': 'cnrL'}).injectInside(div);
  new Element('span', {'class': 'cnrB'}).injectInside(div);
  new Element('span', {'class': 'cnrBL'}).injectInside(div);
  if(typeof dhtmlRedirectLink != 'undefined')
  {
	var closeLink = new Element('a', {'href': dhtmlRedirectLink}).setContent(lang_Close).injectInside(div);
  }
  else if (typeof addPopupCloseClass != 'undefined' && addPopupCloseClass == true)
  {
    var closeLink = new Element('a', {'class': 'dhtmlclose popupClose'}).setStyle('cursor', 'pointer').setContent(lang_Close).injectInside(div);
  }
  else 
  {
    var closeLink = new Element('a', {'class': 'dhtmlclose'}).setStyle('cursor', 'pointer').setContent(lang_Close).injectInside(div);
  }
  
  var inner = new Element('div', {'class': 'inner'}).setContent(content).injectInside(ctnr);
  
  // go back if we hit close
  if (inner.getElement('.popupBackOnClose'))
  {
    closeLink.removeClass('dhtmlclose');
    closeLink.addClass('js_back');
  }
  if (inner.getElement('.silentClose')) closeLink.removeClass('popupClose');
  
  if (popupConfig.servlet)
  {
      // give us control to apply styles depending on which popup we're shoing
      ctnr.addClass("DefaultPopup");
      ctnr.addClass(popupConfig.servlet);
      inner.addClass(popupConfig.servlet+"Inner");

      if (window.location.hash) {
        var id = window.location.hash;
        if (id.length > 1) id = id.substring(1);
        var t = $(id);
        if (t) ctnr.setStyle('top', t.getTop() * 1.20);
      }
      
      // a subset of the actions defined in DhtmlPopup.java
      // only actions that are triggered by a mouse click
      ctnr.getElements('.popupClose').each(function(item, index){
        item.addEvent('click', function(){ DHTMLPopupRequest('Close'); } );
      });
      
      inner.getElements('.popupConvert').each(function(item, index){
        item.addEvent('click', function(){ DHTMLPopupRequest('Convert'); } );
      });
      
      inner.getElements('.popupDecline').each(function(item, index){
        item.addEvent('click', function(){ DHTMLPopupRequest('Decline'); } );
      });

      var popupSubmitOnEnterFunction = function(e)  
      {
        var charCode = (e.charCode) ? e.charCode :
            ((e.which) ? e.which : e.keyCode)
        if(charCode == 13 || charCode == 10)
        {
          popupSubmitFunction(e);
        }
      }

      var popupSuppressEnterFunction = function(e)  
      {
        var charCode = (e.charCode) ? e.charCode :
            ((e.which) ? e.which : e.keyCode)
        if(charCode == 13 || charCode == 10)
        {
          new Event(e).preventDefault();
        }
      }

      inner.getElements('.popupSubmitOnEnter').each(function(item, index){
        item.addEvent('keydown', popupSubmitOnEnterFunction );
      });

      var popupSendForgotEmailFunction = function(e) 
      {
        $$('#POPUP_FORM #sendpass').setProperty("value", "true");
        popupSubmitFunction(e);
      }

      inner.getElements('.popupSendForgotEmail').each(function(item, index){
        item.addEvent('click', popupSendForgotEmailFunction );
      });

      // avoid duplicate submits
      var popupSubmitFunction = function(e) 
      {
        new Event(e).preventDefault();

        inner.getElements('.popupSubmit').each(function(item, index){
          item.removeEvent('click', popupSubmitFunction);
        });

        inner.getElements('.popupSendForgotEmail').each(function(item, index){
          item.removeEvent('click', popupSendForgotEmailFunction);
        });

        inner.getElements('.popupSubmitOnEnter').each(function(item, index){
          item.removeEvent('keydown', popupSubmitOnEnterFunction);
          item.addEvent('keydown', popupSuppressEnterFunction);
        });

        inner.getElements('.focusClear').each(function(item, index){
          item.setProperty('value', '');
        });

        DHTMLPopupRequest('Submit', DHTMLPopupResponse, null, inner.getElementById('POPUP_FORM')); 
      }

      inner.getElements('.popupSubmit').each(function(item, index){
        item.addEvent('click', popupSubmitFunction );
      });
  }

  // apply behavior
  window.behavior.apply(ctnr);

  // position relative to left corner of content and top of scroll positiion
  popupConfig.coords = ctnr.getCoordinates();
  if (popupConfig.options && popupConfig.options.center) {
    var cs = ctnr.getSize(); 
    ctnr.setStyles({
      left: (window.getWidth() - cs.size.x) / 2 + window.getScrollLeft(),
      top: (window.getHeight() - cs.size.y) / 2 + window.getScrollTop()
    });
  }
  else {
    ctnr.setStyle('left', $('PAGE').getLeft() + popupConfig.coords.left + 'px');
    ctnr.setStyle('top', $('PAGE').getTop() + popupConfig.coords.top + 'px');
  }
  
  // fix corners
  top.setStyle('width', popupConfig.coords.width + 'px');
  btm.setStyle('width', popupConfig.coords.width + 'px');
  var t = popupConfig.coords.width - tl.getCoordinates().width - tr.getCoordinates().width;
  var b = popupConfig.coords.width - bl.getCoordinates().width - br.getCoordinates().width;
  tm.setStyle('width', (t > 0 ? t : 0) + "px");
  bm.setStyle('width', (b > 0 ? b : 0) + "px");

  if (window.ie6)
  {
    var coords = ctnr.getCoordinates();
    var iframeEl = new Element('IFRAME', {'id': 'dhtmlPopupIframe'});
    iframeEl.setStyles({zIndex: '9997', borderWidth: '0', position: 'absolute',
      display: 'block', top: coords.top, left: coords.left, 
      width: coords.width, height: coords.height});
    iframeEl.injectInside($(document.body));
    
    // bug 25643
    if (lightbox)
    {
      $$('select').setStyle('visibility', 'hidden');
      ctnr.getElements("select").setStyle('visibility', 'visible');
    }
  }
  
  if (lightbox)
  {
    // if we're in a light box, follow the scroll position
    if (!popupConfig.options || !popupConfig.options.center)
      ctnr.setStyle('top', window.getScrollTop() + popupConfig.coords.top + 'px');
    window.addEvent('scroll', moveDHTMLPopupToScrollPosition.bindAsEventListener(ctnr));
    window.addEvent('resize', resizeToWindow.bindAsEventListener(lightbox));
  }

  if (popupConfig.options && popupConfig.options.callback) 
  {
    popupConfig.options.callback(ctnr);
  }
  
}

function moveDHTMLPopupToScrollPosition(event)
{
  var popupHeight = this.getSize().size.y;
  
  // popup is bigger than whole window so just don't move it
  if (popupHeight > window.getHeight()) {
    return;
  }
  // keep it centered
  else if (popupConfig.options && popupConfig.options.center) {
    var cs = this.getSize(); 
    this.setStyles({
      left: (window.getWidth() - cs.size.x) / 2 + window.getScrollLeft(),
      top: (window.getHeight() - cs.size.y) / 2 + window.getScrollTop()
    });
  }
  // top offset pushes it out of window
  else if (popupConfig.coords.top + popupHeight > window.getHeight()) {
    var freeSpace = window.getHeight() - popupHeight;
    this.setStyle('top', window.getScrollTop() + (freeSpace/2) + 'px');
  }
  // keep the offset to top defined in base.css
  else {
  	this.setStyle('top', window.getScrollTop() + popupConfig.coords.top + 'px');
  }
}

function resizeToWindow(event)
{
  var pageSize = Math.max( window.getHeight(), window.getScrollHeight() );
  this.setStyle('height', pageSize + 'px');
}

function showToggleBlock(toggleClass)
{
  // only hide all the toggle blocks besides toggleClass
  $$('.js_toggleBlocks .js_toggleBlock').each( function(el, i) {
    el.hide();
	if (el.hasClass(toggleClass))
	{
	  el.show();
	}
  });
}

linkMap['js_reopenDhtmlPopup']=function(elmt, e) {
    new Event(e).preventDefault();
    showDHTMLPopup(popupConfig.servlet, popupConfig.servletUrl, popupConfig.lightbox);
} 

linkMap['js_toggleBlockTrigger'] =function (elmt, e) { 
  var toggleClass = elmt.getProperty("class");
  toggleClass.replace(/toggleBlock[0-9]+/g, function(match){ toggleClass = match; });
  showToggleBlock(toggleClass);
};

rules['#SWAPBLOCK .js_toggleBlock']=function(elmt) {
  // the default toggleBlock
  if (elmt.hasClass("js_toggleBlockSelected"))
  {
    var toggleClass = elmt.getProperty("class");
    toggleClass.replace(/toggleBlock[0-9]+/g, function(match){ toggleClass = match; });
    showToggleBlock(toggleClass);
  }
}

function clearPopupForm()
{
  // clear password
  $$('#POPUP_FORM #pass').setProperty("value", "");
  
  // clear errors
  $$('#DHTMLPOPUP .error-message').empty();
}

// only used in DHTML pop-ups
linkMap['js_clearPopupForm'] =function (elmt, e) { 
  clearPopupForm();
};

function setPopupFormAction(val)
{
  $$('#POPUP_FORM #action').setProperty("value", val);
}

// only used in DHTML pop-ups
linkMap['js_popupFormAction1'] =function (elmt, e) { 
  setPopupFormAction("1");
};
linkMap['js_popupFormAction2'] =function (elmt, e) { 
  setPopupFormAction("2");
};

function callPopupSendPasswordEmail(elmt)
{
  alert("callPopupSendPasswordEmail");
  $$('#POPUP_FORM #sendpass').setProperty("value", "true");
  popupSubmitFunction(elmt);
}

// only used in DHTML pop-ups
ajaxRules['.js_popupForgot']=function(elmt) {
  elmt.addEvent("click", callPopupSendPasswordEmail);
}

// MOVE - only used in Help Center
rules['#HELP_CENTER dl.js_toggleset'] = function(elmt) {
  var initTab = 0;
  var ts = new ToggleSet(elmt.getElements('dt'), elmt.getElements('dd'));
  if (window.location.hash && (hash = window.location.hash.match(/c(\d+)/))) ts.display(parseInt(hash[1]));
}

// XXX - used for pool testing of amenity icons
// This should be removed in the not so distant future
// Greg Belote  19aug08

var amenityFiredHoverEvent = false;

function recordAmenityIconHover ()
{
    // send an AJAX request that will log the hover
    new Ajax("/ActionRecord?action=amenityIconHover").request();

    // note that we've recorded one hover for this page view
    amenityFiredHoverEvent = true;
}

//rules['#redesignAmenity .amenities img'] = function(icon) {
//    icon.addEvent('mouseenter', function(e) {
//        // if we haven't already recorded a hover for this page view...
//        if (amenityFiredHoverEvent == false)
//        {
//            // set a timer at 750ms to record the user hovering
//            icon.hoverTimeout = setTimeout ("recordAmenityIconHover()", 750);
//        }
//    });
//
//    icon.addEvent('mouseleave', function(e) {
//        // stop the timeout
//        clearTimeout (icon.hoverTimeout);
//        
//        // remove any references to it
//        icon.hoverTimeout = null;
//    });
//}

var propertyTypeClicked = false;

//rules['#PROPERTY_TYPE .flyout a'] = function(questionMark)
//{
//    questionMark.addEvent('click', function(e) {
//        if (propertyTypeClicked == false)
//        {
//            new Ajax("/ActionRecord?action=propertyTypeClicked").request();
//            propertyTypeClicked = true;
//        }
//    });
//}

var mtHelpHovered = false;
rules['#ACCOM_DETAIL div.translation li.flyoutB a, #SHOW_USER_REVIEW div.translation li.flyoutB a'] = function(questionMark)
{
	questionMark.addEvent('mouseenter', function(e) {
		if (mtHelpHovered == false)
		{
			new Ajax("/ActionRecord?action=MTQuestionmarkHover").request();
			mtHelpHovered = true;
		}
	});
}

rules['#HAC_FORM .js_hacRadio'] = function(elmt) {
  if(!elmt.checked)
  {
    elmt.addEvent("click", function(e) {
    	var aelmt = $('cat' + elmt.value + 'url');
    	if(aelmt)
    	{
          window.location = aelmt.href;
    	}
    });
  }
}

// inspiration
//rules['#popularity .js_togglepopularity'] = function(elmt) {
//  elmt.addEvent("click", function(e) {
//      sort('popularity');
//  });
//}
//rules['#alphabetical .js_togglealphabetical'] = function(elmt) {
//  elmt.addEvent("click", function(e) {
//      sort('alphabetical');
//  });
//}

ajaxRules['div.CHECKED_SITES'] = function(elmt) {
  if(!elmt.className.match(/cs_(\w\w)/)) return;
  var csType = elmt.className.match(/cs_(\w\w)/)[1];
  var totOpenedVen = 0;
  var totCheckedVen = 0;
  for( x = 0; x < vendors.length; x++ ){
    if(vendors[x].checkbox.checked)
    {
      if(csType == 'ps' && !vendors[x].additionalOffer)
      {
        totCheckedVen++;
      }
      else if(csType == 'ao' && vendors[x].additionalOffer)
      {
        totCheckedVen++;
      }
      
      if(vendors[x].bOpened)
      {
        if(csType == 'ps' && !vendors[x].additionalOffer)
        {
          totOpenedVen++;
        }
        else if(csType == 'ao' && vendors[x].additionalOffer)
        {
          totOpenedVen++;
        }
        
      }
    }
  }
  elmt.getElement('span.opnSites').innerHTML = totOpenedVen;
  elmt.getElement('span.totSites').innerHTML = totCheckedVen;
}

var js_popTestCR = function(cr_box, event, params) {
  if (!params)
    params = {};
  var evt = new Event(event || window.event);
  evt.preventDefault();
  cr_box.onclick = "";
  var accomId = cr_box.className.match(/id_(\d+)/)[1];
  var pos = $(cr_box).getPosition();
  cr_box.addClass('relPos');
  if (params.Action)
    cr_box.addClass('custom_area_' + params.Action);
  if (/pid(\d+)/.test(cr_box.className)) Cookie.set('NPID', RegExp.$1, {domain: cookieDomain, time:5});
  var cr_ajax_req = "/HotelCheckRates-d" + accomId;
  for (var att in params)
    cr_ajax_req += "&" + att + "=" + params[att];
  var lb  = new Lightbox(cr_box, {
    contentId: 'lbContentCR',
    top: pos.x,
    left: pos.y,
    centerOnScreen: false,
      autoAdjust: true,
      padLeft: 105,
      padTop: -55,
    arrow: true,
    evalScripts: true,
    source: cr_ajax_req
    });
  lb.activate(evt);
}

var js_hoverTestCR = function(cr_box, event, params) {
  if (!params)
    params = {};
  new Event(event || window.event).preventDefault();
  if (/pid(\d+)/.test(cr_box.className))
  {
    var crPid = RegExp.$1;
    Cookie.set('NPID', crPid, {domain: cookieDomain, time:5})
  }
  var btn = $(cr_box).getElement('img.btnPop');
  btn.addClass('relPos');
  var accomId = cr_box.className.match(/id_(\d+)/)[1];
  var cr_ajax_req = "/HotelCheckRates-d" + accomId + "?pw=true";
  for (var att in params)
    cr_ajax_req += "&" + att + "=" + params[att];
  var flyoutInst = new Flyout(btn, {
    offsets: {x:0, y:-55},
    flyoutClass: "crHover",
    arrowPosition: POS.RIGHT,
    bound: true,
    remoteContent: cr_ajax_req,
    runScripts: true,
    cacheAjax: false,
    disableGlobal: true,
    cancelBoundOnClick: true,
    crAutoAdjust: true
  }).show();
  cr_box.onmouseover = "";
	new Lightbox(btn, {
    contentId: 'lbContentCR',
    top: 0,
    left: 0,
    evalScripts: true,
    flyoutToClose: flyoutInst,
    centerOnScreen: false,
    autoAdjust: true,
    padLeft: 105,
    padTop: -55,
    arrow: true,
    source: cr_ajax_req
  });
}

linkMap['js_crPop'] = function(crBox, e) {
  if (crBox.removeEventListener) crBox.removeEventListener('click', doBehavior, false);
  else crBox.detachEvent('onclick', doBehavior);
  new Event(e).preventDefault();
  var relPosition = crBox.className.match(/pos_(\d+)_(\d+)/);
  
  var cArea = null;
  if(cArea = crBox.className.match(/custom_area_(\w+)/))
  {
    crBox.customArea = cArea[1]; 
  }
  
  crBox.addClass('relPos');
  var pLeft = null; var pTop = null;
  if(relPosition)
  {
    pLeft = relPosition[1].toInt();
    pTop = relPosition[2].toInt() * -1;
  }
  if (window.flyout) window.flyout.hide();
  new Lightbox(crBox, {
    contentId: 'lbContentCR',
    left: 0,
    top: 0,
    evalScripts: true,
    centerOnScreen: false,
    autoAdjust: true,
    padLeft: pLeft,
    padTop: pTop,
    arrow: true
  }).activate(e);
}

var bookPopEvent = false;
//rules['#BOOKPOP'] = function(box) {
//  box.addEvent('click', bookPopEventHelper);
//}

ajaxRules['#HotelDateSearch_CR ul.siteLst'] = function(elmt) {
  if(typeof vendors != "undefined")
  {
    vendors.each(function(vendor) {
      var bn_checked = "";
      if($(vendor.name).checked)
      {
        bn_checked = ' checked="checked"';
      }
      new Element('li').setHTML(
        '<input id="bn' + vendor.name + '" onchange="$(this.id.substring(2, this.id.length)).checked = this.checked" class="chk" name="' + vendor.name + '" type="checkbox"' + bn_checked + '/>' +
        '<label for="bn' + vendor.name + '">' + vendor.vendorName + '</label>'
      ).injectInside(elmt);
    }, elmt);
    window.lightbox.readjust();
  }  
}

/* CheckRates tip test */
ajaxRules['div.crlbTip'] = function(elmt) {
  if(typeof qcShowTip != 'undefined')
  {
	elmt.setStyle('display','block');
    elmt.setHTML(
	  '<img src="'+qcTipImage+'" /><span>Tip:</span> Travelers usually check <strong>3 or more sites</strong> to find the best price.'
    );
  }
}

var slots;
var bWinXPSP2 = false;
var bOneAtATime = false;
var bUpdating = false;
var lb_ie_enabled = true;

// 330 days in future
var dTooFar = new Date();
for(var i = 0; i < 330; i++)
{
  dTooFar.setMilliseconds(86400000);
}

if(navigator.appVersion.indexOf('SV1') != -1)
{
  bWinXPSP2 = true;
  bOneAtATime = true;
}

function Slot(lx, ly, lw, lh){
  this.x = lx;
  this.y = ly;
  this.w = lw;
  this.h = lh;
  this.occupied = null;
}

function makeSlots(){
  var nW = 525;
  var nH = 460;
  var nXI = 24;
  var nYI = 24;
  //move all the pop windows away from the dhtml popup
  var nX = (typeof lb_ie_enabled != "undefined") ? 500 : 205;
  var nY = (window.screenTop || window.screenY);

  if(screen.width > 1024){
    nW = 800;
    nH = 600;
    nXI = 80;
    nYI = 40;
  } else if(screen.width > 800){
    nW = 620;
    nH = 500;
    nXI = 60;
    nYI = 30;
  }
  slots = [];
  for (var i=0; i<20; i++){
    slots[i] = new Slot(nX,nY,nW,nH);
    nX = nX + nXI;
    nY = nY + nYI;
  }
}

function PopunderSlot(x, y, w, h, tx, ty, tw, th){
  this.x = x;
  this.y = y;
  this.w = w;
  this.h = h;
  this.tx = tx;
  this.ty = ty;
  this.tw = tw;
  this.th = th;
  this.occupied = null;
}

var popunderSlotCount = 2;
function makePopunderSlots(){
  var w = 1;
  var h = 1;
  var nW = 620;
  var nH = 500;
  var nXI = 24;
  var nYI = 24;
  if (window.ie7) {w = 250; h = 100;}
  if (window.webkit) { w = 85; h = 100;}
  var nX = (window.screenLeft || window.screenX);
  var nY = (window.screenTop || window.screenY);

  if (typeof(nX) == "undefined") { // full screen
    nX = 0;
    nY = 0;
    var x = nX + window.screen.availWidth - w; // bottom-right corner of window
    var y = nY + window.screen.availHeight - h;
  }
  else{
    var x = nX + window.getWidth() - w; // bottom-right corner of window
    var y = nY + window.getHeight() - h;
  }

  if(window.ie7)
  {
    y = y - 95;
    x = x + 13;
  }
  else if(window.webkit)
  { 
    y = y - 16;
  }
  else
  {
    x = 5000;
    y = 5000;
  }
  
  popunderSlots = [];
  for (var i=0; i<popunderSlotCount; i++){
    popunderSlots[i] = new PopunderSlot(nX, nY, nW, nH, x, y, w, h);
    nX = nX + nXI;
    nY = nY + nYI;
  }
}

function getOpenSlot(n, slotGroup){
  if(n<=0){
    n=1;
  }
  for (var i=n-1; i>=0; i-=1){
    if (slotGroup[i].occupied == null){
      return slotGroup[i];
    } else if (slotGroup[i].occupied.closed){
      slotGroup[i].occupied = null;
      return slotGroup[i];
    }
  }
  for (var i=n; i<slotGroup.length; i++){
    if (slotGroup[i].occupied == null){
      return slotGroup[i];
    } else if (slotGroup[i].occupied.closed){
      slotGroup[i].occupied = null;
      return slotGroup[i];
    }
  }
  return null;
}

function focusSlots(){
  for (var i=0; i<slots.length; i++){
    if (slots[i].occupied != null && !slots[i].occupied.closed)
    {
      try {
        slots[i].occupied.focus();
      } catch(e) { }
    }
  }
}

var unusedPopunderCount = 0;

rules['#HotelDateSearch #checkIn'] = rules['#HotelDateSearch #checkOut'] = function(elmt) {
  /* providerWindow check...*/
  if(elmt.className.match(/popEnabled/) && (window.ie7 || window.ie6) && $('CHECK_RATE') && !$('CHECK_RATE').hasClass('providerWin'))
  {
    elmt.addEvent('click', function(e) { 
      popunderLaunch(test_uri);
    });
  }
  
  if($defined(window.inFldDefault) && $('checkIn'))
  {
    $('checkIn').setProperty('value', window.inFldDefault);
  }
  if($defined(window.otFldDefault) && $('checkOut'))
  {
    $('checkOut').setProperty('value', window.otFldDefault);
  }
}

var popunderSlots;
function popunderLaunch(popunder_uri, windowName)
{
  popunderslot = getOpenSlot(0, popunderSlots); 
  
  //vendor check - only call popunder if there is a vendor to match it, we get a free pop with the click, 
  //so we only need to prefill up to one less than the vendor count
  
  var checkedVendors = 0;
  for( x = 0; x < vendors.length; x++ ){   
      if(vendors[x].checkbox.checked)
      {
        checkedVendors++;
      }
  }
  var usedPopunders = 0;
  for(var j = 0; j < popunderSlots.length; j++)
  {
    if(popunderSlots[j].occupied)
    {
      usedPopunders++;
    }
  }
  if( usedPopunders > vendors.length - 2 || usedPopunders > checkedVendors - 2)
  {
    return;
  }
  //vendor check complete
  
  if(popunderslot)
  {
    if(!windowName)
    {
      windowName = "UPC_" + unusedPopunderCount;
    }
    unusedPopunderCount++;
    cpu_win = window.open("", windowName, "toolbar=1,location=1,directories=1,status=1,menubar=1,resizable=1,copyhistory=1,scrollbars=1,width="+popunderslot.tw+",height="+popunderslot.th+",left="+popunderslot.tx+",top="+popunderslot.ty);
    if(cpu_win && isTAWindow(cpu_win) )
    {
      cpu_win.blur();
      window.focus();
      cpu_win.location = popunder_uri;
      popunderslot.occupied = cpu_win;
      cpu_win.opener = self;
      cpu_win.moveTo(popunderslot.x, popunderslot.y);
      cpu_win.resizeTo(popunderslot.w,popunderslot.h);
    }
    else if( cpu_win && unusedPopunderCount < 20) //window already used for commerce
    {
      popunderLaunch(popunder_uri);
    }
  }
}

var isTAWindow = function(win_hook){
  var isTA = true;
  try {
    var tempLoc = win_hook.location;
    // for some reason IE runs the next line even if the last one throws a SecurityException
    window.status = ""; // so do something pointless - DO NOT REMOVE THIS LINE!

    // Handle case when IE7 returns '' for window.opener.location rather than a security exception
    // bug 28404   gbelote
    if (tempLoc == null || tempLoc == "")
    {
        isTA = false;
    }
  }
  catch (e) {
    isTA = false;
  }
  return isTA;
}

var popunderReminder = function(pop_hook){
  if(typeof popunderSlots == "undefined")
  {
    popunderReminder.delay(500, pop_hook);
  }
  else
  {
    for(var j = 0; j < popunderSlots.length; j++)
    {
      if(!popunderSlots[j].occupied)
      {
        popunderSlots[j].occupied = pop_hook;
        break;
      }
    }
  }
}

var vendors = [];
function addVendor(vendor){
  vendors[vendors.length] = vendor;
}

function Vendor(lName, lCheckbox, lUrl, lVendorName, lAddOffer){
  this.name = lName;
  this.checkbox = lCheckbox;
  this.url = lUrl;
  this.window = null;
  this.lastDates = "";
  this.slot = null;
  this.bOpened = false;
  this.vendorName = lVendorName;
  this.additionalOffer = lAddOffer;
}

function popwindows(trigger)
{
  var numChecked = 0;
  var numToOpen = 0;
  var numOpened = 0;
  var numOpen = 0;
  var numCheckedOrOpen = 0;

  
  for (var i=0; i<vendors.length; i++)
  {
    if (vendors[i].checkbox.checked)
    {
      numChecked++;
      if (vendors[i].window == null)
      {
        numToOpen++;
        numCheckedOrOpen++;
      } 
      else if (vendors[i].window.closed)
      {
        vendors[i].window = null;
        numToOpen++;
        numCheckedOrOpen++;
      } 
      else 
      {
        numOpen++;
        numCheckedOrOpen++;
      }
    } 
    else if (vendors[i].window != null && !vendors[i].window.closed)
    {
      numCheckedOrOpen++;
    }
  }
  
  if (numChecked == 0)
  {
    alert(js_0001); // "Please select at least one vendor from the list."
    return false;
  }
  
  // User Supplied Dates
  var sInMonthYear = $('qcInMonth').value.split(/\//);
  var dCheckin = new Date( sInMonthYear[1], sInMonthYear[0]-1 , $('qcInDay').value );
  var sOutMonthYear = $('qcOutMonth').value.split(/\//);
  var dCheckout = new Date(sOutMonthYear[1], sOutMonthYear[0]-1, $('qcOutDay').value);

  // Today; Force to midnight
  var dToday = new Date();
  dToday.setHours(0,0,0,0);

  // Calendar protects against this but keep it anyway
  if (dCheckin < dToday || dCheckout < dToday) {
    alert(js_0002); // "Please choose dates in the future."
    return false;
  }

  if (dCheckin >= dCheckout) {
    alert(js_0003); // "Please choose a check-out date that is at least one day later than your check-in date."
    return false;
  }

  if (dCheckin > dTooFar || dCheckout > dTooFar) {
    alert(js_0004); // "Please choose dates that are less than 330 days away."
    return false;
  }

  $("msgbox").setContent(js_0005).show(); // "Searching for deals ... this may take a few moments"

  //set globally here
  sUserData = (
          "inMonth=" + escape(sInMonthYear[0] + " " + sInMonthYear[1]) +
          "&inDay=" + escape($('qcInDay').value) +
          "&outMonth=" + escape(sOutMonthYear[0] + " " + sOutMonthYear[1]) +
          "&outDay=" + escape($('qcOutDay').value) +
          "&adults=" + escape($('qcAdults').selectedIndex+1)
        );
  
  var pidElmt = $('hacPid');
  if(pidElmt)
  {
    var pid = pidElmt.value;
    sUserData += "&pid=" + pid;
  }

  if($(trigger) && $(trigger).hasClass('providerWin') && (window.ie6 || window.ie7))
  {
  	ta.commerce.commerceHelper.openProviderWindow(trigger);
    if(js_0014)
    {
      $("errbox").hide().empty();
      $("msgbox").hide().empty();
    }
    return false;
  }
  
  if(lb_ie_enabled)
  {
    popAll(sUserData);
    setUpdateText();
  }
  else{
    if(bOneAtATime)
    {
      var nIndex = getNextWindowIndex(sUserData);
      if(nIndex > -1)
      {
        popOne(nIndex, sUserData);
      }
      else if(bUpdating)
      {
        alert(js_0006); // "Your selections have not changed."
      }

      // Are we done?
      nIndex = getNextWindowIndex(sUserData);
      if(nIndex == -1)
      {
        setUpdateText();
      }
      else
      {
        setPopAnotherText();
      }
    }
    else
    {
      if(popAll(sUserData))
      {
        setUpdateText();
      }
      else
      {
        setPopAnotherText();
      }
    }
  }

  focusSlots();

  return true;
}

function getNextWindowIndex(sUserDataVar)
{
  for (var i=0; i<vendors.length; i++)
  {
    if(vendors[i].checkbox.checked && !vendors[i].bOpened)
    {
      return i;
    }
  }

  for (var i=0; i<vendors.length; i++)
  {
    if(vendors[i].checkbox.checked
       && vendors[i].window != null
       && !vendors[i].window.closed
       && sUserDataVar != vendors[i].lastDates)
    {
      return i;
    }
  }

  for (var i=0; i<vendors.length; i++)
  {
    if(vendors[i].checkbox.checked
       && vendors[i].lastDates != sUserDataVar)
      {
        return i;
      }
  }

  return -1;
}

function popOne(nIndex, sUserDataVar)
{
  try {
    var bReturn = false;
    var bHasWindow = (vendors[nIndex].window != null && !vendors[nIndex].window.closed);
    var sFinalUrl = vendors[nIndex].url + '&' + sUserDataVar;

    if (window.qcCustomArea) {
      sFinalUrl = sFinalUrl.replace(/&area\=\w+/, '&area=' + window.qcCustomArea);
    }
    
    var slot;
    if (bHasWindow)
    {
      slot = vendors[nIndex].slot;
    }
    else
    {
      slot = getOpenSlot(0, slots);
    }
    
    var resusePopunder = null;
    for(var j = 0; j < popunderSlots.length; j++)
    {
      if(popunderSlots[j].occupied)
      {
        resusePopunder = popunderSlots[j].occupied;
        popunderSlots[j].occupied = null;  
        break;
      }
    }
    
    var popWidth = slot.w;
    if(vendors[nIndex].vendorName == "hotels.com")
    {
      popWidth = 975;
    }
    
    var winName = vendors[nIndex].name;
    if(resusePopunder)
    {
      winName = resusePopunder.name;
    }
    
    var sProps = 'toolbar=yes,location=yes,directories=yes,status=yes,menubar=yes,scrollbars=yes,copyhistory=yes,resizable=yes,alwaysraised=true';
    var sMyProps = sProps + ',screenX=' + slot.x + ',screenY=' + slot.y + ',left=' + slot.x + ',top=' + slot.y + ',height=' + slot.h + ',width=' + popWidth;
    vendors[nIndex].window = window.open(sFinalUrl, winName, sMyProps);
    if(resusePopunder)
    {
      resusePopunder.popunderRepos(slot);
    }

    if(typeof vendors[nIndex].window != "undefined" && vendors[nIndex].window != null)
    {
      slot.occupied = vendors[nIndex].window;
      vendors[nIndex].slot = slot;
      vendors[nIndex].window.focus();
      vendors[nIndex].bOpened = true;
      vendors[nIndex].lastDates = sUserDataVar;
      bReturn = true;
    }
  } catch(e) { }

  return bReturn;
}

function popAll(sUserDataVar)
{
  cr_checkDates();
  for (var i=0; i<vendors.length; i++)
  {
    if (vendors[i].checkbox.checked)
    {
      if (sUserDataVar != vendors[i].lastDates || vendors[i].bOpened == false
          || vendors[i].window == null || vendors[i].window.closed)
      {
        if(!popOne(i, sUserDataVar))
        {
          bOneAtATime = true;
          if(lb_ie_enabled)
          {
            popCheckRatesIE();
          }
          return false;
        }
      }
    }
  }
  
  return true;
}

function setUpdateText()
{
  // TODO: not a button anymore, an image
  //document.HotelDateSearch.submitbtn.value=js_0011; // "Update"
  $("errbox").hide().empty();
  $("msgbox").hide().empty();
  bUpdating = true
}

function setPopAnotherText()
{
  // TODO: not a button anymore
  //document.HotelDateSearch.submitbtn.value=js_0012; //"Show next offer";
  
  if(bWinXPSP2) {
    $("msgbox").setContent(js_0013).show(); // "Please click the \"Check Rates!\" button above to open each window."
    $("errbox").setContent(qcErrorImage).show();
  }
  else {
    $("msgbox").setContent(js_0010).show(); // "Please click again to open each window or adjust browser settings to disable popup blockers."
    $("errbox").setContent(qcErrorImage).show();
  }
}

function closewindows()
{
  for (var i=0; i<vendors.length; i++)
  {
    if (vendors[i].window != null && !vendors[i].window.closed)
    {
      try {
        vendors[i].window.close();
      } catch(e) { }
    }
    vendors[i].window = null;
  }
}

function closeMe(sUrl, bFromPop)
{
  closewindows();
  try 
  {
    if(self.opener != null && bFromPop != 'true')
    {
      if(self.opener.closed == true){
        w = window.open(sUrl, 'TripAdvisor');
        w.focus();
      }
      else 
      {
        if(self.opener.location.href != sUrl)
        {
          self.opener.location.href = sUrl;
        }
        self.opener.focus();
      }
    } 
    else 
    {
      w = window.open(sUrl, 'TripAdvisor');
      w.focus();
    }
  } catch(e) { }

  try {
    self.close();
  } catch(e) { }
}

function quickCheckInit() 
{ 
  makeSlots();
  if(typeof addVendors != "undefined")
  {
    addVendors();
  }  
}

// ========================================================================= //
// ================ Book Now Lightbox Functions ============================ //
// ========================================================================= //

function bn_displayVendors()
{
  var crLBform = $$('#lbContentCR form')[0];
  var valid = validateDates.attempt([], crLBform);
  if (!valid) return;
  else
  {
    if(crLBform && crLBform.getElement('span.error_msg') != null)
    {
      crLBform.getElement('span.error_msg').hide();
    }
  }
  if(window.lightbox && window.lightbox.trigger.className && window.lightbox.trigger.className.match(/custom_area_(\w+)/))
  {
    var customArea = window.lightbox.trigger.className.match(/custom_area_(\w+)/);
    if(customArea)
    {
      window.qcCustomArea = customArea[1]; 
    }
  }
  
  try {
    bn_popwindows();
  } catch(e) { }
  return false;
}

function bn_popwindows()
{
  var lb = $('lbContentCR');
  var form = lb.getElement('form');
  var numChecked = 0;
  var numToOpen = 0;
  var numOpened = 0;
  var numOpen = 0;
  var numCheckedOrOpen = 0;
  for (var i=0; i<vendors.length; i++)
  {
    if (form.getElement('#bn'+vendors[i].name).checked)
    {
      numChecked++;
      if (vendors[i].window == null)
      {
        numToOpen++;
        numCheckedOrOpen++;
      } 
      else if (vendors[i].window.closed)
      {
        vendors[i].window = null;
        numToOpen++;
        numCheckedOrOpen++;
      } 
      else 
      {
        numOpen++;
        numCheckedOrOpen++;
      }
    } 
    else if (vendors[i].window != null && !vendors[i].window.closed)
    {
      numCheckedOrOpen++;
    }
  }
  
  if (numChecked == 0)
  {
    alert(js_0001); // "Please select at least one vendor from the list."
    return false;
  }

  // User Supplied Dates
  var sInMonthYear = form.getElement('.chk-in input.month').getValue().split(/\//);
  var dCheckin = new Date(sInMonthYear[1], sInMonthYear[0]-1 , form.getElement('.chk-in input.day').getValue() );
  var sOutMonthYear = form.getElement('.chk-ot input.month').getValue().split(/\//);
  var dCheckout = new Date(sOutMonthYear[1], sOutMonthYear[0]-1, form.getElement('.chk-ot input.day').getValue());

  // Today; Force to midnight
  var dToday = new Date();
  dToday.setHours(0,0,0,0);

  // Calendar protects against this but keep it anyway
  if (dCheckin < dToday || dCheckout < dToday) {
    alert(js_0002); // "Please choose dates in the future."
    return false;
  }

  if (dCheckin >= dCheckout) {
    alert(js_0003); // "Please choose a check-out date that is at least one day later than your check-in date."
    return false;
  }

  if (dCheckin > dTooFar || dCheckout > dTooFar) {
    alert(js_0004); // "Please choose dates that are less than 330 days away."
    return false;
  }

  lb.getElement("div.remind").setText(js_0005); // "Searching for deals ... this may take a few moments"

  //set globally here
  sUserData = (
          "inMonth=" + escape(sInMonthYear[0] + " " + sInMonthYear[1]) +
          "&inDay=" + escape(form.getElement('.chk-in input.day').getValue()) +
          "&outMonth=" + escape(sOutMonthYear[0] + " " + sOutMonthYear[1]) +
          "&outDay=" + escape(form.getElement('.chk-ot input.day').getValue()) +
          "&adults=" + escape(form.getElement('.adults select').getValue())
        );

  if(lb_ie_enabled)
  {
    bn_popAll(sUserData);
    setUpdateText();
  }
  else{
    if(bOneAtATime)
    {
      var nIndex = bn_getNextWindowIndex(sUserData);
      if(nIndex > -1)
      {
        popOne(nIndex, sUserData);
      }
      else if(bUpdating)
      {
        alert(js_0006); // "Your selections have not changed."
      }

      // Are we done?
      nIndex = bn_getNextWindowIndex(sUserData);
      if(nIndex == -1)
      {
        bn_setUpdateText();
      }
      else
      {
        bn_setPopAnotherText();
      }
    }
    else
    {
      if(bn_popAll(sUserData))
      {
        bn_setUpdateText();
      }
      else
      {
        bn_setPopAnotherText();
      }
    }
  }

  focusSlots();

  return true;
}

function bn_getNextWindowIndex(sUserDataVar)
{
  var form = $$('#lbContentCR form')[0];
  for (var i=0; i<vendors.length; i++)
  {
    if(form.getElement('bn'+vendors[i].name).checked && !vendors[i].bOpened)
    {
      return i;
    }
  }

  for (var i=0; i<vendors.length; i++)
  {
    if(form.getElement('#bn'+vendors[i].name).checked
       && vendors[i].window != null
       && !vendors[i].window.closed
       && sUserDataVar != vendors[i].lastDates)
    {
      return i;
    }
  }

  for (var i=0; i<vendors.length; i++)
  {
    if(form.getElement('#bn'+vendors[i].name).checked
       && vendors[i].lastDates != sUserDataVar)
      {
        return i;
      }
  }

  return -1;
}

function bn_popAll(sUserDataVar)
{
  var form = $$('#lbContentCR form')[0];
  for (var i=0; i<vendors.length; i++)
  {
    if (form.getElement('#bn'+vendors[i].name).checked)
    {
      if (sUserDataVar != vendors[i].lastDates || vendors[i].bOpened == false
          || vendors[i].window == null || vendors[i].window.closed)
      {
        if(!popOne(i, sUserDataVar))
        {
          bOneAtATime = true;
          if(lb_ie_enabled)
          {
            popCheckRatesIE();
          }
          return false;
        }
      }
    }
  }
  
  return true;
}

function bn_setUpdateText()
{
  // TODO: not a button anymore, an image
  //document.HotelDateSearch.submitbtn.value=js_0011; // "Update"
  $$("#lbContentCR .js_error")[0].innerHTML = "";
  $$("#lbContentCR div.remind")[0].innerHTML = "";
  bUpdating = true
}

function bn_setPopAnotherText()
{
  // TODO: not a button anymore
  //document.HotelDateSearch.submitbtn.value=js_0012; //"Show next offer";
  
  if(bWinXPSP2) {
    $$("#lbContentCR div.remind")[0].innerHTML = js_0013; // "Please click the \"Check Rates!\" button above to open each window."
    $$("#lbContentCR .js_error")[0].innerHTML = qcErrorImage;
  }
  else {
    $$("#lbContentCR div.remind")[0].innerHTML = js_0010; // "Please click again to open each window or adjust browser settings to disable popup blockers."
    $$("#lbContentCR .js_error")[0].innerHTML = qcErrorImage;
  }
}


// Keeps 'Compare Prices' as button when applicable on 'Hotel_Review' & 'ShowUserReviews'
ajaxRules['#BOOK_NOW'] = function(elmt) {
  if (window.lightbox.trigger && (!window.lightbox.trigger.id || window.lightbox.trigger.id != 'BOOKPOP') ) {
    elmt.src = cdnHost+'/img2/buttons/comparePrices-v1.gif';
    elmt.alt = js_0015;
    $(elmt.parentNode).removeClass('bookNow');
  }
}

  
// ========================================================================= //
// ================ / Book Now Lightbox Functions ========================== //
// ========================================================================= //

rules['#BOOK_NOW'] = function(elmt) {
  elmt.addEvent('click', bn_displayVendors.bindAsEventListener(elmt));
}

window.addEvent(TAReadyEvent, quickCheckInit);

function popCheckRatesIE()
{
  if(window.lightbox)
  {
    window.lightbox.deactivate();
  }
  new Ajax( 'http://' + document.domain + '/vpages/quickcheck_lb.html', {
    onComplete: function(res){
      if ($defined(window.qcCustomArea) && window.lightbox) window.lightbox.deactivate();
      if(typeof window.crFlyout != 'undefined' && $('FLYOUT')) 
      {
        $('FLYOUT').remove(); //remove checkrates hover flyout
      }
 	  var resPrep = new StringBuffer();
	  resPrep.append(res);
	  showInLightbox(resPrep.toString(), 'lbContent_org', 0, 0);
	  
    },
   	onFailure: function(e) { }
  }).request();
}

var cr_checkin = "";
var cr_checkout = "";

var cr_checkDates = function() {
  if( $('checkIn') && $('checkOut') )
  {
    if( cr_checkin != $('checkIn').value || cr_checkout != $('checkOut').value && vendors)
    {
      for( x = 0; x < vendors.length; x++ ){
        vendors[x].bOpened = false;
      }
    }
    cr_checkin = $('checkIn').value;
    cr_checkout = $('checkOut').value;
  }
}

ajaxRules['#QUICK_CHECK_LB'] = function(elmt) {
  
  if(pageServlet == 'Hotels')
  {
    $(elmt).getElement('div.legend').show();
    if(typeof selectedHotelName != "undefined")
    {
      $(elmt).getElement('div.accomName').innerHTML = selectedHotelName;
    }
  }
  else
  {
    $('QUICK_CHECK_LB').getElement('h2.popBlock').show();
  }
  
  var vendorsShown = 0;
  var normOffers = 0;
  var addOffers = 0;
  for( x = 0; x < vendors.length; x++ ){
    if(vendors[x].checkbox.checked)
    {
      vendorsShown++;
      var lnkUrl = vendors[x].url;
      if (window.qcCustomArea) {
        lnkUrl = lnkUrl.replace(/&area\=\w+/, '&area=' + window.qcCustomArea);
      }
      
      var listSectionId = 'QUICK_CHECK_LB_PARTNERS';
      if(vendors[x].additionalOffer)
      {
        listSectionId = 'QUICK_CHECK_LB_ADD_OFFERS';
        addOffers++;
      }
      else
      {
        normOffers++;
      }
      var elemAnchor = new Element('a', {'id' : 'qc_'+x , 'href' : lnkUrl})
        .injectInside(new Element('div', {'class': 'qc_lb_name'})
          .injectInside($(listSectionId)) ).setContent(vendors[x].vendorName);
        
      var imgUrl = vendors[x].bOpened ? cr_loc_vend_ch : cr_loc_vend;
      elemAnchor.setStyle('background', 'url(' + imgUrl + ') no-repeat');
      
      elemAnchor.addEvent('click', function(e){
        
        var clickedVenderName = this.innerHTML;
        
        //update opened status of the popped vendor
        var iPopVendor = -1;
        var unopenedVendors = false;
        
        for( x = 0; x < vendors.length; x++ ){
          
          if(vendors[x].vendorName == clickedVenderName)
          {
            if(!vendors[x].bOpened)
	        {
	          var targ = new Event(e).target;
	          if(targ)
	          {
	            $(targ).setStyle('background', 'url(' + cr_loc_vend_ch + ') no-repeat');
	          }
	          iPopVendor = x;
	          var offerSection = vendors[x].additionalOffer ? 'div.cs_ao span.opnSites' : 'div.cs_ps span.opnSites';
	          var openSitesElem = $('QUICK_CHECK_LB').getElement(offerSection);
	          var openSites = parseInt(openSitesElem.innerHTML);
		      openSitesElem.innerHTML = openSites+1;
		      vendors[x].bOpened = true;
		    }
            popOne(x, sUserData);
          }
          
          if(vendors[x].checkbox.checked && !vendors[x].bOpened)
		  {
		    unopenedVendors = true;
		  }
		  
        }
        
	    if(!unopenedVendors)
        {
	      //if all vendors have popped, reset them and close the lb
	      for( x = 0; x < vendors.length; x++ ){
            vendors[x].bOpened = false;
	      }
	      //clear stored user data
	      sUserData = null;
	      window.lightbox.deactivate();
	    }

	    focusSlots();
	    
	    return false;
	  });
    }
  }
  
  //CheckRates Tip Test IE DHTML
  if(typeof qcShowTip != 'undefined')
  {
	  $('QUICK_CHECK_HR').setStyle('display','none');
	  $('QUICK_CHECK_TIP').setStyle('display','block');
	  $('QUICK_CHECK_TIP').setHTML(
	    '<div><span>Tip:</span> Travelers usually check <strong>3 or more sites</strong> to find the best price.</div><img src="'+qcTipImage+'" />'
	  );
  }

  if(normOffers == 0)
  {
    $('QUICK_CHECK_LB_PARTNERS').addClass('qcl_hidden');
    $$('#QUICK_CHECK_LB .cs_ps')[0].addClass('qcl_hidden');
  }

  if(addOffers == 0)
  {
    $('QUICK_CHECK_LB_ADD_OFFERS').addClass('qcl_hidden');
    $$('#QUICK_CHECK_LB .cs_ao')[0].addClass('qcl_hidden');
  }
};

/*CheckRates IE DHTML LB - Flights cross-sell test*/
ajaxRules['#QUICK_CHECK_FLIGHTS'] = function(elmt) {
  if(typeof qcShowFlight != 'undefined')
  {
	elmt.setStyle('display','block');
    elmt.setHTML(
      '<strong>Also interested in a flight to '+flightLocation+'?</strong> Shop multiple web sites with just one click.<div class="crFlights"><a id="FIND_FLIGHTS" href="'+flightsLink+'"><img src="'+flightBtn+'"/></a><img src="'+flightIcon+'"/></div>'
    );
    $('FIND_FLIGHTS').addEvent('click', function(e) {
      new Event(e).preventDefault();
      var sProps = 'toolbar=yes,location=yes,directories=yes,status=yes,menubar=yes,scrollbars=yes,copyhistory=yes,resizable=yes,alwaysraised=true,height=768,width=1024';
      //var sMyProps = sProps + ',screenX=' + slot.x + ',screenY=' + slot.y + ',left=' + slot.x + ',top=' + slot.y + ',height=' + slot.h + ',width=' + popWidth;
      window.open(flightsLink,'Flights',sProps);
    });
  }
}

ajaxRules['#FLAGS_FLY'] = function(elmt) {
  elmt.getElements('a').each(function(e) {
      var footerFlag = $(e.id.replace(/_fly/, ""));
      if (footerFlag) {
        e.href = footerFlag.href;
      }
    });
}

//var deferFM = function(e) {
//  new Asset.javascript(mapsJs);
//  new Event(e).stop();
//}

//rules['#FLOATMAP'] = function(elmt) {
//  mapDivId = elmt.getElement('.js_map').id;
//  fmThumb = elmt.getElement('.js_floatMap');
//  fmThumb.myDeferFn = deferFM;
//  fmThumb.addtl = new Array();
//  fmThumb.addtl.push(elmt.getElement('div.all a').addEvent('click', fmThumb.myDeferFn));
//  var ln = $('LEFTNAV').getElement('a.k_maps');
//  if (ln)
//  {
//     fmThumb.addtl.push(ln.addEvent('click',fmThumb.myDeferFn));
//  }
//  fmThumb.addEvent('click', fmThumb.myDeferFn);
//}

//rules['#CNFLOATMAP'] = function(elmt) {
//
//    foo = $('FLOATMAP').getElement('.js_floatMap');
//    foo.addtl.push(elmt.getElement('a').addEvent('click', foo.myDeferFn));
//}

//rules['#SEARCH_LANG_SELECTOR input.searchLangSelect'] = function(elmt)
//{
//    elmt.addEvent("click", function(e)
//    {
//        if (this.form.elements['q'].value.length > 0)
//        {
//            this.form.submit();
//        }
//    });
//}

rules['#PHPROMO'] = function(elmt)
{
      // Make AJAX call to get content.
      new Ajax('/' + elmt.getText(), {
        onComplete: function(txt, xml) { 
            elmt.empty();
            elmt.innerHTML = txt;
            window.behavior.apply(elmt);
            elmt.style.display = 'block';
          } 
        }).request();
}

rules['#PHPROMOX'] = function(elmt)
{
      var url = elmt.getText();
      if (url)
      {
        url = '/' + url;
        elmt.empty();
        replaceContent(null, elmt, url);
        elmt.style.display = '';
      }
}

// only needed if savesEnable
var showLastSavesRD = function()
{
  var node = $('LAST_SAVES_PLACEHOLDER');
  if (typeof savesIncluded != 'undefined') {
    if (!node) return renderLastSaves(SAVES_RECENT_SAVES);
    else {
      node.innerHTML = renderLastSaves(SAVES_RECENT_SAVES);
      flyout.positionCorners();
    }
  }
  else if (!node) {
    new Asset.javascript(savesJS);
    showLastSavesRD.delay(125);
    return new Element('div', {id: 'LAST_SAVES_PLACEHOLDER'});;
  }
}

var showSavesWidget = function(anchor, entityType, entityId, options, xOff, yOff, fromLander) {
  if (typeof savesIncluded != 'undefined') {
    showSavesWidget2(anchor, entityType, entityId, options, xOff, yOff, fromLander);
  }
  else {
    new Asset.javascript(savesJS);
    showSavesWidget.delay(125, null, [anchor, entityType, entityId, options, xOff, yOff, fromLander]);
  }
}

var savesInlineLoginOnClickHandler = function(loggedInFn, loginFn, clickedElement) {
  if (typeof savesIncluded != 'undefined') {
    savesInlineLoginOnClickHandler2(loggedInFn, loginFn, clickedElement);
  }  
  else {
    new Asset.javascript(savesJS);
    savesInlineLoginOnClickHandler.delay(125, null, [loggedInFn, loginFn, clickedElement]);
  }
}

var doSavesPostLoginPopup = function() {
  if (typeof savesIncluded != 'undefined') {
    handleSavesPostLoginPopup();
  }  
  else {
    new Asset.javascript(savesJS);
    doSavesPostLoginPopup.delay(125);
  }
}

linkMap['js_trackDirPop'] = function(elmt, e) {
  if (actionToRecord = elmt.className.match(/ar_(\w+)/)) {
    actionToRecord = actionToRecord[1];
    new Ajax("/ActionRecord?action=" + actionToRecord).request();
  }
}

function expandIframe(id,w,h){
  if(document.getElementById(id)){
    document.getElementById(id).width=w;
    document.getElementById(id).height=h;
  }
}

function collapseAd(id)
{
  var frameE = $(id);
  if (frameE == null) return;
  var e = frameE.getParent('.adServer');
  if (e == null) return;
  e.addClass('taEmpty');
}

// might not need this
function expandAd(id, h)
{
  var frameE = $(id);
  if (frameE == null) return;
  var e = frameE.getParent('.ad');
  if (e == null) return;
  e.setStyle('height', h + 'px');
}

function injectAds()
{
  var ads = $$(".adServer .details");
  if (ads.length == 0) return;
  var url = "adp/adp.html";
  if (adpHtml) {
    url = adpHtml;
  }
  var domainParam = window.documentDomainChanged ? 'dd+' : '';
  for(var i=0; i<ads.length; i++)
  {
    var el = document.createElement("iframe");
    var id = ads[i].id + '_iframe';
    el.setAttribute('id', id);
    el.setAttribute('name', id);
    el.setAttribute('height', 0); 
    el.setAttribute('width', 0) ; 
    el.setAttribute('scrolling', 'no');
    el.setAttribute('border', '0');
    el.setAttribute('marginheight', '0');
    el.setAttribute('marginwidth', '0');
    el.setAttribute('frameBorder', '0');
    el.setAttribute('src', 'http://' + document.location.host + "/" + url + "#" + domainParam + eval(ads[i].id));
    ads[i].getParent().appendChild(el);
  }
}

window.addEvent('load', function() {
    injectAds.delay(10);  // Be sure all else is done before loading ads.
} );

/*
 * Replace the contents of an element via XHR
 */
var replaceContent = function(/* Event */ event,
                              /* HTMLElement */ element,
                              /* String */ href)
{
    //  local copies for our callbacks
    var myEvent = event;
    var myElement = element;

    //  add an 'xhr' request parameter to indicate what this is for
    var myHref = href + (href.indexOf('?') == -1 ? '?' : '&') + 'xhr=true';
    
    // Set content to placeholder graphic
    var imgCntr = new Element('div', { 'class': 'progresstab' } );
    (new Asset.image(img_loop)).injectInside(imgCntr);
    imgCntr.injectInside(myElement);

    // Make AJAX call to get content.
    new Ajax(myHref,
    {
        onComplete: function(txt, xml)
        {
            myElement.empty();
            myElement.innerHTML = txt;
            
            // apply any defined behavior
            window.behavior.apply(myElement);
            
            //  notify anyone listening we are done
            myElement.fireEvent('onContentReplaced', [myEvent, myElement]);
        },
        evalScripts:true
    }).request();
};

linkMap['js_replaceContent'] = function(elmt, e)
{
    //  get the target element's id
    var match = elmt.className.match(/id_([^\s"]*)?/);
    if (!match || match.length != 2) throw new Error("Links with behavior js_replaceContent must also have a style class id_??? to indicate which element's contents should be replaced");
    match = match[1];
    
    //  get the target element
    var element = $(match);
    
    var href = elmt.href;
    if (href) 
    {
        //  replace the contents of the element via XHR
        replaceContent(e, element, href);
    }
    e.stop();
};

rules['#TAB_CONTAINER'] = function(elmt, e)
{
    //  grab the initially selected tab and its index
    var selectedTab = elmt.getElements('.current');
    if (selectedTab.length != 1)
    {
        throw new Error("You must have exactly one tab with a class of 'current'.");
    }
    else
    {
        selectedTab = selectedTab[0];
    }
    var selectedTabIndex = Number(selectedTab.className.match(/tab(\d+)/)[1]);
    
    //  if we are on the home page, we allow the currently selected tab to
    //  be defined by a 't' has param
    if ($('HOMEPAGE') && window.location.hash)
    {
        var hash = window.location.hash.match(/t(\d)/);
        if (hash && hash.length > 0)
        {
            selectedTabIndex = parseInt(hash[1]);
            selectedTab.removeClass('current');
            elmt.getElements('.tab')[selectedTabIndex].addClass('current');
        }
    }
    
    //  grab references to all tabs and tab content nodes
    var tabs = elmt.getElements('.tabContainerHead .tab');
    if (tabs.length == 0) return;
    var elmts = elmt.getElements('.tabContainerBody .tabContent')

    //  create a new tab set    
    new TabSet(tabs, elmts,
    {
        show:selectedTabIndex,
        onActive:function(event, toggler, element)
        {
            var xhr = toggler.hasClass('xhr');   
            
            //  if we are using XHR to populate the tab content and we have not already done so
            if (xhr && !toggler.hasClass('xhrComplete'))
            {
                // grab the href
                var href = toggler.getElement('a').href;
                if (href) 
                {
                    //  replace the contents of the tab element via XHR
                    var myToggler = toggler;
                    element.addEvent('onContentReplaced', function(){myToggler.addClass('xhrComplete');});
                    replaceContent(event, element, href);
                }
            }
            
            //  if we should record the user action
            if (toggler.hasClass('recordAction'))
            {
                new Ajax('/ActionRecord?action=' + toggler.id).request();
            }
            
            //  add a class to mark this as the current tab
            toggler.addClass('current');
            
            //  if we are using XHR then stop the event so we do not navigate the entire page
            if (xhr && event) event.stop();
        },
        onBackground:function(event, toggler, element)
        {
            toggler.removeClass('current');
        }
    });
};

//close the lightbox (for 'account has been deleted' lightbox)
rules['#LIGHTBOX_CLOSE'] = function(elmt) {
  elmt.addEvent("click", function(e) {
      window.lightbox.deactivate();
  });
};

//Expand click area for offers in BBDN box on Tourism Servlet
//rules['#BBD tr.offerRow'] = function(elmt) {
//  elmt.addEvent('click', function(e) {
//    var event = new Event(e);
//    event.preventDefault();
//    offerLink = elmt.getElement('a');
//    popCommFN = linkMap['js_popComm'];
//    popCommFN(offerLink,e);
//  });
//} 

//  open the vacation rentals calculator in a lightbox
function vrCalculator (elmt, e)
{
    var event = e != null ? new Event(e) : null;

    if (elmt && /pid(\d+)/.test(elmt.className)) Cookie.set('NPID', RegExp.$1, {domain: cookieDomain, time:5});
    
//  if this is the home page promo
    var args = '';
    var vrCalcForm = $('homePageVRCalcPromo');
    if (!vrCalcForm)
    {
        // try looking for the div from the VR overview page
        vrCalcForm = $('calculatorOverviewPromo');
    }
    if (!vrCalcForm)
    {
        // try looking for the div from the VR overview page
        vrCalcForm = $('calculatorLanderPromo');
    }
    if (vrCalcForm && $('vrCalculatorForm'))
    {
        //  if the user did not provide a geo name, clear the tip text
        var geoNameField = vrCalcForm.getElement('#geoName');
        if (geoNameField.hasClass('focusClear'))
        {
            geoNameField.value = '';
            geoNameField.removeClass('focusClear');
        }
        
        //  grab our args
        args = '&geoName=' + vrCalcForm.getElement('#geoName').value;
    }
    
    //  open an ajax lightbox and when active focus on the first input element
    ajaxLightbox('/VacationRentalCalculator?restart=true' + args,
                 function() { this.inner.getElement('input').focus();});
    if (event) event.stop();
    return false;
};

//  update the vacation rentals calculator with results
linkMap['js_submitVRCalculator'] = function(elmt, e)
{
    var event = e != null ? new Event(e) : null;
    
    //  get the calculator div and form
    var div = $('vrCalculator');
    var form = div.getElement('form');
    
    //  hide any server error messages since they are trying again
    var serverError = div.getElement('.serverErrorMsg');
    if (serverError)
    {
        serverError.style.display = 'none';
    }
    
    //  make sure they selected a valid destination
    if (form.geoName.value == '')
    {
        div.getElement('.errorMsg').style.display = '';
    }
    //  else assemble a url from the form and replace the div's contents with the resulting
    //  content
    else
    {
        var url = form.action + '?' + form.toQueryString();
        replaceContent(e, div.getParent(), url);
    }
    if (event) event.stop();
    return false;
};
/*
Script: flyout.js
  Flyout class and related behavior rules.
  Contains: <Flyout>
*/

var POS = {TOP:0, RIGHT:1, BOTTOM:2, LEFT:3};

/*
Class: Flyout
  Spawns a flyout on the page from a target. If the element has a child with the class
  'flyoutContents', its contents will be used for the flyout. Otherwise, the href of the
  first 'A' child will be used to request the content via AJAX. By default flyouts are
  triggered on click. Clicking the spawning element a second time, or anywhere outside
  the flyout, will close the flyout. If the bound option is set, flyouts instead show on
  mouse enter, and disappear when the mouse leaves either the element or the flyout.

Arguments:
  elmt - required, the element that should spawn the flyout.
	options - optional, see options below.
  content - optional, content to use in the flyout (overrides flyoutContents and AJAX request).

Options:
  offsets - (obj) x and y offsets, default: {x:0, y:0}
  arrowPosition - one of: POS.TOP, POS.RIGHT, POS.BOTTOM, POS.LEFT, default: POS.TOP
  showClose - (boolean) whether or not to show the close link in the flyout, default: true
  bound - (boolean) if true, the flyout is on mouseenter and hidden when the mouse leaves the
    spawning elements or the flyout, default: false
  showArrow - (boolean) whether or not to show the arrow, default: true
  autoSpawn - (boolean) whether or not events should be added to cause the flyout to show and hide.
    Note if this is set to false, you will have to manually call show and hide.
  centerArrow - (boolean) true to center the arrow, otherwise defaults to top/left
  adjustable - (boolean) true if position can be adjusted to ensure visibility
  adjusted - (obj) x and y offsets when adjusted, defaults to offsets if not set
  runScripts - (boolean) true to execute scripts in response text for remote content via Ajax, defaults to false
  cacheAjax - (boolean) if true, response of ajax request to remoteContent is kept, if false the content is reloaded
    each time the flyout is shown, default: true
  disableGlobal - (boolean) if true, global reference window.flyout is not set. default: false
    This may need to be used if a flyout contains a calendar which loads in another flyout itself, for example.
  cancelBoundOnClick - (boolean) if set to true and the bound option is true, a click anywhere inside the flyout will 
    cancel the bound so that moving the mouse outside the flyout will no longer hide the flyout, default: false
  flyoutClass - (String) a custom flyout CSS class
  flyoutId - (String) a custom flyout Id.  Note that if you change this you will lose the base '#FLYOUT' styles
*/
var Flyout = new Class({
  options: {
    offsets: {x:0, y:0},
    arrowPosition: 2,
    showClose: true,
    bound: false,
    showArrow: true,
    arrowClass: 'arrow',
    autoSpawn: true,
    flyoutClass: null,
    flyoutId: 'FLYOUT',
    limit: 0,
    centerArrow: false,
    remoteContent: false,
    remoteCallback: false,
    adjustable: false,
    adjusted: false,
    crAutoAdjust: false,
    runScripts: false,
    cacheAjax: true,
    disableGlobal: false,
    cancelBoundOnClick: false
  },

  initialize: function(elmt, options, content) {
    this.elmt = elmt;
    this.setOptions(options);
    
    if (!this.options.adjusted) this.options.adjusted = this.options.offsets;

    if (pos = elmt.className.match(/\bpos(Left|Right|Top|Bottom)\b/)) {
      this.options.arrowPosition = POS[pos[1].toUpperCase()];
      // reset offsets if overriding position
      this.options.offsets = {x:0, y:0};
    }
    if (off = elmt.className.match(/\bol(-?\d+)/)) this.options.offsets.x = parseInt(off[1]);
    if (off = elmt.className.match(/\bot(-?\d+)/)) this.options.offsets.y = parseInt(off[1]);

    if (!options.arrowClass && this.options.arrowPosition != POS.BOTTOM) {
      if (this.options.arrowPosition == POS.RIGHT) this.options.arrowClass = 'arrowLeft';
      else if (this.options.arrowPosition == POS.TOP) this.options.arrowClass = 'arrowBottom';
      else this.options.arrowClass = 'arrowRight';
    }

    if (content) this.content = content;
    else {
      this.content = this.elmt.getElement('.flyoutContents');
      if (this.content) this.content = this.content.getChildren().remove();
      else {
        // fetch content via AJAX
        var t = this.elmt.getElement('a.src');
        if (t) {
          // set content to placeholder graphic
          this.remoteContent = t.href;
        }
        else if (this.options.remoteContent) {
          this.remoteContent = this.options.remoteContent;
        }
        else if (window[elmt.id]) {
          if (this.options.remoteCallback) {
            this.remoteContent = window[elmt.id]();
          }
          else {
            this.callback = window[elmt.id];
          }
        }
        else {return;}
      }
    }

    // Build container when requested.
    this.container = false; 
    
    this.clickedInside = false;

    if (this.options.autoSpawn) {
      this.documentListener = this.hide.bindAsEventListener(this);
      if (this.options.bound) {
        if(this.options.cancelBoundOnClick)
        {
          this.clickInsideListener = this.userClick.bindAsEventListener(this); 
        }
        this.eventType = 'mousemove';
        this.elmt.addEvent('mouseenter', this.toggle.bindAsEventListener(this));
        this.elmt.addEvent('mouseleave', this.abort.bindAsEventListener(this));
      }
      else {
        this.eventType = 'click';
        // for ie6, we'll immediately toggle back off if we do this inside the click event
        var defer = function() {
            this.elmt.addEvent('click', this.toggle.bindAsEventListener(this));
        }
        defer.delay(10, this);
      }
    }

    // Be sure to cleanup 
    this.elmt.addEvent('trash', this.destroy.bindAsEventListener(this));
  },

  buildContainer: function() { 

    if (this.remoteContent) {
      this.content = new Asset.image(img_loop);
      this.content.style.height = "40px";
      this.content.style.width = "40px";
      this.content.className = "loading";
    }

    this.container = new Element('div', {
      styles: {
        position: 'absolute',
        left: '-999em',
        display: 'block',
        zIndex: 9999
      },
      id: this.options.flyoutId,
      'class': this.options.flyoutClass
    });

    // rounded corners
    this.top  = new Element('div', {'class': 'cnrR5 top'}).injectInside(this.container);
    this.tl   = new Element('div', {'class': 'lft'}).setContent("<!--Lft Corner-->").injectInside(this.top);
    this.tm   = new Element('div', {'class': 'mid'}).setContent("<!--Mid Border-->").injectInside(this.top);
    this.tr   = new Element('div', {'class': 'rgt'}).setContent("<!--Rgt Corner-->").injectInside(this.top);
    this.btm  = new Element('div', {'class': 'cnrR5 btm'}).injectInside(this.container);
    this.bl   = new Element('div', {'class': 'lft'}).setContent("<!--Lft Corner-->").injectInside(this.btm);
    this.bm   = new Element('div', {'class': 'mid'}).setContent("<!--Mid Border-->").injectInside(this.btm);
    this.br   = new Element('div', {'class': 'rgt'}).setContent("<!--Rgt Corner-->").injectInside(this.btm);

    if (this.options.showArrow)
      this.point = new Element('span', {'class': this.options.arrowClass}).setContent('&#x20').injectInside(this.container);

    if (this.options.showClose) {
      var div   = new Element('div', {'class': 'close'}).injectInside(this.container);
      new Element('span', {'class': 'cnrL'}).injectInside(div);
      new Element('span', {'class': 'cnrB'}).injectInside(div);
      new Element('span', {'class': 'cnrBL'}).injectInside(div);
      this.closeLink  = new Element('a', {href: 'javascript: void(0)', 'class': 'close'}).setContent(lang_Close).injectInside(div);
    }

    this.inner = new Element('div', {'class': 'inner'}).setContent(this.content).injectInside(this.container);
  },
  
  adjustPositioning: function(){
    if(typeof this.elmt != "undefined")
    {
      var heightDiff = 0;
      var widthDiff = 0;
      
      //set default position for arrow
      this.point.setStyle('top', 52).setStyle('left', -12);
      this.point.setStyle('background', 'transparent url(/img2/checkrates/pointer.gif) repeat scroll 0 0');
      
      //Update bottom edge case
      var lb_bottom_pos = this.elmt.getTop() - window.getScrollTop() + this.container.getCoordinates().height;
      if( $(window).getHeight() < lb_bottom_pos )
      {
        var heightDiffPadding = -50;
        heightDiff = lb_bottom_pos - $(window).getHeight() + heightDiffPadding;
        this.container.setStyle('top', this.container.getStyle('top').toInt() - heightDiff);
        if (this.options.showArrow && this.point)
        {
          this.point.setStyle('top', 71 + heightDiff);
          if( this.elmt.getTop() + this.container.getTop() - window.getScrollTop() + 20 > $(window).getHeight() )
          {
              this.point.setStyle('top', this.point.getStyle('top').toInt() - 20 );
          }
        }
      }
      
      //Update right screen case
      var lb_right_pos = this.elmt.getLeft() - window.getScrollLeft() + this.container.getCoordinates().width;
      if( $(window).getWidth() < lb_right_pos)
      {
        var widthDiffPadding = 10;
        widthDiff = this.container.getCoordinates().width + this.elmt.getCoordinates().width + widthDiffPadding;
        this.container.setStyle('left', this.container.getStyle('left').toInt() - widthDiff);
        if (this.options.showArrow && this.point)
        {
          var arrowOffset = 3;
          this.point.setStyle('left', this.container.getCoordinates().width + this.point.getStyle('left').toInt() + arrowOffset);
          this.point.setStyle('background', 'transparent url(' + cdnHost + '/img2/checkrates/pointer_flip.gif) repeat scroll 0 0');
        }
      }
      
      /*  --- TO DO ---
      //Update top screen case
      var lb_top_pos = this.elmt.getTop() - window.getScrollTop() + this.options.padTop;
      if( 0 > lb_top_pos )
      {
        var heightDiffPadding = 2;
        heightDiff = lb_top_pos + heightDiffPadding;
        
        var arrowImg = $(this.options.contentId).getElement('img.arrow');
        if(arrowImg)
        {
          arrowImg.setStyle('top', arrowImg.getStyle('top').toInt() + heightDiff );
          if( this.trigger.getTop() - window.getScrollTop() - 30 < 0 )
          {
            arrowImg.setStyle('top', arrowImg.getStyle('top').toInt() + 30 );
          }
        }
        
      }
      */ 
    }
  },

  position: function() {
    var c = this.container.getCoordinates();
    var sC = this.elmt.getCoordinates();
    // Safari can't calculate positions for TRs correctly, so use the first cell instead
    if (window.webkit419 && this.elmt.getTag() == "tr") sC = this.elmt.getElement('td').getCoordinates();
    // make sure flyout is within bounds of PAGE element
    var page = $('PAGE').getCoordinates();
    var rightLimit = page.right - 14 - this.options.limit;

    // default to top-left corner
    this.container.setStyle('top', sC.top + this.options.offsets.y + 'px');
    
    if (this.options.arrowPosition == POS.BOTTOM) { // deafult
      var l = sC.left + this.options.offsets.x;
      if (this.point && !this.pointOrigLeft) this.pointOrigLeft = parseInt(this.point.getStyle('left').replace(/px/,''));
      if (this.point) l -= this.pointOrigLeft;
      if (l + c.width > rightLimit) {
        l = rightLimit - c.width;
        if (this.point) this.point.setStyle('left', sC.left - l + "px");
      }
      this.container.setStyle('left', l + 'px');
      this.container.setStyle('top', sC.bottom + this.options.offsets.y + "px");
      if (this.options.centerArrow && this.point) { // move the arrow to the right half-way across the source elmt
        this.point.setStyle('left', sC.left + Math.floor(sC.width / 2) - l - Math.floor(this.point.getCoordinates().width / 2) + "px");
      }
    }
    else if (this.options.arrowPosition == POS.RIGHT) {
      // Safari can't calculate positions for TRs correctly, so use the last cell instead
      if (window.webkit419 && this.elmt.getTag() == "tr") sC = this.elmt.getLastElement('td').getCoordinates();
      this.container.setStyle('left', (sC.right + this.options.offsets.x) + 'px');
    }
    else if (this.options.arrowPosition == POS.LEFT) {
      // Safari can't calculate positions for TR/TDs correctly, so use the table for left position instead
      // note: if trying to do this for any TD after the first, will also need to add the left position of the TD
      if (window.webkit419 && this.elmt.getTag() == "tr") sC = this.elmt.getParent('table').getCoordinates();
      this.container.setStyle('left', (sC.left - c.width + this.options.offsets.x) + 'px');
    }
    else if (this.options.arrowPosition == POS.TOP) {}

    if (this.options.adjustable) {
      var pageSize = Math.max( window.getHeight(), window.getScrollHeight() );
      var c = this.container.getCoordinates();
      if ((c.top + c.height) > (pageSize - 14)) {
        this.container.setStyle('top', sC.top - c.height - this.options.adjusted.y + 'px');
      }
    }

    //adjust positioning if flyout has crAutoAdjust enabled - only used for Check Rates test
    if(this.options.crAutoAdjust)
    {
      this.adjustPositioning();
    }
    
    this.positionCorners();
    return this;
  },

  positionCorners: function() {
    var c = this.container.getCoordinates();
    this.top.setStyle('width', c.width + 'px');
    this.btm.setStyle('width', c.width + 'px');
    var tm = c.width - this.tl.getCoordinates().width - this.tr.getCoordinates().width;
    var bm = c.width - this.bl.getCoordinates().width - this.br.getCoordinates().width;
    this.tm.setStyle('width', (tm > 0 ? tm : 0) + "px");
    this.bm.setStyle('width', (bm > 0 ? bm : 0) + "px");

    if (this.options.autoSpawn && this.options.bound) { // set bounds for pass-thru
      var sC = this.elmt.getCoordinates();
      if (this.options.arrowPosition == POS.BOTTOM) { // deafult
        this.passThruBounds = {top:sC.bottom, bottom:c.top, left:sC.left, right:sC.right};
      }
      else if (this.options.arrowPosition == POS.RIGHT) {
        this.passThruBounds = {top:c.top, bottom:c.bottom, left:c.right, right:sC.left};
      }
      else if (this.options.arrowPosition == POS.LEFT) {
        this.passThruBounds = {top:c.top, bottom:c.bottom, left:sC.right, right:c.right};
      }
      else if (this.options.arrowPosition == POS.TOP) {
        this.passThruBounds = {top:c.bottom, bottom:sC.top, left:sC.left, right:sC.right};
      }
    }
  },

  setAJAXContent: function(txt, xml) {
    this.content = txt;
    if (this.options.arrowPosition == POS.LEFT) this.container.setStyle('left', '-999em');
    this.inner.setContent(this.content);
    if(this.options.cacheAjax) this.remoteContent = null;
    if (this.options.arrowPosition == POS.LEFT) {
      var c = this.container.getCoordinates();
      var sC = this.elmt.getCoordinates();
      // Safari can't calculate positions for TR/TDs correctly, so use the table for left position instead
      // note: if trying to do this for any TD after the first, will also need to add the left position of the TD
      if (window.webkit419 && this.elmt.getTag() == "tr") sC = this.elmt.getParent('table').getCoordinates();
      this.container.setStyle('left', (sC.left - c.width + this.options.offsets.x) + 'px');
    }
    this.positionCorners();
    this.position(); // make sure its still within the bounds of the PAGE element
    this.hideSelects();
    window.behavior.apply(this.inner);// apply any defined behavior
  },

  hideSelects: function() {
    if (window.ie6) {
      var contained = this.container.getElements('select');
      var covered = [];
      $$('select').each(function(s){
        if (!contained.contains(s) && this.container.overlaps(s)) {
          covered.push(s);
          s.setStyle('visibility', 'hidden');
        }
      }, this);
      this.covered = new Elements(covered);
    }
  },

  toggle: function(e) {
    new Event(e).stop();

    if (!this.options.bound && this.container && this.container.inDocument()) {
      if (window.ie6) $$('select').setStyle('visibility', 'visible');
      this.hide();
    }
    else {this.options.bound ? this._show() : this.show(); }
    return this;
  },

  show: function() {
    // If the container hasn't been built, then build it.
    var containerBuilt = false;
    if (!this.container) { containerBuilt = true; this.buildContainer(); }

    if (this.container.inDocument()) return;
    if (this.remoteContent) {
      new Ajax(this.remoteContent, {
        onComplete: this.setAJAXContent.bind(this),
        onFailure: function(e) { alert(JS_Ajax_failed); },
        evalScripts: this.options.runScripts
      }).request();
    }
    if (this.callback) {
      this.inner.setContent(this.callback(this));
      this.positionCorners();
    }
    if (window.flyout) window.flyout.hide();
    
    if(!this.options.disableGlobal)
    {
      window.flyout = this;
    }
    else
    {  
      window.crFlyout = this;
    }
    
    this.container.setStyle('left', '-999em');
    this.add();

    // if showing close link, reposition contents lower
    if (containerBuilt) {
      if (this.closeLink) this.inner.style.paddingTop = parseInt(this.inner.getStyle("paddingTop").replace(/px/,'')) + this.closeLink.getCoordinates().height + "px";
    }
    this.position();

    this.hideSelects();
    if (this.options.autoSpawn)
    {
      document.addEvent(this.eventType, this.documentListener);
      if(this.options.bound && this.options.cancelBoundOnClick)
      {
        document.addEvent('click', this.clickInsideListener);
      }
    }
    
    // add the 'open' class to the flyout origin element
    this.elmt.addClass("open");
    
    return this;
  },

  _show: function() {
    this.showDelay = this.show.delay(200, this);
  },

  abort: function(e) {
    $clear(this.showDelay);
  },

  /*
  Property: hide
    Called either on mousemove or click by document events.
  */
  hide: function(e) {
    // If the container hasn't been built, then bail.
    if ((this.container == null) || (this.container == false)) { return; }
    if (!this.container.inDocument()) return;

    if (e) {
      e = new Event(e);
      if (this.options.bound) {
        // mouse is still inside the flyout or the spawning element
        if (this.container.contains(e) || this.elmt.contains(e)) return;
        if (e.page.x > this.passThruBounds.left && e.page.x < this.passThruBounds.right &&
            e.page.y > this.passThruBounds.top && e.page.y < this.passThruBounds.bottom) return;
      }
      else {
        if ($(e.target).getTag() == 'option') return; // clicked on an open select dropdown

        if (window.ie && $(e.target).getTag() == 'select' && this.container.getElements('select').contains(e.target)) return;

        // user clicked inside the flyout but not on the close button
        if (this.container.contains(e) && !this.closeLink.contains(e)) return;

        // FF: button version of submit button causes flyout to close after an alert
        if (e.page.x == 0 || e.page.y == 0) {
          if (e.target.getTag() == 'a' && this.container.getElements('a').contains(e.target)) return;
          else if (e.target.getTag() == 'input' && this.container.getElements('input').contains(e.target)) return;
        }
      }
      e.preventDefault();
    }
    if (this.options.autoSpawn)
    {
      document.removeEvent(this.eventType, this.documentListener);
      
      //reset flyout to original bound state on hide if a click inside occurred
      if (this.clickedInside)
      {
        this.options.bound = true;
        this.clickedInside = false;
        this.eventType = 'mousemove';
        document.addEvent(this.eventType, this.documentListener); 
      }
      //otherwise remove the click listener if hidden before a click inside
      else if (this.options.bound && this.options.cancelBoundOnClick)
      {
        document.removeEvent('click', this.clickInsideListener);
      }
    }
    if (this.covered) this.covered.setStyle('visibility', 'visible');
    this.remove();
    
    // remove the 'open' class to the flyout origin element
    this.elmt.removeClass("open");
  },

  /*
  Property: add
    Add the flyout container to the DOM.
  */
  add: function() { this.container.injectInside(document.body); },

  /*
  Property: remove
    Remove the flyout container from the DOM.
  */
  remove: function() 
  {
    if (this.container == false) { return; }
    if (this.container.inDocument()) this.container.remove(); 
  },

  /*
    Discards the flyout on page unload.
  */
  destroy: function() 
  {
    this.remove();
    this.elmt = null;
    this.content = null;
    this.container = null;
  },
  
  /* Used with option cancelBoundOnClick
   * When a user has clicked inside the flyout, cancel the bound option
   * so that the flyout doesn't close on a mousemove outside of the flyout container.
   */
  userClick: function(e)
  {
    if (e)
    {
      e = new Event(e);
      if (this.container.contains(e) || this.elmt.contains(e))
      {
        //only one click needs to be detected
        document.removeEvent('click',this.clickInsideListener);
        this.options.bound = false;
        this.clickedInside = true;
        
        //switch hide from being bound to mousemove to click
        document.removeEvent(this.eventType, this.documentListener);
        this.eventType = 'click';
        document.addEvent(this.eventType, this.documentListener);
      }
    }
  }

});
Flyout.implement(new Options);

var flyoutSpawner = function(e, ops, evntType, onCreateCallback) {
  this.removeEvent(evntType || 'click', this.deferFn).flyout = new Flyout(this, ops).toggle(e);
  this.deferFn = null;
  if (onCreateCallback) onCreateCallback(e, this);
}

var deferFlyout = function(elmt, ops, evntType, onCreateCallback) {
  elmt.deferFn = flyoutSpawner.bindAsEventListener(elmt, [ops, evntType, onCreateCallback]);
  elmt.addEvent(evntType || 'click', elmt.deferFn);
}

rules['li.flyout'] = function(elmt) {deferFlyout(elmt, {offsets: {x:-1, y:8}});}
rules['li.flyoutB'] = function(elmt) {deferFlyout(elmt, {offsets: {x:-1, y:8}, bound: true, showClose: false, flyoutClass: 'mediaBox'}, 'mouseenter');}
//rules['#FUNSTUFFPOP'] = function(elmt) {deferFlyout(elmt, {offsets: {x:14, y:16}, remoteContent: '/vpages/funStuffFly.html?lt=evt'});}
rules['li.flyoutR'] = function(elmt) {deferFlyout(elmt, {arrowPosition: POS.RIGHT, offsets: {x:4, y:-16}});}
//rules['#SIS_ACCORDION tr.flyout'] = function(elmt) { deferFlyout(elmt, {arrowPosition: POS.RIGHT, offsets: {x:0, y:0}});}
//rules['#SIS_ACCORDION tr.flyoutL'] = function(elmt) { deferFlyout(elmt, {arrowPosition: POS.LEFT, offsets: {x:0, y:0}});}
//rules['#reisePop'] = function(elmt) {deferFlyout(elmt, {offsets: {x:-374, y:30}, flyoutClass: 'flyoutAwardContents', remoteContent: '/vpages/reise.html?lt=evt'});}
//rules['#DESTINATIONSPOP'] = function(elmt) {deferFlyout(elmt, {offsets: {x:12, y:14}, flyoutClass: 'flyoutMapContents', remoteContent: '/vpages/destinationsFly.html?lt=evt'});}
//rules['#INTLPOP'] = function(elmt) {deferFlyout(elmt, {offsets: {x:12, y:14}, remoteCallback: true});}
rules['li.flyoutMemOnly'] = function(elmt) {deferFlyout(elmt, {offsets: {x:14, y:16}, remoteContent: '/vpages/memOnlyFly.html'});}
//rules['#THUMBBOX li'] = rules['#SHOW_USER_REVIEW div.thumbnails li'] = function(elmt) { deferFlyout(elmt, {offsets: {x:4, y:9}, limit:14, showClose: false, bound: true, flyoutClass: 'mediaBox', centerArrow: true}, 'mouseenter');}
//rules['li.flyoutX'] = function(elmt) {deferFlyout(elmt, {offsets: {x:4, y:8}});}
//rules['#ACCOM_OVERVIEW img.bestValueFly'] = rules['#ACCOM_DETAIL img.bestValueFly'] = rules['#HDPR_V1 img.bestValueFly'] = rules['#SHOW_USER_REVIEW img.bestValueFly'] = function(elmt) {deferFlyout(elmt, {arrowPosition: POS.BOTTOM, offsets: {x:12, y:12}, bound: true, showClose: false, remoteContent: '/vpages/bestValueFly.html'}, 'mouseenter');}
//rules['#BV_SMALL'] = function(elmt) {deferFlyout(elmt, {arrowPosition: POS.BOTTOM, offsets: {x:0, y:18}, bound: true, showClose: false, remoteContent: '/vpages/bestValueFly.html'}, 'mouseenter');}


function INTLPOP () {
  if (!$defined(flagsUrl) || flagsUrl == ''){
	  flagsUrl = document.location.pathname;
  }
  var uri = '/StaticVelocityPage?t=intSitesFly.vm&lt=evt&footerFlagFormat=' + footerFlagFormat + '&flagsURL=' + encodeURIComponent(flagsUrl);
  if (document.location.search != '') uri += encodeURIComponent(document.location.search);
  if (document.location.hash != '') uri += encodeURIComponent(document.location.hash);
  if (window['modelGeoId']) uri += '&geo=' + modelGeoId;
  return uri;
}   

/*
 * Today's Top Value drop down on /Hotel_Review
 */
rules['#VALUE_DROP'] = function(elmt)
{
    var xpos = 0;
    var limit = 0;
    if (window.ie6)
    {
        xpos = 3;
        limit = -3;
    }
    deferFlyout(elmt, {
        offsets:{x:xpos, y:0},
        limit:limit, 
        bound:true, 
        showClose:false,
        showArrow:false,
        flyoutId:"VALUE_DROP_FLYOUT"
    }, 'mouseenter');
};/*
Script: calendar.js
  Contains <Calendar>

License:
  not free for public use
*/

var fromCalendar = null;
var toCalendar = null;
var currentCalendar = null;

var daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
/*
Class: Calendar
  A scrolling, multi-month calendar.

Arguments:
  elmt - required, the element that should spawn the flyout.
	options - optional, see options below.

Options:
  calendarClass - (string) class name to give the calendar
  todayClass - (string) class name for the table cell representing today
  selectedClass - (string) class name for the table cell representing the selected day
  disabledClass - (string) class name for disabled dates
  invalidClass - (String) class name for invalid dates
  weekStart - (integer) days from Sunday on which to start the week (1 for Monday, etc.)
  selectedDate - (Date) the currently selected date (default: null)
  firstDate - (Date) first valid date of calendar (anything before it will be disabled)
  lastDate - (Date) last valid date of calendar (anything after it will be disabled)
  showOtherDates - (boolean) if false the padding days around a month aren't shown
  dualCalendar - (boolean) if true two months are shown instead of just one
  show - (function) function to be called in order to show the calendar (here for overriding)
    The function will be bound to the calendar as event listener.
  hide - (function) same as show, but called when that calendar should be hidden
  hideOnDocClick - (boolean) if the hide function should be called on a document click
  showOnSourceFocusOrClick - (boolean) if the show function should be called whenever the source
      gains focus or is clicked
  invalidDates - (Array) a list of invalid dates or date ranges.  If it is a date range then we
      are expecting a sub-array of size 2.  All these dates will be replaced with a red 'X'.  Note
      that dates may be in timestamp format (i.e. number of milliseconds).
  useLinks - (boolean) if each valid date should be a link

Events:
  onSelect - called when the user selects a date
  onRequest - called just before the calendar is shown
*/
var Calendar = new Class({
  options: {
    calendarClass: "calendar",
    todayClass: "today",
    selectedClass: "selected",
    disabledClass: "disabled",
    invalidClass: "invalid",
    otherMonthClass: "other",
    controlsClass: "navCal",
    weekStart: 0,
    selectedDate: null,
    firstDate: null,
    lastDate: null,
    showOtherDates: true,
    dualCalendar: false,
    show: null,
    hide: null,
    hideOnDocClick:false,
    showOnSourceFocusOrClick:true,
    invalidDates:null,
    useLinks:true,
    formatter:null,
    dayNames: false,
    offsetOther: 0
  },

  initialize: function(elmt, options) {
    this.source = elmt;
    this.setOptions(options);
    
    if (!this.options.firstDate) this.options.firstDate = new Date();
    if (!this.options.lastDate) this.setLastDate();

    this.today = new Date();
    this.selectedDate = this.options.selectedDate;

    // force Dates to midnight for easier comparison
    this.today.setHours(0,0,0,0);
    if (this.options.firstDate) this.options.firstDate.setHours(0,0,0,0);
    if (this.options.lastDate)  this.options.lastDate.setHours(0,0,0,0);
    if (this.selectedDate)      this.selectedDate.setHours(0,0,0,0);

    if (!this.options.show) this.options.show = this.show;
    if (!this.options.hide) this.options.hide = this.hide;
    
    var arr = [];
    arr.push('<div class="');
    arr.push(this.options.controlsClass);
    arr.push('">');
    arr.push('<span class="prev"><a style="display: block;" onclick="currentCalendar.prev()">Previous Month</a></span>');
    arr.push('<span class="next"><a style="display: block;" onclick="currentCalendar.next()">Next Month</a></span>');
    arr.push('</div>');
    
    this.container = new Element('div', {'class': this.options.calendarClass});
    this.container.setHTML(arr.join(''));
    if (this.container.inDocument())
      this.container.parentNode.removeChild(this.container);

    if (this.options.showOnSourceFocusOrClick)
    {
        this.source.addEvent('focus', this.options.show.bindAsEventListener(this));
        this.source.addEvent('click', this.options.show.bindAsEventListener(this));
    }
    
    if (this.options.hideOnDocClick) document.addEvent('click', this.options.hide.bindAsEventListener(this));
    
    if (this.source.onSelectDefer) {
      this.addEvent('onSelect', this.source.onSelectDefer);
      this.source.onSelectDefer = null;
    }

    // Be sure to cleanup
    this.source.addEvent('trash', this.destroy.bindAsEventListener(this));
  },

  /*
    Discards the flyout on page unload.
  */
  destroy: function()
  {
    this.source.calendar = null;
    this.source = null;
    this.container = null;
    this.controls = null;
    this.prev = null;
    this.next = null;
    this.after = null;
    this.before = null;
  },
  
  setLastDate: function() {
    var d = new Date();
    d.setDate(1);
    if (d.getMonth() == 0) {
      d.setMonth(11);
    }
    else {
      d.setMonth(d.getMonth()-1);
      d.setFullYear(d.getFullYear()+1);
    }
    this.options.lastDate = d;
  },

  /*
  Property: update
    Update the month(s) shown by the calendar. Should be called whenever the date is changed externally.
  */
  update: function() {
    if (this.currentMonth) this.removeTable(null, this.currentMonth);
    if (this.nextMonth) this.removeTable(null, this.nextMonth);

    var firstMonth = this.selectedDate || this.today;
    if (this.options.firstDate && firstMonth < this.options.firstDate) firstMonth = this.options.firstDate;
    if (this.options.dualCalendar) {
      var testMonth = new Date(firstMonth);
      testMonth.setDate(daysInMonth[testMonth.getMonth()]);
      testMonth.setHours(0,0,0,0);
      if (testMonth >= this.options.lastDate) {
        firstMonth = new Date(firstMonth);
        if (firstMonth.getMonth() == 0)
          firstMonth.setFullYear(firstMonth.getFullYear()-1,11,1);
        else
          firstMonth.setMonth(firstMonth.getMonth()-1,1);
      }
    }
    
    this.currentMonth = this.createMonth(firstMonth);
    this.container.appendChild(this.currentMonth.elmt);
    if (this.options.dualCalendar) {
      var d = new Date(this.currentMonth.date);
      var day = d.getDate();
      var nextMonth = d.getMonth()+1;
      if (day > daysInMonth[nextMonth]) { day = daysInMonth[nextMonth]; }
      d.setMonth(nextMonth, day);
      this.nextMonth = this.createMonth(d);
      this.container.appendChild(this.nextMonth.elmt);
    }
    
    //  set initial state of prev and next buttons
    this.updatePrevNext();

    return this;
  },

  /*
  Property: show
    Default show function.
  */
  show: function(e) {
    currentCalendar = this;
    this.fireEvent('onRequest');

    if (!this.container) this.build();
    else this.update();
    if (!this.container.inDocument()) this.container.injectInside(this.source);
    
    this.reposition();
    return this;
  },
  
  reposition: function(){
    //  adjust the left offset of the current and next month (if applicable)
    this.currentMonth.elmt.setStyle('left', '0px');
    if (this.options.dualCalendar)
    {
        this.nextMonth.elmt.setStyle('left', this.currentMonth.elmt.getCoordinates().width + this.options.offsetOther + 'px');
    }
    return this;
  },
  
  /*
   * Update the visibility of the prev and next buttons
   */
  updatePrevNext:function()
  {
    var currentPrev = this.currentMonth.date;
    var currentNext = this.options.dualCalendar ? this.nextMonth.date : this.currentMonth.date;
    
    var hidePrev = this.sameMonth(currentPrev, this.options.firstDate);
    var hideNext = this.sameMonth(currentNext, this.options.lastDate);
    
    getChildByClass(this.container,"prev").style.display = (hidePrev ? 'none' : 'block');
    getChildByClass(this.container,"next").style.display = (hideNext ? 'none' : 'block');
  },
  
  /*
   * Check that two dates are both not null and occur in the same month/year
   */
  sameMonth:function(/* Date */ date1,
                     /* Date */ date2)
  {
    return (date1 != null) &&
           (date2 != null) &&
           (date1.getMonth() == date2.getMonth()) &&
           (date1.getYear() == date2.getYear());
  },

  /*
  Property: hide
    Default hide function.
  */
  hide: function(e) {
    if (!this.container.inDocument()) return;
    if (this.source.contains(e)) return;
    if (this.container.contains(e)) return;
    var e = new Event(e).stop();
    this.container.remove();
  },

  /*
  Property: createMonth
    Creates a month object; including start/end dates and the Table object.

  Arguments:
    d - (Date) any date in the month
  */
  createMonth: function(d) {
    var month = {date: d};

    // currDate = the date that we use as we step through the month
    var currDate = new Date(d);
    currDate.setDate(1);
    currDate.setHours(0,0,0,0);
    var currentDay = (currDate.getDay() - jsGlobalDayOffset + 7) % 7;
    
    var arr = [];
    var year = d.getFullYear();
    var currentMonth = d.getMonth();
    var now = new Date();
    var today = this.sameMonth(now,d) ? now.getDate() : -1;
    var selectedDay = -1;
    if (this.selectedDate && this.selectedDate.getMonth() == currentMonth)
      selectedDay = this.selectedDate.getDate();
    
    arr.push('<table cellspacing="0" cellpadding="0" border="0"><thead><tr><th class="caption" colspan="7">');
    arr.push(DATE_FORMAT_MMM_YYYY.replace(/MMM/,jsGlobalMonths[currentMonth]).replace(/YYYY/,year));
    arr.push('</th></tr><tr>');
    for (var i = 0; i < jsGlobalDaysShort.length; i++) {
      arr.push('<th>');
      arr.push(this.options.dayNames ? jsGlobalDaysAbbrev[i] : jsGlobalDaysShort[i]);
      arr.push('</th>');
    }
    arr.push('</tr></thead><tbody><tr>');
    
    // blanks at beginning of month
    for (var i = 0; i < currentDay; i++)
      arr.push('<td class="other">&nbsp;</td>')
  
    // days
    currentDay--;
    var day = 0;
    var numDays = daysInMonth[month.date.getMonth()];
    var numValidDays = numDays;
    while (day < numDays) {
      currentDay = (currentDay + 1) % 7;
      day++;
      currDate.setDate(day);
      var contents = day;
      var cname = null;
      var inRange = !(currDate < this.options.firstDate || currDate > this.options.lastDate);
      var isValid = !this.isInvalidDate(currDate);
      var link = "calendarSelect";
      
      // determine contents and classname
      if (this.options.formatter) {
        var cnc = this.options.formatter(currDate, inRange, isValid);
        cname = cnc.cname;
        contents = cnc.contents;
        link = $pick(cnc.link, link);
      }
      else if (!isValid) {
        cname = this.options.invalidClass;
        contents = 'X';
      }
      else if (day == today) {
        if (day == selectedDay) {
          cname = this.options.todayClass + " " + this.options.selectedClass;
        }
        else {
          cname = this.options.todayClass;
        }
      }
      else if (day == selectedDay) {
        cname = this.options.selectedClass;
      }
      
      if (currentDay == 0) {
        arr.push('</tr><tr>');
      }
      if (!inRange) {
        arr.push('<td class="');
        arr.push(cname || this.options.disabledClass);
        arr.push('">');
        arr.push(contents || day);
        arr.push("</td>");
      }
      else {
        if (cname) {
          arr.push('<td class="');
          arr.push(cname);
          arr.push('">');
        }
        else {
          arr.push('<td>');
        }
        
        if (isValid && this.options.useLinks && link) {
          arr.push('<a href="javascript:void(0);" onclick="');
          arr.push(link);
          arr.push('(event,');
          arr.push(year);
          arr.push(',');
          arr.push(currentMonth);
          arr.push(',');
          arr.push(day);
          arr.push(',this)">');
          arr.push(contents);
          arr.push('</a>');
        }
        else {
          arr.push(contents);
        }
        arr.push('</td>');
      }
    }
    
    // blanks at end of month
    while (++currentDay < 7)
      arr.push("<td class='other'>&nbsp;</td>")
  
    arr.push('</tr></tbody></table>');
    
    month.elmt = new Element('div', {'class': 'month'}).setHTML(arr.join(''));
    
    return month;
  },
  
  /**
   * Check if this is an invalid date given 'this.options.invalidDates'.
   */
  isInvalidDate:function(/* Date */ date)
  {
    var invalidDates = this.options.invalidDates;
    if (invalidDates == null) return false;
    
    for (x in invalidDates)
    {
      var invalid = invalidDates[x];
      
      //  if 'x' is a range
      if ($type(invalid) == 'array')
      {
         var start = invalid[0];
         var end = invalid[1];

         //  convert them to timstamps (if needed)
         if ($type(start) == 'date') start = start.getTime();
         if ($type(end) == 'date') end = end.getTime();
         
         //  if the date occurs in the range
         if ((start <= date.getTime()) && (end >= date.getTime()))
         {
             return true;
         }
      }
      
      //  else if 'invalid' is a date and they match
      else if (($type(invalid) == 'date') && (date == invalid)) return true;
      
      //  else if 'invalid' is a timestamp and they match
      else if (date == new Date(invalid)) return true;
    }
    return false;
  },

  /*
  Property: prev
    Moves the calendar back one month.
  */
  prev: function() {
    if (this.animating) return;
    var dc = this.options.dualCalendar;
    this.animating = true;
    
    //  calculate the prev month
    var d = new Date(this.currentMonth.date);
    var month = d.getMonth()-1;
    if(month < 0){
        month = month + 12;
        d.setFullYear(d.getFullYear() - 1);
    }
    var day = d.getDate();
    if (day > daysInMonth[month]) { day = daysInMonth[month]; }
    d.setMonth(month, day);
    
    //  grab the width pf the current month table
    var w = this.currentMonth.elmt.getCoordinates().width;

    //  create the new month table, offset it to its starting position (to prevent flicker)
    //  and inject it (we don't have the actual width of the new month table yet so assume
    //  it is about the size of the current month... should be good enough to eliminate
    //  the flicker).
    var m = this.createMonth(d);
    m.elmt.style.left = '-' + w + 'px';
    m.elmt.inject(this.container.getElement("." + this.options.controlsClass), 'after');
    
    //  grab the tables and slide them to the right with an animation
    var elmts = this.container.getElements('div.month');
    var opts = {'0':{left:[-w,0]},
                '1':{left:[0,w + this.options.offsetOther]}};
    if (dc) opts['2'] = {left:[w + this.options.offsetOther,w*2 + this.options.offsetOther]};
    
    var fx = new Fx.Elements(elmts, {
      onComplete: this.doneAnimating.bindAsEventListener(this, [this.nextMonth || this.currentMonth])
    });
    
    //  update the current and next month
    if (dc) this.nextMonth = this.currentMonth;
    this.currentMonth = m;
    
    //  update the state of the prev and next buttons
    this.updatePrevNext();

    //  start the animation
    fx.start(opts);
  },

  /*
  Property: next
    Moves the calendar forward one month.
  */
  next: function() {
    if (this.animating) return;
    var dc = this.options.dualCalendar;
    this.animating = true;
    
    //  calculate the next month
    var d = new Date(this.currentMonth.date);
    var month = d.getMonth() + (dc ? 2 : 1);
    if(month > 11){
        month = month - 12;
        d.setFullYear(d.getFullYear() + 1);
    }
    var day = d.getDate();
    if (day > daysInMonth[month]) { day = daysInMonth[month]; }
    d.setMonth(month, day);
    
    //  grab the width pf the current month table
    var w = this.currentMonth.elmt.getCoordinates().width;
    
    //  grab the total width of the calendars (if it is a dual calendar)
    var totalWidth = w + (dc ? this.nextMonth.elmt.getCoordinates().width : 0)

    //  create the new month table, offset it to its starting position (to prevent flicker)
    //  and inject it
    var m = this.createMonth(d);
    m.elmt.style.left = totalWidth + 'px';
    m.elmt.injectInside(this.container);
    
    //  grab the tables and slide them to the left with an animation
    var elmts = this.container.getElements('div.month');
    var opts = {'0':{left:[0,-w]},
                '1':{left:[w + this.options.offsetOther,0]}};
    if (dc) opts['2'] = {left:[w*2 + this.options.offsetOther,w + this.options.offsetOther]};

    var fx = new Fx.Elements(elmts, {
      onComplete: this.doneAnimating.bindAsEventListener(this, [this.currentMonth])
    });

    //  update the current and next month
    if (dc)
    {
        this.currentMonth = this.nextMonth;
        this.nextMonth = m;
    }
    else this.currentMonth = m;
    
    //  update the state of the prev and next buttons
    this.updatePrevNext();

    //  start the animation
    fx.start(opts);
  },

  /*
  Property: removeTable
    Removes the table from the container. Used by prev/next as a bound event listener for when
    the animation completes.

  Arguments:
    e - (event) the event object, unused
    t - (month object) the month to be removed
  */
  removeTable: function(e, t) {
    t.elmt.remove();
  },

  doneAnimating: function(e, t) {
    this.removeTable(e, t);
    this.animating = false;
  },

  /*
  Property: select
    Called when the user selects a date. Fires any onSelect events.

  Arguments:
    e - (event) the event object, unused
    d - (Date) the date the user selected
  */
  select: function(e, d) {
    this.selectedDate = d;
    this.fireEvent('onSelect', e);
  },

  /*
  Property: nearbyMonth
    Convenience method to get a month near a given month. Checks for boundary conditions.

  Arguments:
    month - (integer) starting month
    mod - (integer) amount to alter the number by (positive or negative)
  */
  nearbyMonth: function(month, mod) {
    var d = month + mod;
    if (d > 11) d -= 12;
    else if (d < 0) d += 12;
    return d;
  }
});
Calendar.implement(new Events, new Options);








var buildDate = function(cal) {
  var d = parseInt(cal.dayField.value.replace(/^0/,''));
  var m = cal.monthField.value.split(/\//);
  if (m.length != 2) return;
  var y = parseInt(m[1]);
  m = parseInt(m[0].replace(/^0/,''));
  cal.selectedDate = new Date(y,m-1,d);
  return d;
}

/*
Function: showCalendar
  Bound to a Calendar and called when the user requests the calendar. Sets the selected date
  and updates the calendar so it can't get out of sync with the form fields. Also uses the
  flyout to contain the calendar.
*/
var showCalendar = function(e) {
  currentCalendar = this;
  if (e) new Event(e).preventDefault();
  if (this.flyout.container && this.flyout.container.inDocument()) {
    return;
  }
  var d = buildDate(this);

  if (this.toggler && this.toggler.checked) {
    this.toggler.setProperty('checked', '');
    this.source.value = formatDate(d, this.selectedDate.getMonth(), this.selectedDate.getFullYear());
    var oC = (this.after || this.before).calendar;
    d = buildDate(oC);
    oC.source.value = formatDate(d, oC.selectedDate.getMonth(), oC.selectedDate.getFullYear());
  }

  this.update();
  this.currentMonth.elmt.setStyle('left', '0px');

  this.flyout.show();
  
  if (this.options.dualCalendar) {
    this.nextMonth.elmt.setStyle('left', this.currentMonth.elmt.getCoordinates().width + 'px');
  }
  window.calendar = this;
}

/*
Function: hideCalendar
  Bound to a Calendar and called when the user clicks anywhere on the document. Will remove the flyout if
  the click was anywhere outside of it.
*/
var hideCalendar = function(e) {
  if ((this.flyout.container == false) || !this.flyout.container.inDocument()) return;
  e = new Event(e).stop();
  if (this.source.contains(e)) return;
  if (this.icn && this.icn.contains(e)) return;
  if (this.flyout.container.contains(e) && !this.flyout.closeLink.contains(e)) return;
  // re-show the select fields
  if (window.ie6 && !window.lightbox) $$('select').setStyle('visibility', 'visible');
  this.flyout.remove();
}

var updateFields = function(cal, leaveSourceValue) {
  var m = cal.selectedDate.getMonth() + 1; if (m < 10) m = "0" + m;
  cal.dayField.value   = cal.selectedDate.getDate();
  cal.monthField.value = m + "/" + cal.selectedDate.getFullYear();
  if(leaveSourceValue === undefined || !leaveSourceValue)
  {
    cal.source.value   = formatDate(cal.selectedDate.getDate(), cal.selectedDate.getMonth(), cal.selectedDate.getFullYear());
  }
}

/*
Function: calendarSelect
  Bound to a Calendar and called when the user selects a date. Hides the flyout and updates the form.
*/
var calendarSelect = function(e,year,month,day) {
  currentCalendar.selectedDate = new Date();
  currentCalendar.selectedDate.setFullYear(year,month,day);
  new Event(e).stop();
  // re-show the select fields
  if (window.ie6) $$('select').setStyle('visibility', 'visible');
  currentCalendar.flyout.remove();
  updateFields(currentCalendar);
  if (currentCalendar.after && currentCalendar.after.calendar.selectedDate > currentCalendar.selectedDate) {
    var before = new Date(currentCalendar.selectedDate);
    before.setDate(before.getDate() - 1);
    currentCalendar.after.calendar.selectedDate = before;
    var leaveSourceValue = false;
    if(window.dateDefault && currentCalendar.after.calendar.source.value == window.dateDefault)
    {
      leaveSourceValue = true;
    }
    updateFields(currentCalendar.after.calendar, leaveSourceValue);
  }
  else if (currentCalendar.before && currentCalendar.before.calendar.selectedDate < currentCalendar.selectedDate) {
    var after = new Date(currentCalendar.selectedDate);
    after.setDate(after.getDate() + 1);
    currentCalendar.before.calendar.selectedDate = after;
    var leaveSourceValue = false;
    if(window.dateDefault && currentCalendar.before.calendar.source.value == window.dateDefault)
    {
      leaveSourceValue = true;
    }
    updateFields(currentCalendar.before.calendar, leaveSourceValue);
  }
}

var validateDate = function(cal) {
  //var d = cal.selectedDate.getDate();
  //var m = cal.selectedDate.getMonth() + 1;
  //var y = cal.selectedDate.getFullYear();
  var r = cal.source.value.match(DATE_FORMAT.pattern);
  if (r) {
    var nd = parseInt(r[DATE_FORMAT.date].replace(/^0/,''));
    var nm = parseInt(r[DATE_FORMAT.month].replace(/^0/,''));
    var ny = parseInt(r[DATE_FORMAT.year].replace(/^0/,''));
    //if (d != nd || m != nm || y != ny) {
    if (nd > 0 && nd < 32 && nm > 0 && nm < 13) {
      if (nd < 10) nd = '0' + nd;
      if (nm < 10) nm = '0' + nm;
      if (ny < 100) ny += 2000;
      cal.dayField.value = nd;
      cal.monthField.value = nm + "/" + ny;
      buildDate(cal);
      if (cal.selectedDate.getTime() < cal.options.firstDate.getTime() || cal.selectedDate.getTime() > cal.options.lastDate.getTime())
        return sInvalidDates; // date out of range
    }
    else { return sInvalidDates; } // number out of range
  }
  else { return sInvalidDates; } // invalid format
  return null;
}

var validateDates = function(e, options) {
  // doesn't have a calendar, nevermind...
  if (!this.checkIn || !this.checkOut) return true;
  // never used the calendar, assume defaults are OK
  if (!this.checkIn.calendar || !this.checkOut.calendar) return true;
  if (this.searchAll && this.searchAll.checked) return true; // any date
  
  options = $merge({
  	'allowSameDay': false,
	'oneWay': false
  }, options);

  if(this.oneWay && this.oneWay.checked)
  {
  	options['oneWay'] = true;
  }

  var valid = true;
  var msg;

  if (options['oneWay']) {
	if ((msg = validateDate(this.checkIn.calendar)) != null) {
  		valid = false;
  		this.getElement('span.error_msg').setContent(msg).show();
  	}
  }
  else
  {
  if ((msg = validateDate(this.checkIn.calendar)) != null || (msg = validateDate(this.checkOut.calendar)) != null) {
    valid = false;
    this.getElement('span.error_msg').setContent(msg).show();
  }
  	else
  		if (!(this.checkOut.calendar.selectedDate >= this.checkIn.calendar.selectedDate ||
  		((this.checkOut.calendar.selectedDate == this.checkIn.calendar.selectedDate) && options['allowSameDay']))) {
    valid = false;
    this.getElement('span.error_msg').setContent(sInvalidDates).show();
  }
  }
  if (!valid && e) new Event(e).stop();
  return valid;
}

rules['#HAC_FORM'] = function(elmt) {elmt.addEvent('submit', validateDates.bindAsEventListener(elmt));}
rules['#FLIGHT_FORM'] = function(elmt) {elmt.addEvent('submit', validateDates.bindAsEventListener(elmt));}
rules['#VRAC_FORM'] = function(elmt) {elmt.addEvent('submit', validateDates.bindAsEventListener(elmt));}

rules['#HotelDateSearch span.calCreate'] = function(elmt){ 
	if (!pageServlet || pageServlet!="Hotel_Review")
	{
      (ajaxRules['#HotelDateSearch_CR span.cal']).delay(125, null, [elmt]);
	}
}

ajaxRules['#HotelDateSearch_CR span.cal'] = function(elmt) {
  if(typeof createCalendar != "undefined") 
  { 
    createCalendar(elmt); 
  }
}

ajaxRules['#HotelDateSearch_CR'] = function(elmt) {
  var inPage = $('HotelDateSearch');
  elmt.getElement('.chk-in input.day').value    = inPage.getElement('.chk-in input.day').getValue();
  elmt.getElement('.chk-in input.month').value  = inPage.getElement('.chk-in input.month').getValue();
  elmt.getElement('.chk-ot input.day').value    = inPage.getElement('.chk-ot input.day').getValue();
  elmt.getElement('.chk-ot input.month').value  = inPage.getElement('.chk-ot input.month').getValue();

  var val = inPage.getElement('.adults select').getValue();
  var sel = elmt.getElement('.adults select');
  $each(sel.options, function(option){
    if ($pick(option.value, option.text) == val) option.selected = "selected";
  });
  var chkIn = elmt.getElement('.chk-in input[type=text]');
  var chkOt = elmt.getElement('.chk-ot input[type=text]');
  if(!chkIn.calendar || !chkIn.calendar.selectedDate)
  {
    chkIn.calendar.dayField.value   = "";
    chkIn.calendar.monthField.value = "";
    chkIn.calendar.source.value     = inPage.getElement('.chk-in input#checkIn').getValue();
    
    chkOt.calendar.dayField.value   = "";
    chkOt.calendar.monthField.value = "";
    chkOt.calendar.source.value     = inPage.getElement('.chk-ot input#checkOut').getValue();
  }
  else
  {
    buildDate(chkIn.calendar);
    buildDate(chkOt.calendar);
    updateFields(chkIn.calendar);
    updateFields(chkOt.calendar);
  }  
}

var createCalendar = function(elmt) {
  var end;
  if (elmt.lastDate) {
    end = elmt.lastDate;
  } else {
    end = new Date();
    end.setYear(end.getFullYear()+1);
    end.setMonth(end.getMonth()-1, 1);
  }
  var src = elmt.getElement('input[type=text]');
  var cal = new Calendar(src, {
    firstDate: new Date(),
    lastDate: end,
    showOtherDates: false,
    dualCalendar: true,
    onSelect: calendarSelect,
    show: showCalendar,
    hide: hideCalendar,
    hideOnDocClick:true,
    weekStart: jsGlobalDayOffset
  });
  cal.dayField = getChildByClass(elmt,"day");
  cal.monthField = getChildByClass(elmt,"month");
  cal.flyout = new Flyout(cal.source, {offsets: {x:0, y:28}, showArrow: false, autoSpawn: false, adjustable: true, adjusted: {x:0, y:10}}, cal.container);
  cal.wrapper = elmt;
  cal.toggler = $(src.form.searchAll); // make sure it is a wrapped element on IE
  var icn = elmt.getElement('.icn');
  cal.icn = icn && icn.addEvent('click', showCalendar.bindWithEvent(cal));
  if (src.id == 'checkIn')    cal.before = src.form.checkOut; // use name instead of byID (multiple forms)
  else if (src.id == 'qcCheckIn')  cal.before = $('qcCheckOut');
  else if (src.id == 'checkOut')   cal.after = src.form.checkIn;
  else if (src.id == 'qcCheckOut') cal.after = $('qcCheckIn');
  else if (src.id == 'earliestDeparture') cal.before = src.form.latestReturn;
  else if (src.id == 'latestReturn') cal.after = src.form.earliestDeparture;
  src.calendar = cal;

  var other = cal.before || cal.after;
  if (other && !other.calendar)
    toCalendar = deferCalPost($(other).getParent());

  buildDate(cal);
  return cal;
}

var deferCalPost = function(elmt) {
  var input = elmt.getElement('input[type=text]');
  input.removeEvent('focus', elmt.myDeferFn);
  input.removeEvent('click', elmt.myDeferFn);
  if (elmt.icn) elmt.icn.removeEvent('click', elmt.myDeferFn);
  elmt.myDeferFn = null;
  var cal = createCalendar(elmt);
  return cal;
}

var deferCal = function(e) {
  fromCalendar = deferCalPost(this)
  showCalendar.apply(fromCalendar, [e]);
}

var initCalFunc = function(elmt) {
  elmt.myDeferFn = deferCal.bindAsEventListener(elmt);
  var input = elmt.getElement('input[type=text]');
  input.addEvent('focus', elmt.myDeferFn);
  input.addEvent('click', elmt.myDeferFn);
  elmt.icn = elmt.getElement('.icn');
  if (elmt.icn) elmt.icn.addEvent('click', elmt.myDeferFn);
}
rules['#BODYCON span.cal, #HOMEPAGE span.cal, #MPU span.cal'] = initCalFunc;
ajaxRules['#VRAC_FORM span.cal'] = initCalFunc;
ajaxRules['#HAC_FORM_NARROW span.cal'] = initCalFunc;
ajaxRules['#PHAC_LB span.cal'] = initCalFunc;

var checkboxCal = function(event,element) {
	var elmt;
	if (element)
	{
		elmt = element;
	} else {		
		var e = new Event(event || window.event);
		elmt = e.target;
	}
	if (elmt.checked) {
	      $(elmt.form).getElements('.cal input[type=text]').each(function(e){
	        e.value = JS_DateFormat;
	      });
	}
	else {
	     $(elmt.form).getElements('.cal input[type=text]').each(function(e){
	        if (!e.calendar) deferCalPost(e.getParent('span.cal'));
	        var d = buildDate(e.calendar);
	        e.calendar.source.value = formatDate(d, e.calendar.selectedDate.getMonth(), e.calendar.selectedDate.getFullYear());
	 });
	 }
}

function calendarSearchAll(elmt)
{
  elmt.addEvent('click', checkboxCal);
  checkboxCal(null,elmt);
}

// HAC calendar
rules['#searchAll'] = function(elmt) {
  calendarSearchAll(elmt);
}

rules['#HAC_FORM_NARROW .checkbox'] = function(elmt) {
  calendarSearchAll(elmt);
}

/*
Class: Lightbox
  If left and top options are not specified, lightbox is position in the center of the screen, which
  is the default behavior.

Arguments:
  ctrl - required, if a string, content is set to string, if an A element content is loaded from href,
         and element is set to trigger lightbox on click
	options - optional, see options below.

Options:
  left - (integer) left position (default: -1)
  top - (integer) top position (default: -1)
  evalScripts - (boolean) true if scripts should be interepted in AJAX content (default: false)
  applyBehavior - (boolean) true if behavior should be applied to AJAX content (default: true)
  positionAbsolute - (boolean) true if position is relative to page, false if screen (default: false)
  contentId - (string) id of content element (default: lbContent)
  loadingMessage - (string) contents when loading via AJAX (default: <p>Loading</p>)
  source - (string) url to load content from (default: null)
  padLeft, padTop: (int) - displacement of flyout from top left of the ctrl trigger that opened it
    only applied if the ctrl trigger has the class 'relPos'
  flyoutToClose: (Flyout) - closes a flyout on lightbox show, used for special case where a flyout
    cannot be given global reference window.flyout due to a calendar flyout being used with it
  arrow: (boolean) - display an arrow pointer on the left side of the lightbox, usually points to the
    ctrl that opened the lightbox
*/

var Lightbox = new Class({

  options: {
    left: -1,
    top: -1,
    evalScripts: false,
    applyBehavior: true,
    positionAbsolute: false,
    contentId: 'lbContent',
    loadingMessage: '<p>Loading</p>',
    source: null,
    cancelLoad: false,
    loadMsgClass: '',
    cacheContent: false,
    autoAdjust: false,
    padLeft: 0,
    padTop: 0,
    flyoutToClose: null,
    arrow: false,
    centerOnScreen: true
  },

  initialize: function(ctrl, options) {
    this.setOptions(options);
    if (typeof(ctrl) == "string") {
      this.content = ctrl;
    }
    else {
      if (ctrl.getTag() == "a") this.options.source = ctrl.href;
      this.trigger = ctrl;
      ctrl.addEvent('click', this.activate.bindAsEventListener(this));
    }
  },
  
  // Turn everything on - mainly the IE fixes
  activate: function(e){
    if (e) new Event(e).stop();// can be activated programatically
    if (this.options.flyoutToClose) {
      this.options.flyoutToClose.hide();
    }
    if ( ! $('overlay') ) this.addLightboxMarkup();
    if (window.ie6){
      $$('select').setStyle('visibility', 'hidden');
    }
    $('overlay').setStyle('height', getScrollHeight() + "px");
    this.displayLightbox("block");
    window.lightbox = this;
    this.adjustPositioning();
    this.fireEvent('onActivate');
    return this;
  },
  
  positionLightbox: function(widthDiff, heightDiff){
    if(typeof this.trigger != "undefined" && this.trigger.hasClass('relPos'))
    {
      if(!widthDiff) widthDiff = 0;
      if(!heightDiff) heightDiff = 0;
      this.lPos = this.trigger.getLeft() - window.getScrollLeft() + this.options.padLeft - widthDiff;
      this.tPos = this.trigger.getTop() - window.getScrollTop() + this.options.padTop - heightDiff;
    }
  },
	
  // Add in markup necessary to make this work. Basically two divs:
  // Overlay holds the shadow
  // Lightbox is the centered square that the content is put into.
  addLightboxMarkup: function() {
    new Element('div', {id: 'overlay'}).injectInside(document.body);
    var lb = new Element('div', {id: 'lightbox', 'class': 'loading'}).injectInside(document.body);
    var div = new Element('div', {id: 'lbLoadMessage'}).setContent(this.options.loadingMessage).injectInside(lb);
    var close = new Element('div', {'id': 'lb_cancel', 'class': 'close'}).injectInside(div);
    new Element('span', {'class': 'cnrL'}).injectInside(close);
    new Element('span', {'class': 'cnrB'}).injectInside(close);
    new Element('span', {'class': 'cnrBL'}).injectInside(close);
    new Element('a', {'id': 'lb_cancelLink', 'class':'lbAction', rel:'deactivate', href:''}).setContent(lang_Close).injectInside(close)
      .addEvent('click', function(e) {
        if (window.lightbox) window.lightbox.cancel(e);
      });
  },

  displayLightbox: function(display){
    $('overlay').setStyle('display', display);
    $('lightbox').setStyle('display', display);
    if(display != 'none') this.loadInfo();
    return this;
  },
	
  loadInfo: function() {
    if (this.content) return this.processInfo(this.content);
    if (!this.requested) {
      this.requested = true;
      var myAjax = new Ajax(this.options.source, {
        onComplete: this.handleResponse.bindAsEventListener(this),
        evalScripts: this.options.evalScripts
      }).request();
    }
    $('lightbox').removeClass('done').addClass('loading').centerOnScreen();
    $('lbLoadMessage').setProperty('class', this.options.loadMsgClass);
    $('lb_cancel').setStyle('display', this.options.cancelLoad ? 'block' : 'none');
    return this;
  },
  
  cancel: function(e) {
    this.requestCancelled = true;
    this.deactivate(e);
  },
  
  handleResponse: function(response){
    this.requested = false;
    if (this.options.cacheContent) this.content = response;
    if (!this.requestCancelled) this.processInfo(response);
  },
	
  adjustPositioning: function(){
    if(typeof this.trigger != "undefined")
    {
      var heightDiff = 0;
      var widthDiff = 0;
      
      //Update bottom edge case
      var lb_bottom_pos = this.trigger.getTop() - window.getScrollTop() + this.options.padTop + $('lightbox').getCoordinates().height;
      if( $(window).getHeight() < lb_bottom_pos )
      {
        var heightDiffPadding = 2;
        heightDiff = lb_bottom_pos - $(window).getHeight() + heightDiffPadding;
        var arrowImg = $(this.options.contentId).getElement('img.arrow');
        if(this.options.arrow && $(this.options.contentId))
        {
          if(arrowImg)
          {
            arrowImg.setStyle('top', arrowImg.getStyle('top').toInt() + heightDiff );
            if( this.trigger.getTop() - window.getScrollTop() + 20 > $(window).getHeight() )
            {
              arrowImg.setStyle('top', arrowImg.getStyle('top').toInt() - 15 );
            }
          }
        }
      }
      
      //Update right screen case
      var lb_right_pos = this.trigger.getLeft() - window.getScrollLeft() + this.options.padLeft + $('lightbox').getCoordinates().width;
      if( $(window).getWidth() < lb_right_pos)
      {
        var widthDiffPadding = 15;
        widthDiff = $('lightbox').getCoordinates().width + this.options.padLeft + widthDiffPadding;
        if(this.options.arrow && $(this.options.contentId))
        {
          var arrowImg = $(this.options.contentId).getElement('img.arrow');
          if(arrowImg && $(arrowImg).getCoordinates().left < $('lightbox').getCoordinates().left)
          {
            var widthArrowPadding = 3;
            arrowImg.setStyle('left', arrowImg.getStyle('left').toInt() + $('lightbox').getCoordinates().width + widthArrowPadding);
            arrowImg.src ='/img2/checkrates/pointer_flip.gif';
          }  
        }
           
      }
      
      //Update top screen case
      var lb_top_pos = this.trigger.getTop() - window.getScrollTop() + this.options.padTop;
      if( 0 > lb_top_pos )
      {
        var heightDiffPadding = 2;
        heightDiff = lb_top_pos + heightDiffPadding;
        
        var arrowImg = $(this.options.contentId).getElement('img.arrow');
        if(arrowImg)
        {
          arrowImg.setStyle('top', arrowImg.getStyle('top').toInt() + heightDiff );
          if( this.trigger.getTop() - window.getScrollTop() - 30 < 0 )
          {
            arrowImg.setStyle('top', arrowImg.getStyle('top').toInt() + 30 );
          }
        }
      }
      
      this.positionLightbox(widthDiff, heightDiff);
    }
  },
	
  processInfo: function(content){
    this.info = new Element('div', {id: this.options.contentId})

    // rounded corners
    this.top  = new Element('div', {'class': 'cnrR5 top'}).injectInside(this.info);
    this.tl   = new Element('div', {'class': 'lft'}).setContent("<!--Lft Corner-->").injectInside(this.top);
    this.tm   = new Element('div', {'class': 'mid'}).setContent("<!--Mid Border-->").injectInside(this.top);
    this.tr   = new Element('div', {'class': 'rgt'}).setContent("<!--Rgt Corner-->").injectInside(this.top);
    this.btm  = new Element('div', {'class': 'cnrR5 btm'}).injectInside(this.info);
    this.bl   = new Element('div', {'class': 'lft'}).setContent("<!--Lft Corner-->").injectInside(this.btm);
    this.bm   = new Element('div', {'class': 'mid'}).setContent("<!--Mid Border-->").injectInside(this.btm);
    this.br   = new Element('div', {'class': 'rgt'}).setContent("<!--Rgt Corner-->").injectInside(this.btm);

    var div   = new Element('div', {'class': 'close'}).injectInside(this.info);
    new Element('span', {'class': 'cnrL'}).injectInside(div);
    new Element('span', {'class': 'cnrB'}).injectInside(div);
    new Element('span', {'class': 'cnrBL'}).injectInside(div);
    
    this.closeLink  = new Element('a', {'id':'lb_close', 'class':'lbAction', rel:'deactivate', href:''}).setContent(lang_Close).injectInside(div);

    this.inner = new Element('div', {'class': 'inner'}).setContent(content).injectInside(this.info);
    if(this.options.arrow)
    {
      var arrow = new Element('img', {'class': 'arrow', 'src': 'http://cdn.tripadvisor.com/img2/checkrates/pointer.gif'}); 
      arrow.setStyles({
        'position': 'absolute',
        'left': '-8px',
        'top': '54px'
      });
      arrow.injectTop(this.inner);
    }
    this.info.injectBefore($('lbLoadMessage'));
    
    var lb = $('lightbox').setProperty('class', 'done');
    if (this.options.autoAdjust) this.adjustPositioning();
    
    if (this.options.centerOnScreen) lb.centerOnScreen();
    else if (typeof this.lPos == "undefined" || typeof this.tPos == "undefined") lb.positionOnScreen(this.options.left, this.options.top);
    else if (this.options.positionAbsolute) lb.setStyles({left: this.lPos, top: this.tPos});
    else lb.positionOnScreen(this.lPos, this.tPos);
    
    this.positionCorners();
		this.actions();			
    return this;
  },

  readjust: function() {
    var lb = $('lightbox');
    if(this.options.autoAdjust) this.adjustPositioning();
    if (this.options.centerOnScreen) lb.centerOnScreen();
    else if (this.options.positionAbsolute) lb.setStyles({left: this.lPos, top: this.tPos});
    else lb.positionOnScreen(this.lPos, this.tPos);
  },

  positionCorners: function() {
    var c = this.info.getCoordinates();
    this.top.setStyle('width', c.width + 'px');
    this.btm.setStyle('width', c.width + 'px');
    var tm = c.width - this.tl.getCoordinates().width - this.tr.getCoordinates().width;
    var bm = c.width - this.bl.getCoordinates().width - this.br.getCoordinates().width;
    this.tm.setStyle('width', (tm > 0 ? tm : 0) + "px");
    this.bm.setStyle('width', (bm > 0 ? bm : 0) + "px");
  },
	
	// Search through new links within the lightbox, and attach click event
	actions: function(){
		this.info.getElements('a.lbAction').each(function(v){
			v.addEvent('click', this[v.rel].bindAsEventListener(this));
		}, this);
    if (this.options.applyBehavior) window.behavior.apply(this.info);
	},

  // Example of creating your own functionality once lightbox is initiated
  insert: function(e){
    if (e) new Event(e).stop();
    link = Event.element(e).parentNode;
    Element.remove(this.info);
    var myAjax = new Ajax(link.href,
      {onComplete: this.processInfo.bindAsEventListener(this)}
    ).request();
    return this;
  },

  // Example of creating your own functionality once lightbox is initiated
  deactivate: function(e){
    if (e) new Event(e).stop();
    if (this.info && !this.info.inDocument()) return false;
    if (this.info) Element.remove(this.info);
    if (window.ie) $$('select').setStyle('visibility', 'visible');
    if (window.flyout) window.flyout.hide();
    this.displayLightbox("none");
    window.lightbox = null;
    this.fireEvent('onDeactivate', this.content);
    return this;
  },
  
  // Example of creating your own functionality once lightbox is initiated
  // close and continue to link (return true)
  autoClose: function(e){
   if (window.ie) $$('select').setStyle('visibility', 'visible');
   this.displayLightbox("none");
   window.lightbox = null;
   return true;
  }
  
});
Lightbox.implement(new Options, new Events);

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

//pulled from lib/fbconnect.js for inclusion in tripadvisor.js
/*
 * Copyright (c) 2008 Aza Raskin (http://azarask.in/blog)
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

var SocialHistory = function() {

  // associative array of sites we're interested in
  // { site: [variations1, variation2...], site: [ ... }
  var sites = {
    "f": ["http://www.facebook.com/", "https://login.facebook.com/login.php", "http://www.facebook.com/home.php"]
    //"f": ["http://www.facebook.com/"]
  };

  var visited = {};

  function getStyle(el, scopeDoc,styleProp) {
    if (el.currentStyle)
      var y = el.currentStyle[styleProp];
    else if (window.getComputedStyle)
      var y = scopeDoc.defaultView.getComputedStyle(el,null).getPropertyValue(styleProp);
    return y;
  }
  
  function remove( el ) {
    el.parentNode.removeChild( el );
  }
  
  // Code inspired by:
  // bindzus.wordpress.com/2007/12/24/adding-dynamic-contents-to-iframes
  function createIframe() {
    var iframe = document.createElement("iframe");
    iframe.style.position   = "absolute";
    iframe.style.visibility = "hidden";

    document.body.appendChild(iframe);

    // Firefox, Opera
    if (iframe.contentDocument)   iframe.doc = iframe.contentDocument;
    // Internet Explorer
    else if(iframe.contentWindow) iframe.doc = iframe.contentWindow.document;

    // Magic: Force creation of the body (which is null by default in IE).
    // Also force the styles of visited/not-visted links.
    iframe.doc.open();
  	iframe.doc.write('<style>');
  	iframe.doc.write("a{color: #000000; display:none;}");  	
  	iframe.doc.write("a:visited {color: #FF0000; display:inline;}");  	
  	iframe.doc.write('</style>');
    iframe.doc.close();
    
    // Return the iframe: iframe.doc contains the iframe.
    return iframe;
  }  

  // create the iframe, insert links, check them, then remove the iframe
  var iframe = createIframe();

  function embedLinkInIframe( href, text ) {
    var a = iframe.doc.createElement("a");
    a.href      = href;
    a.innerHTML = site;
    iframe.doc.body.appendChild( a );
  }

  // add links to each site
  for (var site in sites) {
    var urls = sites[site];
    for( var i=0; i<urls.length; i++ ) {
      // You have to create elements in the scope of the iframe for IE.
      embedLinkInIframe( urls[i], site );
      
      // Automatically try variations of the URLS with and without the "www"
      if( urls[i].match(/www\./) ){
        var sansWWW = urls[i].replace(/www\./, "");
        embedLinkInIframe( sansWWW, site );
      } else {
        // 2 = 1 for length of string + 1 for slice offset
        var httpLen = urls[i].indexOf("//") + 2;
        var withWWW = urls[i].substring(0, httpLen ) + "www." + urls[i].substring( httpLen );
        embedLinkInIframe( withWWW, site );
      }
    }
  }
    
  var links = iframe.doc.body.childNodes;
  for( var i=0; i<links.length; i++) {
    // Handle both Firefox/Safari, and IE (respectively)
    var displayValue = getStyle(links[i], iframe.doc, "display");
    var didVisit = displayValue != "none";
      
    if( didVisit ){
      visited[ links[i].innerHTML ] = true;
    }
  }

  // done; remove the iframe
  remove( iframe );
  
  return new (function(){
    var usedSites = [];
    for( var site in visited ){
      usedSites.push( site );
    }
    
    // Return an array of visited sites.
    this.visitedSites = function() {
      return usedSites;
    }
    
    // Return true/false. If we didn't check the site, return -1.
    this.doesVisit = function( site ) {
      if( typeof( sites[site] ) == "undefined" )
        return -1;
      return typeof( visited[site] ) != "undefined";
    }
    
    var checkedSites = [];
    for( var site in sites ){
      checkedSites.push( site );
    }
    // Return a list of the sites checked.
    this.checkedSites = function(){
      return checkedSites;
    }
  })();
}

/*
Looks to see if the browser has been to facebook and adjusts the
hidden field appropriately.
*/
function sniffFacebook() {
  var been = false;
  try {
    var sl = SocialHistory();
    var list = sl.visitedSites();
    if (list[0] == 'f') {
      been = true;
    }
  }
  catch(e) {
  }
  return been;
}
/*
Script: trcore.js
    Definitions used by legacy components on fully redesigned pages. Put things here instead
    of tripcompat.js for things used by components on both tweaked and fully redesigned pages
*/

function registerOnLoad(fn) {
  window.addEvent('load', fn);
}
function registerOnUnload(fn) {
  window.addEvent('unload', fn);
}

//func: getScrollOffset
function getScrollOffset()
{
  return [ window.getScrollLeft(), window.getScrollTop() ];
}

function isIn(eventPos, ele, bounds)
{
  var off = getScrollOffset();

  ele = $(ele);
  var pos = findPos(ele);
  // calculate element bounts
  var l = pos[0] - off[0];
  var t = pos[1] - off[1];
  var r = l + ele.clientWidth;
  var b = t + ele.clientHeight;

  if (bounds) {
    if (typeof(bounds) == "number") {
      l = l - bounds;
      t = t - bounds;
      r = r + bounds;
      b = b + bounds;
    }
    else if (bounds instanceof Array && (bounds.length == 2 || bounds.length == 4)) {
      t = t - bounds[0];
      r = r + bounds[1];
      l = l - (bounds.length == 4 ? bounds[3] : bounds[1]);
      b = b + (bounds.length == 4 ? bounds[2] : bounds[0]);
    }
  }

  return (eventPos[0] >= l && eventPos[0] <= r && eventPos[1] >= t && eventPos[1] <= b);
}

function setDetails(event, title, category, space) {
  new Event(event).stop();
  $('title').value = title;
  $('category').value = category;
  $('space').value = space;
  $('newPage').submit();
}

function setOneTimeCookie(key,value)
{
  Cookie.set(key, value, {domain: cookieDomain, time: 5});
  return true;
}

/**
 * Element.getElement() is slow on IE. So, mimic the most common use case with simpler, faster code.
 */
var getChildByClass = function(node,className,tagName) {
  if (!className || className.length == 0) {
    if (tagName == node.tagName)
      return node;
  }
  else if (node.className && (!tagName || tagName == node.tagName)) {
    var pos = -1;
    do
    {
      pos = node.className.indexOf(className,pos+1);
      if (pos >= 0 && (pos == 0 || node.className.charCodeAt(pos-1) == 32) && (pos+className.length == node.className.length || node.className.charCodeAt(pos+className.length) == 32))
        return node;
    } while (pos >= 0);
  }
  for (var i = 0; i < node.childNodes.length; i++) {
    var result = getChildByClass(node.childNodes[i],className,tagName);
    if (result)
      return result;
  }
  return null;
}
