
RessourcesTextes.add([["bab.nombre_activites_genre_region_rech","{3}{0}{4} événement(s) de type {3}«{1}»{4} dans la région {3}«{2}»{4} correspond(ent) à {3}«{5}»{4}."],["bab.nombre_activites_genre_pays_rech","{3}{0}{4} événement(s) de type {3}«{1}»{4} dans le pays {3}«{2}»{4} correspond(ent) à {3}«{5}»{4}."],["bab.nombre_activites_genre_rech","{2}{0}{3} événement(s) de type {2}«{1}»{3} correspond(ent) à {2}«{4}»{3}."],["bab.nombre_activites_region_rech","{2}{0}{3} événement(s) dans la région {2}«{1}»{3} correspond(ent) à {2}«{4}»{3}."],["bab.nombre_activites_pays_rech","{2}{0}{3} événement(s) dans le pays {2}«{1}»{3} correspond(ent) à {2}«{4}»{3}."],["bab.nombre_activites_rech","{1}{0}{2} événement(s) classé(s) dans {1} tous les types{2} et {1}toutes les régions{2} correspond(ent) à {1}«{3}»{2}."],["bab.nombre_activites_genre_pays","{3}{0}{4} événement(s) de type {3}«{1}»{4} dans le pays {3}«{2}»{4}."],["bab.nombre_activites_pays","{2}{0}{3} événement(s) dans le pays {2}«{1}»{3}."],["bab.voirevent_site_web","Voir le site Web de l'événement"],["mot.adm_js_calendrier_erreur_implantation","Vous devez implémenter une version spécifique au site de chargerMois..."],["bab.image_message","Joignez une image représentative de l’événement."],["bab.occev1","Sélectionnez l'occurrence de l'événement"],["bab.dateunique_message_1","Sélectionnez la date de l’événement à l’aide du petit calendrier."],["bab.heure_de_message_1","Saisissez une heure valide pour le début de l'événement (ex : 9:00)."],["bab.heure_a_message","Saisissez une heure valide pour la fin de l'événement (ex : 13:00)."],["bab.date_du_message","Sélectionnez les dates de l’événement à l’aide du petit calendrier. Vous pouvez indiquer plusieurs dates séparées ou un intervalle de temps continu."],["bab.typecout1_message","Indiquez si l’événement est gratuit. Sinon, sélectionnez « Autre »."],["bab.erreur_adresse_internet","L'adresse Internet que vous avez inscrite ne semble pas valide."],["bab.erreur_frequence_evenement","Sélectionnez les dates de l’événement à l’aide du petit calendrier. S’il se déroule pendant plusieurs jours, sélectionnez les dates de début et de fin pour indiquer l’intervalle."],["bab.erreur_selection_date_evenement","Sélectionnez la date de l’événement à l’aide du petit calendrier."],["bab.erreur_serie_dates","Vous devez entrer au moins une série de dates."],["bab.erreur_selection_cout_evenement","Indiquez si l’événement est gratuit. Sinon, sélectionnez « Autre »."],["bab.erreur_age_maximal_enfant","Inscrivez l'âge maximum pour bénéficier du tarif pour enfant."],["bab.erreur_cout_enfant","Vous devez déterminer quel est le prix d'entrée pour un enfant."],["bab.rendre_visible_message","Cochez cette case pour que vos informations (courriel et numéro de téléphone) soient affichées sur le babillard."],["bab.adresse_introuvable","Nous n'avons pas trouvé cette adresse."],["bab.x_results","{0} résultats"],["bab.pas_google_map","Ne pas utiliser l'adresse validée par Google Map."],["bab.adresse_not_implemented","Désolé, la validation de votre adresse par Google n'est pas disponible sur votre navigateur. Nous vous suggérons de le mettre à jour."],["bab.cont_sans_val","Continuer sans validé votre adresse."],["bab.mois_janvier","janvier"],["bab.mois_fevrier","février"],["bab.mois_mars","mars"],["bab.mois_avril","avril"],["bab.mois_mai","mai"],["bab.mois_juin","juin"],["bab.mois_juillet","juillet"],["bab.mois_septembre","septembre"],["bab.mois_octobre","octobre"],["bab.mois_novembre","novembre"],["bab.mois_decembre","décembre"],["bab.jour_dimanche","dimanche"],["bab.jour_lundi","lundi"],["bab.jour_mardi","mardi"],["bab.jour_mercredi","mercredi"],["bab.jour_jeudi","jeudi"],["bab.jour_vendredi","vendredi"],["bab.jour_samedi","samedi"],["bab.js_modifier","Modifier"],["bab.js_effacer","Effacer"],["bab.erreur_date_debut_evenement","La date du début de l'événement doit être antérieure à la date de fin."],["bab.erreur_saisie_date_courante","Il vous faut d'abord saisir correctement la série de date courante avant d'en ajouter une autre."],["bab.erreur_conflit","Les dates entrées entrent en conflit avec d'autres dates."]]);

/*
Copyright (c) 2008, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://developer.yahoo.net/yui/license.txt
version: 2.5.1
*/
if(typeof YAHOO=="undefined"||!YAHOO){var YAHOO={};}YAHOO.namespace=function(){var A=arguments,E=null,C,B,D;for(C=0;C<A.length;C=C+1){D=A[C].split(".");E=YAHOO;for(B=(D[0]=="YAHOO")?1:0;B<D.length;B=B+1){E[D[B]]=E[D[B]]||{};E=E[D[B]];}}return E;};YAHOO.log=function(D,A,C){var B=YAHOO.widget.Logger;if(B&&B.log){return B.log(D,A,C);}else{return false;}};YAHOO.register=function(A,E,D){var I=YAHOO.env.modules;if(!I[A]){I[A]={versions:[],builds:[]};}var B=I[A],H=D.version,G=D.build,F=YAHOO.env.listeners;B.name=A;B.version=H;B.build=G;B.versions.push(H);B.builds.push(G);B.mainClass=E;for(var C=0;C<F.length;C=C+1){F[C](B);}if(E){E.VERSION=H;E.BUILD=G;}else{YAHOO.log("mainClass is undefined for module "+A,"warn");}};YAHOO.env=YAHOO.env||{modules:[],listeners:[]};YAHOO.env.getVersion=function(A){return YAHOO.env.modules[A]||null;};YAHOO.env.ua=function(){var C={ie:0,opera:0,gecko:0,webkit:0,mobile:null,air:0};var B=navigator.userAgent,A;if((/KHTML/).test(B)){C.webkit=1;}A=B.match(/AppleWebKit\/([^\s]*)/);if(A&&A[1]){C.webkit=parseFloat(A[1]);if(/ Mobile\//.test(B)){C.mobile="Apple";}else{A=B.match(/NokiaN[^\/]*/);if(A){C.mobile=A[0];}}A=B.match(/AdobeAIR\/([^\s]*)/);if(A){C.air=A[0];}}if(!C.webkit){A=B.match(/Opera[\s\/]([^\s]*)/);if(A&&A[1]){C.opera=parseFloat(A[1]);A=B.match(/Opera Mini[^;]*/);if(A){C.mobile=A[0];}}else{A=B.match(/MSIE\s([^;]*)/);if(A&&A[1]){C.ie=parseFloat(A[1]);}else{A=B.match(/Gecko\/([^\s]*)/);if(A){C.gecko=1;A=B.match(/rv:([^\s\)]*)/);if(A&&A[1]){C.gecko=parseFloat(A[1]);}}}}}return C;}();(function(){YAHOO.namespace("util","widget","example");if("undefined"!==typeof YAHOO_config){var B=YAHOO_config.listener,A=YAHOO.env.listeners,D=true,C;if(B){for(C=0;C<A.length;C=C+1){if(A[C]==B){D=false;break;}}if(D){A.push(B);}}}})();YAHOO.lang=YAHOO.lang||{isArray:function(B){if(B){var A=YAHOO.lang;return A.isNumber(B.length)&&A.isFunction(B.splice);}return false;},isBoolean:function(A){return typeof A==="boolean";},isFunction:function(A){return typeof A==="function";},isNull:function(A){return A===null;},isNumber:function(A){return typeof A==="number"&&isFinite(A);},isObject:function(A){return(A&&(typeof A==="object"||YAHOO.lang.isFunction(A)))||false;},isString:function(A){return typeof A==="string";},isUndefined:function(A){return typeof A==="undefined";},hasOwnProperty:function(A,B){if(Object.prototype.hasOwnProperty){return A.hasOwnProperty(B);}return !YAHOO.lang.isUndefined(A[B])&&A.constructor.prototype[B]!==A[B];},_IEEnumFix:function(C,B){if(YAHOO.env.ua.ie){var E=["toString","valueOf"],A;for(A=0;A<E.length;A=A+1){var F=E[A],D=B[F];if(YAHOO.lang.isFunction(D)&&D!=Object.prototype[F]){C[F]=D;}}}},extend:function(D,E,C){if(!E||!D){throw new Error("YAHOO.lang.extend failed, please check that "+"all dependencies are included.");}var B=function(){};B.prototype=E.prototype;D.prototype=new B();D.prototype.constructor=D;D.superclass=E.prototype;if(E.prototype.constructor==Object.prototype.constructor){E.prototype.constructor=E;}if(C){for(var A in C){D.prototype[A]=C[A];}YAHOO.lang._IEEnumFix(D.prototype,C);}},augmentObject:function(E,D){if(!D||!E){throw new Error("Absorb failed, verify dependencies.");}var A=arguments,C,F,B=A[2];if(B&&B!==true){for(C=2;C<A.length;C=C+1){E[A[C]]=D[A[C]];}}else{for(F in D){if(B||!E[F]){E[F]=D[F];}}YAHOO.lang._IEEnumFix(E,D);}},augmentProto:function(D,C){if(!C||!D){throw new Error("Augment failed, verify dependencies.");}var A=[D.prototype,C.prototype];for(var B=2;B<arguments.length;B=B+1){A.push(arguments[B]);}YAHOO.lang.augmentObject.apply(this,A);},dump:function(A,G){var C=YAHOO.lang,D,F,I=[],J="{...}",B="f(){...}",H=", ",E=" => ";if(!C.isObject(A)){return A+"";}else{if(A instanceof Date||("nodeType" in A&&"tagName" in A)){return A;}else{if(C.isFunction(A)){return B;}}}G=(C.isNumber(G))?G:3;if(C.isArray(A)){I.push("[");for(D=0,F=A.length;D<F;D=D+1){if(C.isObject(A[D])){I.push((G>0)?C.dump(A[D],G-1):J);}else{I.push(A[D]);}I.push(H);}if(I.length>1){I.pop();}I.push("]");}else{I.push("{");for(D in A){if(C.hasOwnProperty(A,D)){I.push(D+E);if(C.isObject(A[D])){I.push((G>0)?C.dump(A[D],G-1):J);}else{I.push(A[D]);}I.push(H);}}if(I.length>1){I.pop();}I.push("}");}return I.join("");},substitute:function(Q,B,J){var G,F,E,M,N,P,D=YAHOO.lang,L=[],C,H="dump",K=" ",A="{",O="}";for(;;){G=Q.lastIndexOf(A);if(G<0){break;}F=Q.indexOf(O,G);if(G+1>=F){break;}C=Q.substring(G+1,F);M=C;P=null;E=M.indexOf(K);if(E>-1){P=M.substring(E+1);M=M.substring(0,E);}N=B[M];if(J){N=J(M,N,P);}if(D.isObject(N)){if(D.isArray(N)){N=D.dump(N,parseInt(P,10));}else{P=P||"";var I=P.indexOf(H);if(I>-1){P=P.substring(4);}if(N.toString===Object.prototype.toString||I>-1){N=D.dump(N,parseInt(P,10));}else{N=N.toString();}}}else{if(!D.isString(N)&&!D.isNumber(N)){N="~-"+L.length+"-~";L[L.length]=C;}}Q=Q.substring(0,G)+N+Q.substring(F+1);}for(G=L.length-1;G>=0;G=G-1){Q=Q.replace(new RegExp("~-"+G+"-~"),"{"+L[G]+"}","g");}return Q;},trim:function(A){try{return A.replace(/^\s+|\s+$/g,"");}catch(B){return A;}},merge:function(){var D={},B=arguments;for(var C=0,A=B.length;C<A;C=C+1){YAHOO.lang.augmentObject(D,B[C],true);}return D;},later:function(H,B,I,D,E){H=H||0;B=B||{};var C=I,G=D,F,A;if(YAHOO.lang.isString(I)){C=B[I];}if(!C){throw new TypeError("method undefined");}if(!YAHOO.lang.isArray(G)){G=[D];}F=function(){C.apply(B,G);};A=(E)?setInterval(F,H):setTimeout(F,H);return{interval:E,cancel:function(){if(this.interval){clearInterval(A);}else{clearTimeout(A);}}};},isValue:function(B){var A=YAHOO.lang;return(A.isObject(B)||A.isString(B)||A.isNumber(B)||A.isBoolean(B));}};YAHOO.util.Lang=YAHOO.lang;YAHOO.lang.augment=YAHOO.lang.augmentProto;YAHOO.augment=YAHOO.lang.augmentProto;YAHOO.extend=YAHOO.lang.extend;YAHOO.register("yahoo",YAHOO,{version:"2.5.1",build:"984"});


/*
Copyright (c) 2008, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://developer.yahoo.net/yui/license.txt
version: 2.5.1
*/
(function(){var B=YAHOO.util,K,I,J={},F={},M=window.document;YAHOO.env._id_counter=YAHOO.env._id_counter||0;var C=YAHOO.env.ua.opera,L=YAHOO.env.ua.webkit,A=YAHOO.env.ua.gecko,G=YAHOO.env.ua.ie;var E={HYPHEN:/(-[a-z])/i,ROOT_TAG:/^body|html$/i,OP_SCROLL:/^(?:inline|table-row)$/i};var N=function(P){if(!E.HYPHEN.test(P)){return P;}if(J[P]){return J[P];}var Q=P;while(E.HYPHEN.exec(Q)){Q=Q.replace(RegExp.$1,RegExp.$1.substr(1).toUpperCase());}J[P]=Q;return Q;};var O=function(Q){var P=F[Q];if(!P){P=new RegExp("(?:^|\\s+)"+Q+"(?:\\s+|$)");F[Q]=P;}return P;};if(M.defaultView&&M.defaultView.getComputedStyle){K=function(P,S){var R=null;if(S=="float"){S="cssFloat";}var Q=P.ownerDocument.defaultView.getComputedStyle(P,"");if(Q){R=Q[N(S)];}return P.style[S]||R;};}else{if(M.documentElement.currentStyle&&G){K=function(P,R){switch(N(R)){case"opacity":var T=100;try{T=P.filters["DXImageTransform.Microsoft.Alpha"].opacity;}catch(S){try{T=P.filters("alpha").opacity;}catch(S){}}return T/100;case"float":R="styleFloat";default:var Q=P.currentStyle?P.currentStyle[R]:null;return(P.style[R]||Q);}};}else{K=function(P,Q){return P.style[Q];};}}if(G){I=function(P,Q,R){switch(Q){case"opacity":if(YAHOO.lang.isString(P.style.filter)){P.style.filter="alpha(opacity="+R*100+")";if(!P.currentStyle||!P.currentStyle.hasLayout){P.style.zoom=1;}}break;case"float":Q="styleFloat";default:P.style[Q]=R;}};}else{I=function(P,Q,R){if(Q=="float"){Q="cssFloat";}P.style[Q]=R;};}var D=function(P,Q){return P&&P.nodeType==1&&(!Q||Q(P));};YAHOO.util.Dom={get:function(R){if(R&&(R.nodeType||R.item)){return R;}if(YAHOO.lang.isString(R)||!R){return M.getElementById(R);}if(R.length!==undefined){var S=[];for(var Q=0,P=R.length;Q<P;++Q){S[S.length]=B.Dom.get(R[Q]);}return S;}return R;},getStyle:function(P,R){R=N(R);var Q=function(S){return K(S,R);};return B.Dom.batch(P,Q,B.Dom,true);},setStyle:function(P,R,S){R=N(R);var Q=function(T){I(T,R,S);};B.Dom.batch(P,Q,B.Dom,true);},getXY:function(P){var Q=function(R){if((R.parentNode===null||R.offsetParent===null||this.getStyle(R,"display")=="none")&&R!=R.ownerDocument.body){return false;}return H(R);};return B.Dom.batch(P,Q,B.Dom,true);},getX:function(P){var Q=function(R){return B.Dom.getXY(R)[0];};return B.Dom.batch(P,Q,B.Dom,true);},getY:function(P){var Q=function(R){return B.Dom.getXY(R)[1];};return B.Dom.batch(P,Q,B.Dom,true);},setXY:function(P,S,R){var Q=function(V){var U=this.getStyle(V,"position");if(U=="static"){this.setStyle(V,"position","relative");U="relative";}var X=this.getXY(V);if(X===false){return false;}var W=[parseInt(this.getStyle(V,"left"),10),parseInt(this.getStyle(V,"top"),10)];if(isNaN(W[0])){W[0]=(U=="relative")?0:V.offsetLeft;}if(isNaN(W[1])){W[1]=(U=="relative")?0:V.offsetTop;}if(S[0]!==null){V.style.left=S[0]-X[0]+W[0]+"px";}if(S[1]!==null){V.style.top=S[1]-X[1]+W[1]+"px";}if(!R){var T=this.getXY(V);if((S[0]!==null&&T[0]!=S[0])||(S[1]!==null&&T[1]!=S[1])){this.setXY(V,S,true);}}};B.Dom.batch(P,Q,B.Dom,true);},setX:function(Q,P){B.Dom.setXY(Q,[P,null]);},setY:function(P,Q){B.Dom.setXY(P,[null,Q]);},getRegion:function(P){var Q=function(R){if((R.parentNode===null||R.offsetParent===null||this.getStyle(R,"display")=="none")&&R!=R.ownerDocument.body){return false;}var S=B.Region.getRegion(R);return S;};return B.Dom.batch(P,Q,B.Dom,true);},getClientWidth:function(){return B.Dom.getViewportWidth();},getClientHeight:function(){return B.Dom.getViewportHeight();},getElementsByClassName:function(T,X,U,V){X=X||"*";U=(U)?B.Dom.get(U):null||M;if(!U){return[];}var Q=[],P=U.getElementsByTagName(X),W=O(T);for(var R=0,S=P.length;R<S;++R){if(W.test(P[R].className)){Q[Q.length]=P[R];if(V){V.call(P[R],P[R]);}}}return Q;},hasClass:function(R,Q){var P=O(Q);var S=function(T){return P.test(T.className);};return B.Dom.batch(R,S,B.Dom,true);},addClass:function(Q,P){var R=function(S){if(this.hasClass(S,P)){return false;}S.className=YAHOO.lang.trim([S.className,P].join(" "));return true;};return B.Dom.batch(Q,R,B.Dom,true);},removeClass:function(R,Q){var P=O(Q);var S=function(T){if(!Q||!this.hasClass(T,Q)){return false;}var U=T.className;T.className=U.replace(P," ");if(this.hasClass(T,Q)){this.removeClass(T,Q);}T.className=YAHOO.lang.trim(T.className);return true;};return B.Dom.batch(R,S,B.Dom,true);},replaceClass:function(S,Q,P){if(!P||Q===P){return false;}var R=O(Q);var T=function(U){if(!this.hasClass(U,Q)){this.addClass(U,P);return true;}U.className=U.className.replace(R," "+P+" ");if(this.hasClass(U,Q)){this.replaceClass(U,Q,P);}U.className=YAHOO.lang.trim(U.className);return true;};return B.Dom.batch(S,T,B.Dom,true);},generateId:function(P,R){R=R||"yui-gen";var Q=function(S){if(S&&S.id){return S.id;}var T=R+YAHOO.env._id_counter++;if(S){S.id=T;}return T;};return B.Dom.batch(P,Q,B.Dom,true)||Q.apply(B.Dom,arguments);},isAncestor:function(P,Q){P=B.Dom.get(P);Q=B.Dom.get(Q);if(!P||!Q){return false;}if(P.contains&&Q.nodeType&&!L){return P.contains(Q);}else{if(P.compareDocumentPosition&&Q.nodeType){return !!(P.compareDocumentPosition(Q)&16);}else{if(Q.nodeType){return !!this.getAncestorBy(Q,function(R){return R==P;});}}}return false;},inDocument:function(P){return this.isAncestor(M.documentElement,P);},getElementsBy:function(W,Q,R,T){Q=Q||"*";R=(R)?B.Dom.get(R):null||M;if(!R){return[];}var S=[],V=R.getElementsByTagName(Q);for(var U=0,P=V.length;U<P;++U){if(W(V[U])){S[S.length]=V[U];if(T){T(V[U]);}}}return S;},batch:function(T,W,V,R){T=(T&&(T.tagName||T.item))?T:B.Dom.get(T);if(!T||!W){return false;}var S=(R)?V:window;if(T.tagName||T.length===undefined){return W.call(S,T,V);}var U=[];for(var Q=0,P=T.length;Q<P;++Q){U[U.length]=W.call(S,T[Q],V);}return U;},getDocumentHeight:function(){var Q=(M.compatMode!="CSS1Compat")?M.body.scrollHeight:M.documentElement.scrollHeight;var P=Math.max(Q,B.Dom.getViewportHeight());return P;},getDocumentWidth:function(){var Q=(M.compatMode!="CSS1Compat")?M.body.scrollWidth:M.documentElement.scrollWidth;var P=Math.max(Q,B.Dom.getViewportWidth());return P;},getViewportHeight:function(){var P=self.innerHeight;
var Q=M.compatMode;if((Q||G)&&!C){P=(Q=="CSS1Compat")?M.documentElement.clientHeight:M.body.clientHeight;}return P;},getViewportWidth:function(){var P=self.innerWidth;var Q=M.compatMode;if(Q||G){P=(Q=="CSS1Compat")?M.documentElement.clientWidth:M.body.clientWidth;}return P;},getAncestorBy:function(P,Q){while(P=P.parentNode){if(D(P,Q)){return P;}}return null;},getAncestorByClassName:function(Q,P){Q=B.Dom.get(Q);if(!Q){return null;}var R=function(S){return B.Dom.hasClass(S,P);};return B.Dom.getAncestorBy(Q,R);},getAncestorByTagName:function(Q,P){Q=B.Dom.get(Q);if(!Q){return null;}var R=function(S){return S.tagName&&S.tagName.toUpperCase()==P.toUpperCase();};return B.Dom.getAncestorBy(Q,R);},getPreviousSiblingBy:function(P,Q){while(P){P=P.previousSibling;if(D(P,Q)){return P;}}return null;},getPreviousSibling:function(P){P=B.Dom.get(P);if(!P){return null;}return B.Dom.getPreviousSiblingBy(P);},getNextSiblingBy:function(P,Q){while(P){P=P.nextSibling;if(D(P,Q)){return P;}}return null;},getNextSibling:function(P){P=B.Dom.get(P);if(!P){return null;}return B.Dom.getNextSiblingBy(P);},getFirstChildBy:function(P,R){var Q=(D(P.firstChild,R))?P.firstChild:null;return Q||B.Dom.getNextSiblingBy(P.firstChild,R);},getFirstChild:function(P,Q){P=B.Dom.get(P);if(!P){return null;}return B.Dom.getFirstChildBy(P);},getLastChildBy:function(P,R){if(!P){return null;}var Q=(D(P.lastChild,R))?P.lastChild:null;return Q||B.Dom.getPreviousSiblingBy(P.lastChild,R);},getLastChild:function(P){P=B.Dom.get(P);return B.Dom.getLastChildBy(P);},getChildrenBy:function(Q,S){var R=B.Dom.getFirstChildBy(Q,S);var P=R?[R]:[];B.Dom.getNextSiblingBy(R,function(T){if(!S||S(T)){P[P.length]=T;}return false;});return P;},getChildren:function(P){P=B.Dom.get(P);if(!P){}return B.Dom.getChildrenBy(P);},getDocumentScrollLeft:function(P){P=P||M;return Math.max(P.documentElement.scrollLeft,P.body.scrollLeft);},getDocumentScrollTop:function(P){P=P||M;return Math.max(P.documentElement.scrollTop,P.body.scrollTop);},insertBefore:function(Q,P){Q=B.Dom.get(Q);P=B.Dom.get(P);if(!Q||!P||!P.parentNode){return null;}return P.parentNode.insertBefore(Q,P);},insertAfter:function(Q,P){Q=B.Dom.get(Q);P=B.Dom.get(P);if(!Q||!P||!P.parentNode){return null;}if(P.nextSibling){return P.parentNode.insertBefore(Q,P.nextSibling);}else{return P.parentNode.appendChild(Q);}},getClientRegion:function(){var R=B.Dom.getDocumentScrollTop(),Q=B.Dom.getDocumentScrollLeft(),S=B.Dom.getViewportWidth()+Q,P=B.Dom.getViewportHeight()+R;return new B.Region(R,S,P,Q);}};var H=function(){if(M.documentElement.getBoundingClientRect){return function(Q){var R=Q.getBoundingClientRect();var P=Q.ownerDocument;return[R.left+B.Dom.getDocumentScrollLeft(P),R.top+B.Dom.getDocumentScrollTop(P)];};}else{return function(R){var S=[R.offsetLeft,R.offsetTop];var Q=R.offsetParent;var P=(L&&B.Dom.getStyle(R,"position")=="absolute"&&R.offsetParent==R.ownerDocument.body);if(Q!=R){while(Q){S[0]+=Q.offsetLeft;S[1]+=Q.offsetTop;if(!P&&L&&B.Dom.getStyle(Q,"position")=="absolute"){P=true;}Q=Q.offsetParent;}}if(P){S[0]-=R.ownerDocument.body.offsetLeft;S[1]-=R.ownerDocument.body.offsetTop;}Q=R.parentNode;while(Q.tagName&&!E.ROOT_TAG.test(Q.tagName)){if(Q.scrollTop||Q.scrollLeft){if(!E.OP_SCROLL.test(B.Dom.getStyle(Q,"display"))){if(!C||B.Dom.getStyle(Q,"overflow")!=="visible"){S[0]-=Q.scrollLeft;S[1]-=Q.scrollTop;}}}Q=Q.parentNode;}return S;};}}();})();YAHOO.util.Region=function(C,D,A,B){this.top=C;this[1]=C;this.right=D;this.bottom=A;this.left=B;this[0]=B;};YAHOO.util.Region.prototype.contains=function(A){return(A.left>=this.left&&A.right<=this.right&&A.top>=this.top&&A.bottom<=this.bottom);};YAHOO.util.Region.prototype.getArea=function(){return((this.bottom-this.top)*(this.right-this.left));};YAHOO.util.Region.prototype.intersect=function(E){var C=Math.max(this.top,E.top);var D=Math.min(this.right,E.right);var A=Math.min(this.bottom,E.bottom);var B=Math.max(this.left,E.left);if(A>=C&&D>=B){return new YAHOO.util.Region(C,D,A,B);}else{return null;}};YAHOO.util.Region.prototype.union=function(E){var C=Math.min(this.top,E.top);var D=Math.max(this.right,E.right);var A=Math.max(this.bottom,E.bottom);var B=Math.min(this.left,E.left);return new YAHOO.util.Region(C,D,A,B);};YAHOO.util.Region.prototype.toString=function(){return("Region {"+"top: "+this.top+", right: "+this.right+", bottom: "+this.bottom+", left: "+this.left+"}");};YAHOO.util.Region.getRegion=function(D){var F=YAHOO.util.Dom.getXY(D);var C=F[1];var E=F[0]+D.offsetWidth;var A=F[1]+D.offsetHeight;var B=F[0];return new YAHOO.util.Region(C,E,A,B);};YAHOO.util.Point=function(A,B){if(YAHOO.lang.isArray(A)){B=A[1];A=A[0];}this.x=this.right=this.left=this[0]=A;this.y=this.top=this.bottom=this[1]=B;};YAHOO.util.Point.prototype=new YAHOO.util.Region();YAHOO.register("dom",YAHOO.util.Dom,{version:"2.5.1",build:"984"});


/*
Copyright (c) 2008, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://developer.yahoo.net/yui/license.txt
version: 2.5.1
*/
YAHOO.util.CustomEvent=function(D,B,C,A){this.type=D;this.scope=B||window;this.silent=C;this.signature=A||YAHOO.util.CustomEvent.LIST;this.subscribers=[];if(!this.silent){}var E="_YUICEOnSubscribe";if(D!==E){this.subscribeEvent=new YAHOO.util.CustomEvent(E,this,true);}this.lastError=null;};YAHOO.util.CustomEvent.LIST=0;YAHOO.util.CustomEvent.FLAT=1;YAHOO.util.CustomEvent.prototype={subscribe:function(B,C,A){if(!B){throw new Error("Invalid callback for subscriber to '"+this.type+"'");}if(this.subscribeEvent){this.subscribeEvent.fire(B,C,A);}this.subscribers.push(new YAHOO.util.Subscriber(B,C,A));},unsubscribe:function(D,F){if(!D){return this.unsubscribeAll();}var E=false;for(var B=0,A=this.subscribers.length;B<A;++B){var C=this.subscribers[B];if(C&&C.contains(D,F)){this._delete(B);E=true;}}return E;},fire:function(){var D=this.subscribers.length;if(!D&&this.silent){return true;}var H=[].slice.call(arguments,0),F=true,C,I=false;if(!this.silent){}var B=this.subscribers.slice();for(C=0;C<D;++C){var K=B[C];if(!K){I=true;}else{if(!this.silent){}var J=K.getScope(this.scope);if(this.signature==YAHOO.util.CustomEvent.FLAT){var A=null;if(H.length>0){A=H[0];}try{F=K.fn.call(J,A,K.obj);}catch(E){this.lastError=E;}}else{try{F=K.fn.call(J,this.type,H,K.obj);}catch(G){this.lastError=G;}}if(false===F){if(!this.silent){}return false;}}}return true;},unsubscribeAll:function(){for(var A=this.subscribers.length-1;A>-1;A--){this._delete(A);}this.subscribers=[];return A;},_delete:function(A){var B=this.subscribers[A];if(B){delete B.fn;delete B.obj;}this.subscribers.splice(A,1);},toString:function(){return"CustomEvent: "+"'"+this.type+"', "+"scope: "+this.scope;}};YAHOO.util.Subscriber=function(B,C,A){this.fn=B;this.obj=YAHOO.lang.isUndefined(C)?null:C;this.override=A;};YAHOO.util.Subscriber.prototype.getScope=function(A){if(this.override){if(this.override===true){return this.obj;}else{return this.override;}}return A;};YAHOO.util.Subscriber.prototype.contains=function(A,B){if(B){return(this.fn==A&&this.obj==B);}else{return(this.fn==A);}};YAHOO.util.Subscriber.prototype.toString=function(){return"Subscriber { obj: "+this.obj+", override: "+(this.override||"no")+" }";};if(!YAHOO.util.Event){YAHOO.util.Event=function(){var H=false;var I=[];var J=[];var G=[];var E=[];var C=0;var F=[];var B=[];var A=0;var D={63232:38,63233:40,63234:37,63235:39,63276:33,63277:34,25:9};return{POLL_RETRYS:2000,POLL_INTERVAL:20,EL:0,TYPE:1,FN:2,WFN:3,UNLOAD_OBJ:3,ADJ_SCOPE:4,OBJ:5,OVERRIDE:6,lastError:null,isSafari:YAHOO.env.ua.webkit,webkit:YAHOO.env.ua.webkit,isIE:YAHOO.env.ua.ie,_interval:null,_dri:null,DOMReady:false,startInterval:function(){if(!this._interval){var K=this;var L=function(){K._tryPreloadAttach();};this._interval=setInterval(L,this.POLL_INTERVAL);}},onAvailable:function(P,M,Q,O,N){var K=(YAHOO.lang.isString(P))?[P]:P;for(var L=0;L<K.length;L=L+1){F.push({id:K[L],fn:M,obj:Q,override:O,checkReady:N});}C=this.POLL_RETRYS;this.startInterval();},onContentReady:function(M,K,N,L){this.onAvailable(M,K,N,L,true);},onDOMReady:function(K,M,L){if(this.DOMReady){setTimeout(function(){var N=window;if(L){if(L===true){N=M;}else{N=L;}}K.call(N,"DOMReady",[],M);},0);}else{this.DOMReadyEvent.subscribe(K,M,L);}},addListener:function(M,K,V,Q,L){if(!V||!V.call){return false;}if(this._isValidCollection(M)){var W=true;for(var R=0,T=M.length;R<T;++R){W=this.on(M[R],K,V,Q,L)&&W;}return W;}else{if(YAHOO.lang.isString(M)){var P=this.getEl(M);if(P){M=P;}else{this.onAvailable(M,function(){YAHOO.util.Event.on(M,K,V,Q,L);});return true;}}}if(!M){return false;}if("unload"==K&&Q!==this){J[J.length]=[M,K,V,Q,L];return true;}var Y=M;if(L){if(L===true){Y=Q;}else{Y=L;}}var N=function(Z){return V.call(Y,YAHOO.util.Event.getEvent(Z,M),Q);};var X=[M,K,V,N,Y,Q,L];var S=I.length;I[S]=X;if(this.useLegacyEvent(M,K)){var O=this.getLegacyIndex(M,K);if(O==-1||M!=G[O][0]){O=G.length;B[M.id+K]=O;G[O]=[M,K,M["on"+K]];E[O]=[];M["on"+K]=function(Z){YAHOO.util.Event.fireLegacyEvent(YAHOO.util.Event.getEvent(Z),O);};}E[O].push(X);}else{try{this._simpleAdd(M,K,N,false);}catch(U){this.lastError=U;this.removeListener(M,K,V);return false;}}return true;},fireLegacyEvent:function(O,M){var Q=true,K,S,R,T,P;S=E[M].slice();for(var L=0,N=S.length;L<N;++L){R=S[L];if(R&&R[this.WFN]){T=R[this.ADJ_SCOPE];P=R[this.WFN].call(T,O);Q=(Q&&P);}}K=G[M];if(K&&K[2]){K[2](O);}return Q;},getLegacyIndex:function(L,M){var K=this.generateId(L)+M;if(typeof B[K]=="undefined"){return -1;}else{return B[K];}},useLegacyEvent:function(L,M){if(this.webkit&&("click"==M||"dblclick"==M)){var K=parseInt(this.webkit,10);if(!isNaN(K)&&K<418){return true;}}return false;},removeListener:function(L,K,T){var O,R,V;if(typeof L=="string"){L=this.getEl(L);}else{if(this._isValidCollection(L)){var U=true;for(O=L.length-1;O>-1;O--){U=(this.removeListener(L[O],K,T)&&U);}return U;}}if(!T||!T.call){return this.purgeElement(L,false,K);}if("unload"==K){for(O=J.length-1;O>-1;O--){V=J[O];if(V&&V[0]==L&&V[1]==K&&V[2]==T){J.splice(O,1);return true;}}return false;}var P=null;var Q=arguments[3];if("undefined"===typeof Q){Q=this._getCacheIndex(L,K,T);}if(Q>=0){P=I[Q];}if(!L||!P){return false;}if(this.useLegacyEvent(L,K)){var N=this.getLegacyIndex(L,K);var M=E[N];if(M){for(O=0,R=M.length;O<R;++O){V=M[O];if(V&&V[this.EL]==L&&V[this.TYPE]==K&&V[this.FN]==T){M.splice(O,1);break;}}}}else{try{this._simpleRemove(L,K,P[this.WFN],false);}catch(S){this.lastError=S;return false;}}delete I[Q][this.WFN];delete I[Q][this.FN];I.splice(Q,1);return true;},getTarget:function(M,L){var K=M.target||M.srcElement;return this.resolveTextNode(K);},resolveTextNode:function(L){try{if(L&&3==L.nodeType){return L.parentNode;}}catch(K){}return L;},getPageX:function(L){var K=L.pageX;if(!K&&0!==K){K=L.clientX||0;if(this.isIE){K+=this._getScrollLeft();}}return K;},getPageY:function(K){var L=K.pageY;if(!L&&0!==L){L=K.clientY||0;if(this.isIE){L+=this._getScrollTop();}}return L;},getXY:function(K){return[this.getPageX(K),this.getPageY(K)];},getRelatedTarget:function(L){var K=L.relatedTarget;
if(!K){if(L.type=="mouseout"){K=L.toElement;}else{if(L.type=="mouseover"){K=L.fromElement;}}}return this.resolveTextNode(K);},getTime:function(M){if(!M.time){var L=new Date().getTime();try{M.time=L;}catch(K){this.lastError=K;return L;}}return M.time;},stopEvent:function(K){this.stopPropagation(K);this.preventDefault(K);},stopPropagation:function(K){if(K.stopPropagation){K.stopPropagation();}else{K.cancelBubble=true;}},preventDefault:function(K){if(K.preventDefault){K.preventDefault();}else{K.returnValue=false;}},getEvent:function(M,K){var L=M||window.event;if(!L){var N=this.getEvent.caller;while(N){L=N.arguments[0];if(L&&Event==L.constructor){break;}N=N.caller;}}return L;},getCharCode:function(L){var K=L.keyCode||L.charCode||0;if(YAHOO.env.ua.webkit&&(K in D)){K=D[K];}return K;},_getCacheIndex:function(O,P,N){for(var M=0,L=I.length;M<L;M=M+1){var K=I[M];if(K&&K[this.FN]==N&&K[this.EL]==O&&K[this.TYPE]==P){return M;}}return -1;},generateId:function(K){var L=K.id;if(!L){L="yuievtautoid-"+A;++A;K.id=L;}return L;},_isValidCollection:function(L){try{return(L&&typeof L!=="string"&&L.length&&!L.tagName&&!L.alert&&typeof L[0]!=="undefined");}catch(K){return false;}},elCache:{},getEl:function(K){return(typeof K==="string")?document.getElementById(K):K;},clearCache:function(){},DOMReadyEvent:new YAHOO.util.CustomEvent("DOMReady",this),_load:function(L){if(!H){H=true;var K=YAHOO.util.Event;K._ready();K._tryPreloadAttach();}},_ready:function(L){var K=YAHOO.util.Event;if(!K.DOMReady){K.DOMReady=true;K.DOMReadyEvent.fire();K._simpleRemove(document,"DOMContentLoaded",K._ready);}},_tryPreloadAttach:function(){if(F.length===0){C=0;clearInterval(this._interval);this._interval=null;return ;}if(this.locked){return ;}if(this.isIE){if(!this.DOMReady){this.startInterval();return ;}}this.locked=true;var Q=!H;if(!Q){Q=(C>0&&F.length>0);}var P=[];var R=function(T,U){var S=T;if(U.override){if(U.override===true){S=U.obj;}else{S=U.override;}}U.fn.call(S,U.obj);};var L,K,O,N,M=[];for(L=0,K=F.length;L<K;L=L+1){O=F[L];if(O){N=this.getEl(O.id);if(N){if(O.checkReady){if(H||N.nextSibling||!Q){M.push(O);F[L]=null;}}else{R(N,O);F[L]=null;}}else{P.push(O);}}}for(L=0,K=M.length;L<K;L=L+1){O=M[L];R(this.getEl(O.id),O);}C--;if(Q){for(L=F.length-1;L>-1;L--){O=F[L];if(!O||!O.id){F.splice(L,1);}}this.startInterval();}else{clearInterval(this._interval);this._interval=null;}this.locked=false;},purgeElement:function(O,P,R){var M=(YAHOO.lang.isString(O))?this.getEl(O):O;var Q=this.getListeners(M,R),N,K;if(Q){for(N=Q.length-1;N>-1;N--){var L=Q[N];this.removeListener(M,L.type,L.fn);}}if(P&&M&&M.childNodes){for(N=0,K=M.childNodes.length;N<K;++N){this.purgeElement(M.childNodes[N],P,R);}}},getListeners:function(M,K){var P=[],L;if(!K){L=[I,J];}else{if(K==="unload"){L=[J];}else{L=[I];}}var R=(YAHOO.lang.isString(M))?this.getEl(M):M;for(var O=0;O<L.length;O=O+1){var T=L[O];if(T){for(var Q=0,S=T.length;Q<S;++Q){var N=T[Q];if(N&&N[this.EL]===R&&(!K||K===N[this.TYPE])){P.push({type:N[this.TYPE],fn:N[this.FN],obj:N[this.OBJ],adjust:N[this.OVERRIDE],scope:N[this.ADJ_SCOPE],index:Q});}}}}return(P.length)?P:null;},_unload:function(Q){var K=YAHOO.util.Event,N,M,L,P,O,R=J.slice();for(N=0,P=J.length;N<P;++N){L=R[N];if(L){var S=window;if(L[K.ADJ_SCOPE]){if(L[K.ADJ_SCOPE]===true){S=L[K.UNLOAD_OBJ];}else{S=L[K.ADJ_SCOPE];}}L[K.FN].call(S,K.getEvent(Q,L[K.EL]),L[K.UNLOAD_OBJ]);R[N]=null;L=null;S=null;}}J=null;if(I){for(M=I.length-1;M>-1;M--){L=I[M];if(L){K.removeListener(L[K.EL],L[K.TYPE],L[K.FN],M);}}L=null;}G=null;K._simpleRemove(window,"unload",K._unload);},_getScrollLeft:function(){return this._getScroll()[1];},_getScrollTop:function(){return this._getScroll()[0];},_getScroll:function(){var K=document.documentElement,L=document.body;if(K&&(K.scrollTop||K.scrollLeft)){return[K.scrollTop,K.scrollLeft];}else{if(L){return[L.scrollTop,L.scrollLeft];}else{return[0,0];}}},regCE:function(){},_simpleAdd:function(){if(window.addEventListener){return function(M,N,L,K){M.addEventListener(N,L,(K));};}else{if(window.attachEvent){return function(M,N,L,K){M.attachEvent("on"+N,L);};}else{return function(){};}}}(),_simpleRemove:function(){if(window.removeEventListener){return function(M,N,L,K){M.removeEventListener(N,L,(K));};}else{if(window.detachEvent){return function(L,M,K){L.detachEvent("on"+M,K);};}else{return function(){};}}}()};}();(function(){var EU=YAHOO.util.Event;EU.on=EU.addListener;
/* DOMReady: based on work by: Dean Edwards/John Resig/Matthias Miller */
if(EU.isIE){YAHOO.util.Event.onDOMReady(YAHOO.util.Event._tryPreloadAttach,YAHOO.util.Event,true);var n=document.createElement("p");EU._dri=setInterval(function(){try{n.doScroll("left");clearInterval(EU._dri);EU._dri=null;EU._ready();n=null;}catch(ex){}},EU.POLL_INTERVAL);}else{if(EU.webkit&&EU.webkit<525){EU._dri=setInterval(function(){var rs=document.readyState;if("loaded"==rs||"complete"==rs){clearInterval(EU._dri);EU._dri=null;EU._ready();}},EU.POLL_INTERVAL);}else{EU._simpleAdd(document,"DOMContentLoaded",EU._ready);}}EU._simpleAdd(window,"load",EU._load);EU._simpleAdd(window,"unload",EU._unload);EU._tryPreloadAttach();})();}YAHOO.util.EventProvider=function(){};YAHOO.util.EventProvider.prototype={__yui_events:null,__yui_subscribers:null,subscribe:function(A,C,F,E){this.__yui_events=this.__yui_events||{};var D=this.__yui_events[A];if(D){D.subscribe(C,F,E);}else{this.__yui_subscribers=this.__yui_subscribers||{};var B=this.__yui_subscribers;if(!B[A]){B[A]=[];}B[A].push({fn:C,obj:F,override:E});}},unsubscribe:function(C,E,G){this.__yui_events=this.__yui_events||{};var A=this.__yui_events;if(C){var F=A[C];if(F){return F.unsubscribe(E,G);}}else{var B=true;for(var D in A){if(YAHOO.lang.hasOwnProperty(A,D)){B=B&&A[D].unsubscribe(E,G);}}return B;}return false;},unsubscribeAll:function(A){return this.unsubscribe(A);},createEvent:function(G,D){this.__yui_events=this.__yui_events||{};var A=D||{};var I=this.__yui_events;if(I[G]){}else{var H=A.scope||this;var E=(A.silent);var B=new YAHOO.util.CustomEvent(G,H,E,YAHOO.util.CustomEvent.FLAT);
I[G]=B;if(A.onSubscribeCallback){B.subscribeEvent.subscribe(A.onSubscribeCallback);}this.__yui_subscribers=this.__yui_subscribers||{};var F=this.__yui_subscribers[G];if(F){for(var C=0;C<F.length;++C){B.subscribe(F[C].fn,F[C].obj,F[C].override);}}}return I[G];},fireEvent:function(E,D,A,C){this.__yui_events=this.__yui_events||{};var G=this.__yui_events[E];if(!G){return null;}var B=[];for(var F=1;F<arguments.length;++F){B.push(arguments[F]);}return G.fire.apply(G,B);},hasEvent:function(A){if(this.__yui_events){if(this.__yui_events[A]){return true;}}return false;}};YAHOO.util.KeyListener=function(A,F,B,C){if(!A){}else{if(!F){}else{if(!B){}}}if(!C){C=YAHOO.util.KeyListener.KEYDOWN;}var D=new YAHOO.util.CustomEvent("keyPressed");this.enabledEvent=new YAHOO.util.CustomEvent("enabled");this.disabledEvent=new YAHOO.util.CustomEvent("disabled");if(typeof A=="string"){A=document.getElementById(A);}if(typeof B=="function"){D.subscribe(B);}else{D.subscribe(B.fn,B.scope,B.correctScope);}function E(J,I){if(!F.shift){F.shift=false;}if(!F.alt){F.alt=false;}if(!F.ctrl){F.ctrl=false;}if(J.shiftKey==F.shift&&J.altKey==F.alt&&J.ctrlKey==F.ctrl){var G;if(F.keys instanceof Array){for(var H=0;H<F.keys.length;H++){G=F.keys[H];if(G==J.charCode){D.fire(J.charCode,J);break;}else{if(G==J.keyCode){D.fire(J.keyCode,J);break;}}}}else{G=F.keys;if(G==J.charCode){D.fire(J.charCode,J);}else{if(G==J.keyCode){D.fire(J.keyCode,J);}}}}}this.enable=function(){if(!this.enabled){YAHOO.util.Event.addListener(A,C,E);this.enabledEvent.fire(F);}this.enabled=true;};this.disable=function(){if(this.enabled){YAHOO.util.Event.removeListener(A,C,E);this.disabledEvent.fire(F);}this.enabled=false;};this.toString=function(){return"KeyListener ["+F.keys+"] "+A.tagName+(A.id?"["+A.id+"]":"");};};YAHOO.util.KeyListener.KEYDOWN="keydown";YAHOO.util.KeyListener.KEYUP="keyup";YAHOO.util.KeyListener.KEY={ALT:18,BACK_SPACE:8,CAPS_LOCK:20,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,META:224,NUM_LOCK:144,PAGE_DOWN:34,PAGE_UP:33,PAUSE:19,PRINTSCREEN:44,RIGHT:39,SCROLL_LOCK:145,SHIFT:16,SPACE:32,TAB:9,UP:38};YAHOO.register("event",YAHOO.util.Event,{version:"2.5.1",build:"984"});


/*
Copyright (c) 2008, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://developer.yahoo.net/yui/license.txt
version: 2.5.1
*/
(function () {

    /**
    * Config is a utility used within an Object to allow the implementer to
    * maintain a list of local configuration properties and listen for changes 
    * to those properties dynamically using CustomEvent. The initial values are 
    * also maintained so that the configuration can be reset at any given point 
    * to its initial state.
    * @namespace YAHOO.util
    * @class Config
    * @constructor
    * @param {Object} owner The owner Object to which this Config Object belongs
    */
    YAHOO.util.Config = function (owner) {

        if (owner) {
            this.init(owner);
        }


    };


    var Lang = YAHOO.lang,
        CustomEvent = YAHOO.util.CustomEvent,
        Config = YAHOO.util.Config;


    /**
     * Constant representing the CustomEvent type for the config changed event.
     * @property YAHOO.util.Config.CONFIG_CHANGED_EVENT
     * @private
     * @static
     * @final
     */
    Config.CONFIG_CHANGED_EVENT = "configChanged";
    
    /**
     * Constant representing the boolean type string
     * @property YAHOO.util.Config.BOOLEAN_TYPE
     * @private
     * @static
     * @final
     */
    Config.BOOLEAN_TYPE = "boolean";
    
    Config.prototype = {
     
        /**
        * Object reference to the owner of this Config Object
        * @property owner
        * @type Object
        */
        owner: null,
        
        /**
        * Boolean flag that specifies whether a queue is currently 
        * being executed
        * @property queueInProgress
        * @type Boolean
        */
        queueInProgress: false,
        
        /**
        * Maintains the local collection of configuration property objects and 
        * their specified values
        * @property config
        * @private
        * @type Object
        */ 
        config: null,
        
        /**
        * Maintains the local collection of configuration property objects as 
        * they were initially applied.
        * This object is used when resetting a property.
        * @property initialConfig
        * @private
        * @type Object
        */ 
        initialConfig: null,
        
        /**
        * Maintains the local, normalized CustomEvent queue
        * @property eventQueue
        * @private
        * @type Object
        */ 
        eventQueue: null,
        
        /**
        * Custom Event, notifying subscribers when Config properties are set 
        * (setProperty is called without the silent flag
        * @event configChangedEvent
        */
        configChangedEvent: null,
    
        /**
        * Initializes the configuration Object and all of its local members.
        * @method init
        * @param {Object} owner The owner Object to which this Config 
        * Object belongs
        */
        init: function (owner) {
    
            this.owner = owner;
    
            this.configChangedEvent = 
                this.createEvent(Config.CONFIG_CHANGED_EVENT);
    
            this.configChangedEvent.signature = CustomEvent.LIST;
            this.queueInProgress = false;
            this.config = {};
            this.initialConfig = {};
            this.eventQueue = [];
        
        },
        
        /**
        * Validates that the value passed in is a Boolean.
        * @method checkBoolean
        * @param {Object} val The value to validate
        * @return {Boolean} true, if the value is valid
        */ 
        checkBoolean: function (val) {
            return (typeof val == Config.BOOLEAN_TYPE);
        },
        
        /**
        * Validates that the value passed in is a number.
        * @method checkNumber
        * @param {Object} val The value to validate
        * @return {Boolean} true, if the value is valid
        */
        checkNumber: function (val) {
            return (!isNaN(val));
        },
        
        /**
        * Fires a configuration property event using the specified value. 
        * @method fireEvent
        * @private
        * @param {String} key The configuration property's name
        * @param {value} Object The value of the correct type for the property
        */ 
        fireEvent: function ( key, value ) {
            var property = this.config[key];
        
            if (property && property.event) {
                property.event.fire(value);
            } 
        },
        
        /**
        * Adds a property to the Config Object's private config hash.
        * @method addProperty
        * @param {String} key The configuration property's name
        * @param {Object} propertyObject The Object containing all of this 
        * property's arguments
        */
        addProperty: function ( key, propertyObject ) {
            key = key.toLowerCase();
        
            this.config[key] = propertyObject;
        
            propertyObject.event = this.createEvent(key, { scope: this.owner });
            propertyObject.event.signature = CustomEvent.LIST;
            
            
            propertyObject.key = key;
        
            if (propertyObject.handler) {
                propertyObject.event.subscribe(propertyObject.handler, 
                    this.owner);
            }
        
            this.setProperty(key, propertyObject.value, true);
            
            if (! propertyObject.suppressEvent) {
                this.queueProperty(key, propertyObject.value);
            }
            
        },
        
        /**
        * Returns a key-value configuration map of the values currently set in  
        * the Config Object.
        * @method getConfig
        * @return {Object} The current config, represented in a key-value map
        */
        getConfig: function () {
        
            var cfg = {},
                prop,
                property;
                
            for (prop in this.config) {
                property = this.config[prop];
                if (property && property.event) {
                    cfg[prop] = property.value;
                }
            }
            
            return cfg;
        },
        
        /**
        * Returns the value of specified property.
        * @method getProperty
        * @param {String} key The name of the property
        * @return {Object}  The value of the specified property
        */
        getProperty: function (key) {
            var property = this.config[key.toLowerCase()];
            if (property && property.event) {
                return property.value;
            } else {
                return undefined;
            }
        },
        
        /**
        * Resets the specified property's value to its initial value.
        * @method resetProperty
        * @param {String} key The name of the property
        * @return {Boolean} True is the property was reset, false if not
        */
        resetProperty: function (key) {
    
            key = key.toLowerCase();
        
            var property = this.config[key];
    
            if (property && property.event) {
    
                if (this.initialConfig[key] && 
                    !Lang.isUndefined(this.initialConfig[key])) {
    
                    this.setProperty(key, this.initialConfig[key]);

                    return true;
    
                }
    
            } else {
    
                return false;
            }
    
        },
        
        /**
        * Sets the value of a property. If the silent property is passed as 
        * true, the property's event will not be fired.
        * @method setProperty
        * @param {String} key The name of the property
        * @param {String} value The value to set the property to
        * @param {Boolean} silent Whether the value should be set silently, 
        * without firing the property event.
        * @return {Boolean} True, if the set was successful, false if it failed.
        */
        setProperty: function (key, value, silent) {
        
            var property;
        
            key = key.toLowerCase();
        
            if (this.queueInProgress && ! silent) {
                // Currently running through a queue... 
                this.queueProperty(key,value);
                return true;
    
            } else {
                property = this.config[key];
                if (property && property.event) {
                    if (property.validator && !property.validator(value)) {
                        return false;
                    } else {
                        property.value = value;
                        if (! silent) {
                            this.fireEvent(key, value);
                            this.configChangedEvent.fire([key, value]);
                        }
                        return true;
                    }
                } else {
                    return false;
                }
            }
        },
        
        /**
        * Sets the value of a property and queues its event to execute. If the 
        * event is already scheduled to execute, it is
        * moved from its current position to the end of the queue.
        * @method queueProperty
        * @param {String} key The name of the property
        * @param {String} value The value to set the property to
        * @return {Boolean}  true, if the set was successful, false if 
        * it failed.
        */ 
        queueProperty: function (key, value) {
        
            key = key.toLowerCase();
        
            var property = this.config[key],
                foundDuplicate = false,
                iLen,
                queueItem,
                queueItemKey,
                queueItemValue,
                sLen,
                supercedesCheck,
                qLen,
                queueItemCheck,
                queueItemCheckKey,
                queueItemCheckValue,
                i,
                s,
                q;
                                
            if (property && property.event) {
    
                if (!Lang.isUndefined(value) && property.validator && 
                    !property.validator(value)) { // validator
                    return false;
                } else {
        
                    if (!Lang.isUndefined(value)) {
                        property.value = value;
                    } else {
                        value = property.value;
                    }
        
                    foundDuplicate = false;
                    iLen = this.eventQueue.length;
        
                    for (i = 0; i < iLen; i++) {
                        queueItem = this.eventQueue[i];
        
                        if (queueItem) {
                            queueItemKey = queueItem[0];
                            queueItemValue = queueItem[1];

                            if (queueItemKey == key) {
    
                                /*
                                    found a dupe... push to end of queue, null 
                                    current item, and break
                                */
    
                                this.eventQueue[i] = null;
    
                                this.eventQueue.push(
                                    [key, (!Lang.isUndefined(value) ? 
                                    value : queueItemValue)]);
    
                                foundDuplicate = true;
                                break;
                            }
                        }
                    }
                    
                    // this is a refire, or a new property in the queue
    
                    if (! foundDuplicate && !Lang.isUndefined(value)) { 
                        this.eventQueue.push([key, value]);
                    }
                }
        
                if (property.supercedes) {

                    sLen = property.supercedes.length;

                    for (s = 0; s < sLen; s++) {

                        supercedesCheck = property.supercedes[s];
                        qLen = this.eventQueue.length;

                        for (q = 0; q < qLen; q++) {
                            queueItemCheck = this.eventQueue[q];

                            if (queueItemCheck) {
                                queueItemCheckKey = queueItemCheck[0];
                                queueItemCheckValue = queueItemCheck[1];

                                if (queueItemCheckKey == 
                                    supercedesCheck.toLowerCase() ) {

                                    this.eventQueue.push([queueItemCheckKey, 
                                        queueItemCheckValue]);

                                    this.eventQueue[q] = null;
                                    break;

                                }
                            }
                        }
                    }
                }


                return true;
            } else {
                return false;
            }
        },
        
        /**
        * Fires the event for a property using the property's current value.
        * @method refireEvent
        * @param {String} key The name of the property
        */
        refireEvent: function (key) {
    
            key = key.toLowerCase();
        
            var property = this.config[key];
    
            if (property && property.event && 
    
                !Lang.isUndefined(property.value)) {
    
                if (this.queueInProgress) {
    
                    this.queueProperty(key);
    
                } else {
    
                    this.fireEvent(key, property.value);
    
                }
    
            }
        },
        
        /**
        * Applies a key-value Object literal to the configuration, replacing  
        * any existing values, and queueing the property events.
        * Although the values will be set, fireQueue() must be called for their 
        * associated events to execute.
        * @method applyConfig
        * @param {Object} userConfig The configuration Object literal
        * @param {Boolean} init  When set to true, the initialConfig will 
        * be set to the userConfig passed in, so that calling a reset will 
        * reset the properties to the passed values.
        */
        applyConfig: function (userConfig, init) {
        
            var sKey,
                oConfig;

            if (init) {
                oConfig = {};
                for (sKey in userConfig) {
                    if (Lang.hasOwnProperty(userConfig, sKey)) {
                        oConfig[sKey.toLowerCase()] = userConfig[sKey];
                    }
                }
                this.initialConfig = oConfig;
            }

            for (sKey in userConfig) {
                if (Lang.hasOwnProperty(userConfig, sKey)) {
                    this.queueProperty(sKey, userConfig[sKey]);
                }
            }
        },
        
        /**
        * Refires the events for all configuration properties using their 
        * current values.
        * @method refresh
        */
        refresh: function () {
        
            var prop;
        
            for (prop in this.config) {
                this.refireEvent(prop);
            }
        },
        
        /**
        * Fires the normalized list of queued property change events
        * @method fireQueue
        */
        fireQueue: function () {
        
            var i, 
                queueItem,
                key,
                value,
                property;
        
            this.queueInProgress = true;
            for (i = 0;i < this.eventQueue.length; i++) {
                queueItem = this.eventQueue[i];
                if (queueItem) {
        
                    key = queueItem[0];
                    value = queueItem[1];
                    property = this.config[key];
        
                    property.value = value;
        
                    this.fireEvent(key,value);
                }
            }
            
            this.queueInProgress = false;
            this.eventQueue = [];
        },
        
        /**
        * Subscribes an external handler to the change event for any 
        * given property. 
        * @method subscribeToConfigEvent
        * @param {String} key The property name
        * @param {Function} handler The handler function to use subscribe to 
        * the property's event
        * @param {Object} obj The Object to use for scoping the event handler 
        * (see CustomEvent documentation)
        * @param {Boolean} override Optional. If true, will override "this"  
        * within the handler to map to the scope Object passed into the method.
        * @return {Boolean} True, if the subscription was successful, 
        * otherwise false.
        */ 
        subscribeToConfigEvent: function (key, handler, obj, override) {
    
            var property = this.config[key.toLowerCase()];
    
            if (property && property.event) {
                if (!Config.alreadySubscribed(property.event, handler, obj)) {
                    property.event.subscribe(handler, obj, override);
                }
                return true;
            } else {
                return false;
            }
    
        },
        
        /**
        * Unsubscribes an external handler from the change event for any 
        * given property. 
        * @method unsubscribeFromConfigEvent
        * @param {String} key The property name
        * @param {Function} handler The handler function to use subscribe to 
        * the property's event
        * @param {Object} obj The Object to use for scoping the event 
        * handler (see CustomEvent documentation)
        * @return {Boolean} True, if the unsubscription was successful, 
        * otherwise false.
        */
        unsubscribeFromConfigEvent: function (key, handler, obj) {
            var property = this.config[key.toLowerCase()];
            if (property && property.event) {
                return property.event.unsubscribe(handler, obj);
            } else {
                return false;
            }
        },
        
        /**
        * Returns a string representation of the Config object
        * @method toString
        * @return {String} The Config object in string format.
        */
        toString: function () {
            var output = "Config";
            if (this.owner) {
                output += " [" + this.owner.toString() + "]";
            }
            return output;
        },
        
        /**
        * Returns a string representation of the Config object's current 
        * CustomEvent queue
        * @method outputEventQueue
        * @return {String} The string list of CustomEvents currently queued 
        * for execution
        */
        outputEventQueue: function () {

            var output = "",
                queueItem,
                q,
                nQueue = this.eventQueue.length;
              
            for (q = 0; q < nQueue; q++) {
                queueItem = this.eventQueue[q];
                if (queueItem) {
                    output += queueItem[0] + "=" + queueItem[1] + ", ";
                }
            }
            return output;
        },

        /**
        * Sets all properties to null, unsubscribes all listeners from each 
        * property's change event and all listeners from the configChangedEvent.
        * @method destroy
        */
        destroy: function () {

            var oConfig = this.config,
                sProperty,
                oProperty;


            for (sProperty in oConfig) {
            
                if (Lang.hasOwnProperty(oConfig, sProperty)) {

                    oProperty = oConfig[sProperty];

                    oProperty.event.unsubscribeAll();
                    oProperty.event = null;

                }
            
            }
            
            this.configChangedEvent.unsubscribeAll();
            
            this.configChangedEvent = null;
            this.owner = null;
            this.config = null;
            this.initialConfig = null;
            this.eventQueue = null;
        
        }

    };
    
    
    
    /**
    * Checks to determine if a particular function/Object pair are already 
    * subscribed to the specified CustomEvent
    * @method YAHOO.util.Config.alreadySubscribed
    * @static
    * @param {YAHOO.util.CustomEvent} evt The CustomEvent for which to check 
    * the subscriptions
    * @param {Function} fn The function to look for in the subscribers list
    * @param {Object} obj The execution scope Object for the subscription
    * @return {Boolean} true, if the function/Object pair is already subscribed 
    * to the CustomEvent passed in
    */
    Config.alreadySubscribed = function (evt, fn, obj) {
    
        var nSubscribers = evt.subscribers.length,
            subsc,
            i;

        if (nSubscribers > 0) {
            i = nSubscribers - 1;
            do {
                subsc = evt.subscribers[i];
                if (subsc && subsc.obj == obj && subsc.fn == fn) {
                    return true;
                }
            }
            while (i--);
        }

        return false;

    };

    YAHOO.lang.augmentProto(Config, YAHOO.util.EventProvider);

}());

/**
* YAHOO.widget.DateMath is used for simple date manipulation. The class is a static utility
* used for adding, subtracting, and comparing dates.
* @namespace YAHOO.widget
* @class DateMath
*/
YAHOO.widget.DateMath = {
	/**
	* Constant field representing Day
	* @property DAY
	* @static
	* @final
	* @type String
	*/
	DAY : "D",

	/**
	* Constant field representing Week
	* @property WEEK
	* @static
	* @final
	* @type String
	*/
	WEEK : "W",

	/**
	* Constant field representing Year
	* @property YEAR
	* @static
	* @final
	* @type String
	*/
	YEAR : "Y",

	/**
	* Constant field representing Month
	* @property MONTH
	* @static
	* @final
	* @type String
	*/
	MONTH : "M",

	/**
	* Constant field representing one day, in milliseconds
	* @property ONE_DAY_MS
	* @static
	* @final
	* @type Number
	*/
	ONE_DAY_MS : 1000*60*60*24,
	
	/**
	 * Constant field representing the date in first week of January
	 * which identifies the first week of the year.
	 * <p>
	 * In the U.S, Jan 1st is normally used based on a Sunday start of week.
	 * ISO 8601, used widely throughout Europe, uses Jan 4th, based on a Monday start of week.
	 * </p>
	 * @property WEEK_ONE_JAN_DATE
	 * @static
	 * @type Number
	 */
	WEEK_ONE_JAN_DATE : 1,

	/**
	* Adds the specified amount of time to the this instance.
	* @method add
	* @param {Date} date	The JavaScript Date object to perform addition on
	* @param {String} field	The field constant to be used for performing addition.
	* @param {Number} amount	The number of units (measured in the field constant) to add to the date.
	* @return {Date} The resulting Date object
	*/
	add : function(date, field, amount) {
		var d = new Date(date.getTime());
		switch (field) {
			case this.MONTH:
				var newMonth = date.getMonth() + amount;
				var years = 0;

				if (newMonth < 0) {
					while (newMonth < 0) {
						newMonth += 12;
						years -= 1;
					}
				} else if (newMonth > 11) {
					while (newMonth > 11) {
						newMonth -= 12;
						years += 1;
					}
				}

				d.setMonth(newMonth);
				d.setFullYear(date.getFullYear() + years);
				break;
			case this.DAY:
				this._addDays(d, amount);
				// d.setDate(date.getDate() + amount);
				break;
			case this.YEAR:
				d.setFullYear(date.getFullYear() + amount);
				break;
			case this.WEEK:
				this._addDays(d, (amount * 7));
				// d.setDate(date.getDate() + (amount * 7));
				break;
		}
		return d;
	},

	/**
	 * Private helper method to account for bug in Safari 2 (webkit < 420)
	 * when Date.setDate(n) is called with n less than -128 or greater than 127.
	 * <p>
	 * Fix approach and original findings are available here:
	 * http://brianary.blogspot.com/2006/03/safari-date-bug.html
	 * </p>
	 * @method _addDays
	 * @param {Date} d JavaScript date object
	 * @param {Number} nDays The number of days to add to the date object (can be negative)
	 * @private
	 */
	_addDays : function(d, nDays) {
		if (YAHOO.env.ua.webkit && YAHOO.env.ua.webkit < 420) {
			if (nDays < 0) {
				// Ensure we don't go below -128 (getDate() is always 1 to 31, so we won't go above 127)
				for(var min = -128; nDays < min; nDays -= min) {
					d.setDate(d.getDate() + min);
				}
			} else {
				// Ensure we don't go above 96 + 31 = 127
				for(var max = 96; nDays > max; nDays -= max) {
					d.setDate(d.getDate() + max);
				}
			}
			// nDays should be remainder between -128 and 96
		}
		d.setDate(d.getDate() + nDays);
	},

	/**
	* Subtracts the specified amount of time from the this instance.
	* @method subtract
	* @param {Date} date	The JavaScript Date object to perform subtraction on
	* @param {Number} field	The this field constant to be used for performing subtraction.
	* @param {Number} amount	The number of units (measured in the field constant) to subtract from the date.
	* @return {Date} The resulting Date object
	*/
	subtract : function(date, field, amount) {
		return this.add(date, field, (amount*-1));
	},

	/**
	* Determines whether a given date is before another date on the calendar.
	* @method before
	* @param {Date} date		The Date object to compare with the compare argument
	* @param {Date} compareTo	The Date object to use for the comparison
	* @return {Boolean} true if the date occurs before the compared date; false if not.
	*/
	before : function(date, compareTo) {
		var ms = compareTo.getTime();
		if (date.getTime() < ms) {
			return true;
		} else {
			return false;
		}
	},

	/**
	* Determines whether a given date is after another date on the calendar.
	* @method after
	* @param {Date} date		The Date object to compare with the compare argument
	* @param {Date} compareTo	The Date object to use for the comparison
	* @return {Boolean} true if the date occurs after the compared date; false if not.
	*/
	after : function(date, compareTo) {
		var ms = compareTo.getTime();
		if (date.getTime() > ms) {
			return true;
		} else {
			return false;
		}
	},

	/**
	* Determines whether a given date is between two other dates on the calendar.
	* @method between
	* @param {Date} date		The date to check for
	* @param {Date} dateBegin	The start of the range
	* @param {Date} dateEnd		The end of the range
	* @return {Boolean} true if the date occurs between the compared dates; false if not.
	*/
	between : function(date, dateBegin, dateEnd) {
		if (this.after(date, dateBegin) && this.before(date, dateEnd)) {
			return true;
		} else {
			return false;
		}
	},
	
	/**
	* Retrieves a JavaScript Date object representing January 1 of any given year.
	* @method getJan1
	* @param {Number} calendarYear		The calendar year for which to retrieve January 1
	* @return {Date}	January 1 of the calendar year specified.
	*/
	getJan1 : function(calendarYear) {
		return this.getDate(calendarYear,0,1);
	},

	/**
	* Calculates the number of days the specified date is from January 1 of the specified calendar year.
	* Passing January 1 to this function would return an offset value of zero.
	* @method getDayOffset
	* @param {Date}	date	The JavaScript date for which to find the offset
	* @param {Number} calendarYear	The calendar year to use for determining the offset
	* @return {Number}	The number of days since January 1 of the given year
	*/
	getDayOffset : function(date, calendarYear) {
		var beginYear = this.getJan1(calendarYear); // Find the start of the year. This will be in week 1.
		
		// Find the number of days the passed in date is away from the calendar year start
		var dayOffset = Math.ceil((date.getTime()-beginYear.getTime()) / this.ONE_DAY_MS);
		return dayOffset;
	},

	/**
	* Calculates the week number for the given date. Can currently support standard
	* U.S. week numbers, based on Jan 1st defining the 1st week of the year, and 
	* ISO8601 week numbers, based on Jan 4th defining the 1st week of the year.
	* 
	* @method getWeekNumber
	* @param {Date}	date The JavaScript date for which to find the week number
	* @param {Number} firstDayOfWeek The index of the first day of the week (0 = Sun, 1 = Mon ... 6 = Sat).
	* Defaults to 0
	* @param {Number} janDate The date in the first week of January which defines week one for the year
	* Defaults to the value of YAHOO.widget.DateMath.WEEK_ONE_JAN_DATE, which is 1 (Jan 1st). 
	* For the U.S, this is normally Jan 1st. ISO8601 uses Jan 4th to define the first week of the year.
	* 
	* @return {Number} The number of the week containing the given date.
	*/
	getWeekNumber : function(date, firstDayOfWeek, janDate) {

		// Setup Defaults
		firstDayOfWeek = firstDayOfWeek || 0;
		janDate = janDate || this.WEEK_ONE_JAN_DATE;

		var targetDate = this.clearTime(date),
			startOfWeek,
			endOfWeek;

		if (targetDate.getDay() === firstDayOfWeek) { 
			startOfWeek = targetDate;
		} else {
			startOfWeek = this.getFirstDayOfWeek(targetDate, firstDayOfWeek);
		}

		var startYear = startOfWeek.getFullYear(),
			startTime = startOfWeek.getTime();

		// DST shouldn't be a problem here, math is quicker than setDate();
		endOfWeek = new Date(startOfWeek.getTime() + 6*this.ONE_DAY_MS);

		var weekNum;
		if (startYear !== endOfWeek.getFullYear() && endOfWeek.getDate() >= janDate) {
			// If years don't match, endOfWeek is in Jan. and if the 
			// week has WEEK_ONE_JAN_DATE in it, it's week one by definition.
			weekNum = 1;
		} else {
			// Get the 1st day of the 1st week, and 
			// find how many days away we are from it.
			var weekOne = this.clearTime(this.getDate(startYear, 0, janDate)),
				weekOneDayOne = this.getFirstDayOfWeek(weekOne, firstDayOfWeek);

			// Round days to smoothen out 1 hr DST diff
			var daysDiff  = Math.round((targetDate.getTime() - weekOneDayOne.getTime())/this.ONE_DAY_MS);

			// Calc. Full Weeks
			var rem = daysDiff % 7;
			var weeksDiff = (daysDiff - rem)/7;
			weekNum = weeksDiff + 1;
		}
		return weekNum;
	},

	/**
	 * Get the first day of the week, for the give date. 
	 * @param {Date} dt The date in the week for which the first day is required.
	 * @param {Number} startOfWeek The index for the first day of the week, 0 = Sun, 1 = Mon ... 6 = Sat (defaults to 0)
	 * @return {Date} The first day of the week
	 */
	getFirstDayOfWeek : function (dt, startOfWeek) {
		startOfWeek = startOfWeek || 0;
		var dayOfWeekIndex = dt.getDay(),
			dayOfWeek = (dayOfWeekIndex - startOfWeek + 7) % 7;

		return this.subtract(dt, this.DAY, dayOfWeek);
	},

	/**
	* Determines if a given week overlaps two different years.
	* @method isYearOverlapWeek
	* @param {Date}	weekBeginDate	The JavaScript Date representing the first day of the week.
	* @return {Boolean}	true if the date overlaps two different years.
	*/
	isYearOverlapWeek : function(weekBeginDate) {
		var overlaps = false;
		var nextWeek = this.add(weekBeginDate, this.DAY, 6);
		if (nextWeek.getFullYear() != weekBeginDate.getFullYear()) {
			overlaps = true;
		}
		return overlaps;
	},

	/**
	* Determines if a given week overlaps two different months.
	* @method isMonthOverlapWeek
	* @param {Date}	weekBeginDate	The JavaScript Date representing the first day of the week.
	* @return {Boolean}	true if the date overlaps two different months.
	*/
	isMonthOverlapWeek : function(weekBeginDate) {
		var overlaps = false;
		var nextWeek = this.add(weekBeginDate, this.DAY, 6);
		if (nextWeek.getMonth() != weekBeginDate.getMonth()) {
			overlaps = true;
		}
		return overlaps;
	},

	/**
	* Gets the first day of a month containing a given date.
	* @method findMonthStart
	* @param {Date}	date	The JavaScript Date used to calculate the month start
	* @return {Date}		The JavaScript Date representing the first day of the month
	*/
	findMonthStart : function(date) {
		var start = this.getDate(date.getFullYear(), date.getMonth(), 1);
		return start;
	},

	/**
	* Gets the last day of a month containing a given date.
	* @method findMonthEnd
	* @param {Date}	date	The JavaScript Date used to calculate the month end
	* @return {Date}		The JavaScript Date representing the last day of the month
	*/
	findMonthEnd : function(date) {
		var start = this.findMonthStart(date);
		var nextMonth = this.add(start, this.MONTH, 1);
		var end = this.subtract(nextMonth, this.DAY, 1);
		return end;
	},

	/**
	* Clears the time fields from a given date, effectively setting the time to 12 noon.
	* @method clearTime
	* @param {Date}	date	The JavaScript Date for which the time fields will be cleared
	* @return {Date}		The JavaScript Date cleared of all time fields
	*/
	clearTime : function(date) {
		date.setHours(12,0,0,0);
		return date;
	},

	/**
	 * Returns a new JavaScript Date object, representing the given year, month and date. Time fields (hr, min, sec, ms) on the new Date object
	 * are set to 0. The method allows Date instances to be created with the a year less than 100. "new Date(year, month, date)" implementations 
	 * set the year to 19xx if a year (xx) which is less than 100 is provided.
	 * <p>
	 * <em>NOTE:</em>Validation on argument values is not performed. It is the caller's responsibility to ensure
	 * arguments are valid as per the ECMAScript-262 Date object specification for the new Date(year, month[, date]) constructor.
	 * </p>
	 * @method getDate
	 * @param {Number} y Year.
	 * @param {Number} m Month index from 0 (Jan) to 11 (Dec).
	 * @param {Number} d (optional) Date from 1 to 31. If not provided, defaults to 1.
	 * @return {Date} The JavaScript date object with year, month, date set as provided.
	 */
	getDate : function(y, m, d) {
		var dt = null;
		if (YAHOO.lang.isUndefined(d)) {
			d = 1;
		}
		if (y >= 100) {
			dt = new Date(y, m, d);
		} else {
			dt = new Date();
			dt.setFullYear(y);
			dt.setMonth(m);
			dt.setDate(d);
			dt.setHours(0,0,0,0);
		}
		return dt;
	}
};

/**
* The Calendar component is a UI control that enables users to choose one or more dates from a graphical calendar presented in a one-month or
* multi-month interface. Calendars are generated entirely via script and can be navigated without any page refreshes.
* @module    calendar
* @title    Calendar
* @namespace  YAHOO.widget
* @requires  yahoo,dom,event
*/

/**
* Calendar is the base class for the Calendar widget. In its most basic
* implementation, it has the ability to render a calendar widget on the page
* that can be manipulated to select a single date, move back and forth between
* months and years.
* <p>To construct the placeholder for the calendar widget, the code is as
* follows:
*	<xmp>
*		<div id="calContainer"></div>
*	</xmp>
* </p>
* <p>
* <strong>NOTE: As of 2.4.0, the constructor's ID argument is optional.</strong>
* The Calendar can be constructed by simply providing a container ID string, 
* or a reference to a container DIV HTMLElement (the element needs to exist 
* in the document).
* 
* E.g.:
*	<xmp>
*		var c = new YAHOO.widget.Calendar("calContainer", configOptions);
*	</xmp>
* or:
*   <xmp>
*       var containerDiv = YAHOO.util.Dom.get("calContainer");
*		var c = new YAHOO.widget.Calendar(containerDiv, configOptions);
*	</xmp>
* </p>
* <p>
* If not provided, the ID will be generated from the container DIV ID by adding an "_t" suffix.
* For example if an ID is not provided, and the container's ID is "calContainer", the Calendar's ID will be set to "calContainer_t".
* </p>
* 
* @namespace YAHOO.widget
* @class Calendar
* @constructor
* @param {String} id optional The id of the table element that will represent the Calendar widget. As of 2.4.0, this argument is optional.
* @param {String | HTMLElement} container The id of the container div element that will wrap the Calendar table, or a reference to a DIV element which exists in the document.
* @param {Object} config optional The configuration object containing the initial configuration values for the Calendar.
*/
YAHOO.widget.Calendar = function(id, containerId, config) {
	this.init.apply(this, arguments);
};

/**
* The path to be used for images loaded for the Calendar
* @property YAHOO.widget.Calendar.IMG_ROOT
* @static
* @deprecated	You can now customize images by overriding the calclose, calnavleft and calnavright default CSS classes for the close icon, left arrow and right arrow respectively
* @type String
*/
YAHOO.widget.Calendar.IMG_ROOT = null;

/**
* Type constant used for renderers to represent an individual date (M/D/Y)
* @property YAHOO.widget.Calendar.DATE
* @static
* @final
* @type String
*/
YAHOO.widget.Calendar.DATE = "D";

/**
* Type constant used for renderers to represent an individual date across any year (M/D)
* @property YAHOO.widget.Calendar.MONTH_DAY
* @static
* @final
* @type String
*/
YAHOO.widget.Calendar.MONTH_DAY = "MD";

/**
* Type constant used for renderers to represent a weekday
* @property YAHOO.widget.Calendar.WEEKDAY
* @static
* @final
* @type String
*/
YAHOO.widget.Calendar.WEEKDAY = "WD";

/**
* Type constant used for renderers to represent a range of individual dates (M/D/Y-M/D/Y)
* @property YAHOO.widget.Calendar.RANGE
* @static
* @final
* @type String
*/
YAHOO.widget.Calendar.RANGE = "R";

/**
* Type constant used for renderers to represent a month across any year
* @property YAHOO.widget.Calendar.MONTH
* @static
* @final
* @type String
*/
YAHOO.widget.Calendar.MONTH = "M";

/**
* Constant that represents the total number of date cells that are displayed in a given month
* @property YAHOO.widget.Calendar.DISPLAY_DAYS
* @static
* @final
* @type Number
*/
YAHOO.widget.Calendar.DISPLAY_DAYS = 42;

/**
* Constant used for halting the execution of the remainder of the render stack
* @property YAHOO.widget.Calendar.STOP_RENDER
* @static
* @final
* @type String
*/
YAHOO.widget.Calendar.STOP_RENDER = "S";

/**
* Constant used to represent short date field string formats (e.g. Tu or Feb)
* @property YAHOO.widget.Calendar.SHORT
* @static
* @final
* @type String
*/
YAHOO.widget.Calendar.SHORT = "short";

/**
* Constant used to represent long date field string formats (e.g. Monday or February)
* @property YAHOO.widget.Calendar.LONG
* @static
* @final
* @type String
*/
YAHOO.widget.Calendar.LONG = "long";

/**
* Constant used to represent medium date field string formats (e.g. Mon)
* @property YAHOO.widget.Calendar.MEDIUM
* @static
* @final
* @type String
*/
YAHOO.widget.Calendar.MEDIUM = "medium";

/**
* Constant used to represent single character date field string formats (e.g. M, T, W)
* @property YAHOO.widget.Calendar.ONE_CHAR
* @static
* @final
* @type String
*/
YAHOO.widget.Calendar.ONE_CHAR = "1char";

/**
* The set of default Config property keys and values for the Calendar
* @property YAHOO.widget.Calendar._DEFAULT_CONFIG
* @final
* @static
* @private
* @type Object
*/
YAHOO.widget.Calendar._DEFAULT_CONFIG = {
	// Default values for pagedate and selected are not class level constants - they are set during instance creation 
	PAGEDATE : {key:"pagedate", value:null},
	SELECTED : {key:"selected", value:null},
	TITLE : {key:"title", value:""},
	CLOSE : {key:"close", value:false},
	IFRAME : {key:"iframe", value:(YAHOO.env.ua.ie && YAHOO.env.ua.ie <= 6) ? true : false},
	MINDATE : {key:"mindate", value:null},
	MAXDATE : {key:"maxdate", value:null},
	MULTI_SELECT : {key:"multi_select", value:false},
	START_WEEKDAY : {key:"start_weekday", value:0},
	SHOW_WEEKDAYS : {key:"show_weekdays", value:true},
	SHOW_WEEK_HEADER : {key:"show_week_header", value:false},
	SHOW_WEEK_FOOTER : {key:"show_week_footer", value:false},
	HIDE_BLANK_WEEKS : {key:"hide_blank_weeks", value:false},
	NAV_ARROW_LEFT: {key:"nav_arrow_left", value:null} ,
	NAV_ARROW_RIGHT : {key:"nav_arrow_right", value:null} ,
	MONTHS_SHORT : {key:"months_short", value:["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]},
	MONTHS_LONG: {key:"months_long", value:["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]},
	WEEKDAYS_1CHAR: {key:"weekdays_1char", value:["S", "M", "T", "W", "T", "F", "S"]},
	WEEKDAYS_SHORT: {key:"weekdays_short", value:["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"]},
	WEEKDAYS_MEDIUM: {key:"weekdays_medium", value:["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]},
	WEEKDAYS_LONG: {key:"weekdays_long", value:["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]},
	LOCALE_MONTHS:{key:"locale_months", value:"long"},
	LOCALE_WEEKDAYS:{key:"locale_weekdays", value:"short"},
	DATE_DELIMITER:{key:"date_delimiter", value:","},
	DATE_FIELD_DELIMITER:{key:"date_field_delimiter", value:"/"},
	DATE_RANGE_DELIMITER:{key:"date_range_delimiter", value:"-"},
	MY_MONTH_POSITION:{key:"my_month_position", value:1},
	MY_YEAR_POSITION:{key:"my_year_position", value:2},
	MD_MONTH_POSITION:{key:"md_month_position", value:1},
	MD_DAY_POSITION:{key:"md_day_position", value:2},
	MDY_MONTH_POSITION:{key:"mdy_month_position", value:1},
	MDY_DAY_POSITION:{key:"mdy_day_position", value:2},
	MDY_YEAR_POSITION:{key:"mdy_year_position", value:3},
	MY_LABEL_MONTH_POSITION:{key:"my_label_month_position", value:1},
	MY_LABEL_YEAR_POSITION:{key:"my_label_year_position", value:2},
	MY_LABEL_MONTH_SUFFIX:{key:"my_label_month_suffix", value:" "},
	MY_LABEL_YEAR_SUFFIX:{key:"my_label_year_suffix", value:""},
	NAV: {key:"navigator", value: null}
};

/**
* The set of Custom Event types supported by the Calendar
* @property YAHOO.widget.Calendar._EVENT_TYPES
* @final
* @static
* @private
* @type Object
*/
YAHOO.widget.Calendar._EVENT_TYPES = {
	BEFORE_SELECT : "beforeSelect", 
	SELECT : "select",
	BEFORE_DESELECT : "beforeDeselect",
	DESELECT : "deselect",
	CHANGE_PAGE : "changePage",
	BEFORE_RENDER : "beforeRender",
	RENDER : "render",
	RESET : "reset",
	CLEAR : "clear",
	BEFORE_HIDE : "beforeHide",
	HIDE : "hide",
	BEFORE_SHOW : "beforeShow",
	SHOW : "show",
	BEFORE_HIDE_NAV : "beforeHideNav",
	HIDE_NAV : "hideNav",
	BEFORE_SHOW_NAV : "beforeShowNav",
	SHOW_NAV : "showNav",
	BEFORE_RENDER_NAV : "beforeRenderNav",
	RENDER_NAV : "renderNav"
};

/**
* The set of default style constants for the Calendar
* @property YAHOO.widget.Calendar._STYLES
* @final
* @static
* @private
* @type Object
*/
YAHOO.widget.Calendar._STYLES = {
	CSS_ROW_HEADER: "calrowhead",
	CSS_ROW_FOOTER: "calrowfoot",
	CSS_CELL : "calcell",
	CSS_CELL_SELECTOR : "selector",
	CSS_CELL_SELECTED : "selected",
	CSS_CELL_SELECTABLE : "selectable",
	CSS_CELL_RESTRICTED : "restricted",
	CSS_CELL_TODAY : "today",
	CSS_CELL_OOM : "oom",
	CSS_CELL_OOB : "previous",
	CSS_HEADER : "calheader",
	CSS_HEADER_TEXT : "calhead",
	CSS_BODY : "calbody",
	CSS_WEEKDAY_CELL : "calweekdaycell",
	CSS_WEEKDAY_ROW : "calweekdayrow",
	CSS_FOOTER : "calfoot",
	CSS_CALENDAR : "yui-calendar",
	CSS_SINGLE : "single",
	CSS_CONTAINER : "yui-calcontainer",
	CSS_NAV_LEFT : "calnavleft",
	CSS_NAV_RIGHT : "calnavright",
	CSS_NAV : "calnav",
	CSS_CLOSE : "calclose",
	CSS_CELL_TOP : "calcelltop",
	CSS_CELL_LEFT : "calcellleft",
	CSS_CELL_RIGHT : "calcellright",
	CSS_CELL_BOTTOM : "calcellbottom",
	CSS_CELL_HOVER : "calcellhover",
	CSS_CELL_HIGHLIGHT1 : "highlight1",
	CSS_CELL_HIGHLIGHT2 : "highlight2",
	CSS_CELL_HIGHLIGHT3 : "highlight3",
	CSS_CELL_HIGHLIGHT4 : "highlight4"
};

YAHOO.widget.Calendar.prototype = {

	/**
	* The configuration object used to set up the calendars various locale and style options.
	* @property Config
	* @private
	* @deprecated Configuration properties should be set by calling Calendar.cfg.setProperty.
	* @type Object
	*/
	Config : null,

	/**
	* The parent CalendarGroup, only to be set explicitly by the parent group
	* @property parent
	* @type CalendarGroup
	*/	
	parent : null,

	/**
	* The index of this item in the parent group
	* @property index
	* @type Number
	*/
	index : -1,

	/**
	* The collection of calendar table cells
	* @property cells
	* @type HTMLTableCellElement[]
	*/
	cells : null,

	/**
	* The collection of calendar cell dates that is parallel to the cells collection. The array contains dates field arrays in the format of [YYYY, M, D].
	* @property cellDates
	* @type Array[](Number[])
	*/
	cellDates : null,

	/**
	* The id that uniquely identifies this Calendar.
	* @property id
	* @type String
	*/
	id : null,

	/**
	* The unique id associated with the Calendar's container
	* @property containerId
	* @type String
	*/
	containerId: null,

	/**
	* The DOM element reference that points to this calendar's container element. The calendar will be inserted into this element when the shell is rendered.
	* @property oDomContainer
	* @type HTMLElement
	*/
	oDomContainer : null,

	/**
	* A Date object representing today's date.
	* @property today
	* @type Date
	*/
	today : null,

	/**
	* The list of render functions, along with required parameters, used to render cells. 
	* @property renderStack
	* @type Array[]
	*/
	renderStack : null,

	/**
	* A copy of the initial render functions created before rendering.
	* @property _renderStack
	* @private
	* @type Array
	*/
	_renderStack : null,

	/**
	* A reference to the CalendarNavigator instance created for this Calendar.
	* Will be null if the "navigator" configuration property has not been set
	* @property oNavigator
	* @type CalendarNavigator
	*/
	oNavigator : null,

	/**
	* The private list of initially selected dates.
	* @property _selectedDates
	* @private
	* @type Array
	*/
	_selectedDates : null,

	/**
	* A map of DOM event handlers to attach to cells associated with specific CSS class names
	* @property domEventMap
	* @type Object
	*/
	domEventMap : null,

	/**
	 * Protected helper used to parse Calendar constructor/init arguments.
	 *
	 * As of 2.4.0, Calendar supports a simpler constructor 
	 * signature. This method reconciles arguments
	 * received in the pre 2.4.0 and 2.4.0 formats.
	 * 
	 * @protected
	 * @method _parseArgs
	 * @param {Array} Function "arguments" array
	 * @return {Object} Object with id, container, config properties containing
	 * the reconciled argument values.
	 **/
	_parseArgs : function(args) {
		/*
		   2.4.0 Constructors signatures

		   new Calendar(String)
		   new Calendar(HTMLElement)
		   new Calendar(String, ConfigObject)
		   new Calendar(HTMLElement, ConfigObject)

		   Pre 2.4.0 Constructor signatures

		   new Calendar(String, String)
		   new Calendar(String, HTMLElement)
		   new Calendar(String, String, ConfigObject)
		   new Calendar(String, HTMLElement, ConfigObject)
		 */
		var nArgs = {id:null, container:null, config:null};

		if (args && args.length && args.length > 0) {
			switch (args.length) {
				case 1:
					nArgs.id = null;
					nArgs.container = args[0];
					nArgs.config = null;
					break;
				case 2:
					if (YAHOO.lang.isObject(args[1]) && !args[1].tagName && !(args[1] instanceof String)) {
						nArgs.id = null;
						nArgs.container = args[0];
						nArgs.config = args[1];
					} else {
						nArgs.id = args[0];
						nArgs.container = args[1];
						nArgs.config = null;
					}
					break;
				default: // 3+
					nArgs.id = args[0];
					nArgs.container = args[1];
					nArgs.config = args[2];
					break;
			}
		} else {
		}
		return nArgs;
	},

	/**
	* Initializes the Calendar widget.
	* @method init
	*
	* @param {String} id optional The id of the table element that will represent the Calendar widget. As of 2.4.0, this argument is optional.
	* @param {String | HTMLElement} container The id of the container div element that will wrap the Calendar table, or a reference to a DIV element which exists in the document.
	* @param {Object} config optional The configuration object containing the initial configuration values for the Calendar.
	*/
	init : function(id, container, config) {
		// Normalize 2.4.0, pre 2.4.0 args
		var nArgs = this._parseArgs(arguments);

		id = nArgs.id;
		container = nArgs.container;
		config = nArgs.config;

		this.oDomContainer = YAHOO.util.Dom.get(container);

		if (!this.oDomContainer.id) {
			this.oDomContainer.id = YAHOO.util.Dom.generateId();
		}
		if (!id) {
			id = this.oDomContainer.id + "_t";
		}

		this.id = id;
		this.containerId = this.oDomContainer.id;

		this.initEvents();

		this.today = new Date();
		YAHOO.widget.DateMath.clearTime(this.today);

		/**
		* The Config object used to hold the configuration variables for the Calendar
		* @property cfg
		* @type YAHOO.util.Config
		*/
		this.cfg = new YAHOO.util.Config(this);

		/**
		* The local object which contains the Calendar's options
		* @property Options
		* @type Object
		*/
		this.Options = {};

		/**
		* The local object which contains the Calendar's locale settings
		* @property Locale
		* @type Object
		*/
		this.Locale = {};

		this.initStyles();

		YAHOO.util.Dom.addClass(this.oDomContainer, this.Style.CSS_CONTAINER);
		YAHOO.util.Dom.addClass(this.oDomContainer, this.Style.CSS_SINGLE);

		this.cellDates = [];
		this.cells = [];
		this.renderStack = [];
		this._renderStack = [];

		this.setupConfig();

		if (config) {
			this.cfg.applyConfig(config, true);
		}

		this.cfg.fireQueue();
	},

	/**
	* Default Config listener for the iframe property. If the iframe config property is set to true, 
	* renders the built-in IFRAME shim if the container is relatively or absolutely positioned.
	* 
	* @method configIframe
	*/
	configIframe : function(type, args, obj) {
		var useIframe = args[0];
	
		if (!this.parent) {
			if (YAHOO.util.Dom.inDocument(this.oDomContainer)) {
				if (useIframe) {
					var pos = YAHOO.util.Dom.getStyle(this.oDomContainer, "position");
					
					if (pos == "absolute" || pos == "relative") {
						
						if (!YAHOO.util.Dom.inDocument(this.iframe)) {
							this.iframe = document.createElement("iframe");
							this.iframe.src = "javascript:false;";
	
							YAHOO.util.Dom.setStyle(this.iframe, "opacity", "0");
	
							if (YAHOO.env.ua.ie && YAHOO.env.ua.ie <= 6) {
								YAHOO.util.Dom.addClass(this.iframe, "fixedsize");
							}
	
							this.oDomContainer.insertBefore(this.iframe, this.oDomContainer.firstChild);
						}
					}
				} else {
					if (this.iframe) {
						if (this.iframe.parentNode) {
							this.iframe.parentNode.removeChild(this.iframe);
						}
						this.iframe = null;
					}
				}
			}
		}
	},

	/**
	* Default handler for the "title" property
	* @method configTitle
	*/
	configTitle : function(type, args, obj) {
		var title = args[0];

		// "" disables title bar
		if (title) {
			this.createTitleBar(title);
		} else {
			var close = this.cfg.getProperty(YAHOO.widget.Calendar._DEFAULT_CONFIG.CLOSE.key);
			if (!close) {
				this.removeTitleBar();
			} else {
				this.createTitleBar("&#160;");
			}
		}
	},
	
	/**
	* Default handler for the "close" property
	* @method configClose
	*/
	configClose : function(type, args, obj) {
		var close = args[0],
			title = this.cfg.getProperty(YAHOO.widget.Calendar._DEFAULT_CONFIG.TITLE.key);
	
		if (close) {
			if (!title) {
				this.createTitleBar("&#160;");
			}
			this.createCloseButton();
		} else {
			this.removeCloseButton();
			if (!title) {
				this.removeTitleBar();
			}
		}
	},
	
	/**
	* Initializes Calendar's built-in CustomEvents
	* @method initEvents
	*/
	initEvents : function() {
	
		var defEvents = YAHOO.widget.Calendar._EVENT_TYPES;
	
		/**
		* Fired before a selection is made
		* @event beforeSelectEvent
		*/
		this.beforeSelectEvent = new YAHOO.util.CustomEvent(defEvents.BEFORE_SELECT); 
	
		/**
		* Fired when a selection is made
		* @event selectEvent
		* @param {Array}	Array of Date field arrays in the format [YYYY, MM, DD].
		*/
		this.selectEvent = new YAHOO.util.CustomEvent(defEvents.SELECT);
	
		/**
		* Fired before a selection is made
		* @event beforeDeselectEvent
		*/
		this.beforeDeselectEvent = new YAHOO.util.CustomEvent(defEvents.BEFORE_DESELECT);
	
		/**
		* Fired when a selection is made
		* @event deselectEvent
		* @param {Array}	Array of Date field arrays in the format [YYYY, MM, DD].
		*/
		this.deselectEvent = new YAHOO.util.CustomEvent(defEvents.DESELECT);
	
		/**
		* Fired when the Calendar page is changed
		* @event changePageEvent
		*/
		this.changePageEvent = new YAHOO.util.CustomEvent(defEvents.CHANGE_PAGE);
	
		/**
		* Fired before the Calendar is rendered
		* @event beforeRenderEvent
		*/
		this.beforeRenderEvent = new YAHOO.util.CustomEvent(defEvents.BEFORE_RENDER);
	
		/**
		* Fired when the Calendar is rendered
		* @event renderEvent
		*/
		this.renderEvent = new YAHOO.util.CustomEvent(defEvents.RENDER);
	
		/**
		* Fired when the Calendar is reset
		* @event resetEvent
		*/
		this.resetEvent = new YAHOO.util.CustomEvent(defEvents.RESET);
	
		/**
		* Fired when the Calendar is cleared
		* @event clearEvent
		*/
		this.clearEvent = new YAHOO.util.CustomEvent(defEvents.CLEAR);
	
		/**
		* Fired just before the Calendar is to be shown
		* @event beforeShowEvent
		*/
		this.beforeShowEvent = new YAHOO.util.CustomEvent(defEvents.BEFORE_SHOW);
	
		/**
		* Fired after the Calendar is shown
		* @event showEvent
		*/
		this.showEvent = new YAHOO.util.CustomEvent(defEvents.SHOW);
	
		/**
		* Fired just before the Calendar is to be hidden
		* @event beforeHideEvent
		*/
		this.beforeHideEvent = new YAHOO.util.CustomEvent(defEvents.BEFORE_HIDE);
	
		/**
		* Fired after the Calendar is hidden
		* @event hideEvent
		*/
		this.hideEvent = new YAHOO.util.CustomEvent(defEvents.HIDE);

		/**
		* Fired just before the CalendarNavigator is to be shown
		* @event beforeShowNavEvent
		*/
		this.beforeShowNavEvent = new YAHOO.util.CustomEvent(defEvents.BEFORE_SHOW_NAV);
	
		/**
		* Fired after the CalendarNavigator is shown
		* @event showNavEvent
		*/
		this.showNavEvent = new YAHOO.util.CustomEvent(defEvents.SHOW_NAV);
	
		/**
		* Fired just before the CalendarNavigator is to be hidden
		* @event beforeHideNavEvent
		*/
		this.beforeHideNavEvent = new YAHOO.util.CustomEvent(defEvents.BEFORE_HIDE_NAV);
	
		/**
		* Fired after the CalendarNavigator is hidden
		* @event hideNavEvent
		*/
		this.hideNavEvent = new YAHOO.util.CustomEvent(defEvents.HIDE_NAV);

		/**
		* Fired just before the CalendarNavigator is to be rendered
		* @event beforeRenderNavEvent
		*/
		this.beforeRenderNavEvent = new YAHOO.util.CustomEvent(defEvents.BEFORE_RENDER_NAV);

		/**
		* Fired after the CalendarNavigator is rendered
		* @event renderNavEvent
		*/
		this.renderNavEvent = new YAHOO.util.CustomEvent(defEvents.RENDER_NAV);

		this.beforeSelectEvent.subscribe(this.onBeforeSelect, this, true);
		this.selectEvent.subscribe(this.onSelect, this, true);
		this.beforeDeselectEvent.subscribe(this.onBeforeDeselect, this, true);
		this.deselectEvent.subscribe(this.onDeselect, this, true);
		this.changePageEvent.subscribe(this.onChangePage, this, true);
		this.renderEvent.subscribe(this.onRender, this, true);
		this.resetEvent.subscribe(this.onReset, this, true);
		this.clearEvent.subscribe(this.onClear, this, true);
	},
	
	/**
	* The default event function that is attached to a date link within a calendar cell
	* when the calendar is rendered.
	* @method doSelectCell
	* @param {DOMEvent} e	The event
	* @param {Calendar} cal	A reference to the calendar passed by the Event utility
	*/
	doSelectCell : function(e, cal) {
		var cell,index,d,date;

		var target = YAHOO.util.Event.getTarget(e);
		var tagName = target.tagName.toLowerCase();
		var defSelector = false;

		while (tagName != "td" && ! YAHOO.util.Dom.hasClass(target, cal.Style.CSS_CELL_SELECTABLE)) {

			if (!defSelector && tagName == "a" && YAHOO.util.Dom.hasClass(target, cal.Style.CSS_CELL_SELECTOR)) {
				defSelector = true;	
			}

			target = target.parentNode;
			tagName = target.tagName.toLowerCase();
			// TODO: No need to go all the way up to html.
			if (tagName == "html") {
				return;
			}
		}

		if (defSelector) {
			// Stop link href navigation for default renderer
			YAHOO.util.Event.preventDefault(e);
		}
	
		cell = target;

		if (YAHOO.util.Dom.hasClass(cell, cal.Style.CSS_CELL_SELECTABLE)) {
			index = cell.id.split("cell")[1];
			d = cal.cellDates[index];
			date = YAHOO.widget.DateMath.getDate(d[0],d[1]-1,d[2]);
		
			var link;

			if (cal.Options.MULTI_SELECT) {
				link = cell.getElementsByTagName("a")[0];
				if (link) {
					link.blur();
				}

				var cellDate = cal.cellDates[index];
				var cellDateIndex = cal._indexOfSelectedFieldArray(cellDate);

				if (cellDateIndex > -1) {	
					cal.deselectCell(index);
				} else {
					cal.selectCell(index);
				}	
	
			} else {
				link = cell.getElementsByTagName("a")[0];
				if (link) {
					link.blur();
				}
				cal.selectCell(index);
			}
		}
	},

	/**
	* The event that is executed when the user hovers over a cell
	* @method doCellMouseOver
	* @param {DOMEvent} e	The event
	* @param {Calendar} cal	A reference to the calendar passed by the Event utility
	*/
	doCellMouseOver : function(e, cal) {
		var target;
		if (e) {
			target = YAHOO.util.Event.getTarget(e);
		} else {
			target = this;
		}

		while (target.tagName && target.tagName.toLowerCase() != "td") {
			target = target.parentNode;
			if (!target.tagName || target.tagName.toLowerCase() == "html") {
				return;
			}
		}

		if (YAHOO.util.Dom.hasClass(target, cal.Style.CSS_CELL_SELECTABLE)) {
			YAHOO.util.Dom.addClass(target, cal.Style.CSS_CELL_HOVER);
		}
	},

	/**
	* The event that is executed when the user moves the mouse out of a cell
	* @method doCellMouseOut
	* @param {DOMEvent} e	The event
	* @param {Calendar} cal	A reference to the calendar passed by the Event utility
	*/
	doCellMouseOut : function(e, cal) {
		var target;
		if (e) {
			target = YAHOO.util.Event.getTarget(e);
		} else {
			target = this;
		}

		while (target.tagName && target.tagName.toLowerCase() != "td") {
			target = target.parentNode;
			if (!target.tagName || target.tagName.toLowerCase() == "html") {
				return;
			}
		}

		if (YAHOO.util.Dom.hasClass(target, cal.Style.CSS_CELL_SELECTABLE)) {
			YAHOO.util.Dom.removeClass(target, cal.Style.CSS_CELL_HOVER);
		}
	},
	
	setupConfig : function() {
	
		var defCfg = YAHOO.widget.Calendar._DEFAULT_CONFIG;

		/**
		* The month/year representing the current visible Calendar date (mm/yyyy)
		* @config pagedate
		* @type String
		* @default today's date
		*/
		this.cfg.addProperty(defCfg.PAGEDATE.key, { value:new Date(), handler:this.configPageDate } );

		/**
		* The date or range of dates representing the current Calendar selection
		* @config selected
		* @type String
		* @default []
		*/
		this.cfg.addProperty(defCfg.SELECTED.key, { value:[], handler:this.configSelected } );

		/**
		* The title to display above the Calendar's month header
		* @config title
		* @type String
		* @default ""
		*/
		this.cfg.addProperty(defCfg.TITLE.key, { value:defCfg.TITLE.value, handler:this.configTitle } );

		/**
		* Whether or not a close button should be displayed for this Calendar
		* @config close
		* @type Boolean
		* @default false
		*/
		this.cfg.addProperty(defCfg.CLOSE.key, { value:defCfg.CLOSE.value, handler:this.configClose } );

		/**
		* Whether or not an iframe shim should be placed under the Calendar to prevent select boxes from bleeding through in Internet Explorer 6 and below.
		* This property is enabled by default for IE6 and below. It is disabled by default for other browsers for performance reasons, but can be 
		* enabled if required.
		* 
		* @config iframe
		* @type Boolean
		* @default true for IE6 and below, false for all other browsers
		*/
		this.cfg.addProperty(defCfg.IFRAME.key, { value:defCfg.IFRAME.value, handler:this.configIframe, validator:this.cfg.checkBoolean } );

		/**
		* The minimum selectable date in the current Calendar (mm/dd/yyyy)
		* @config mindate
		* @type String
		* @default null
		*/
		this.cfg.addProperty(defCfg.MINDATE.key, { value:defCfg.MINDATE.value, handler:this.configMinDate } );

		/**
		* The maximum selectable date in the current Calendar (mm/dd/yyyy)
		* @config maxdate
		* @type String
		* @default null
		*/
		this.cfg.addProperty(defCfg.MAXDATE.key, { value:defCfg.MAXDATE.value, handler:this.configMaxDate } );
	
	
		// Options properties
	
		/**
		* True if the Calendar should allow multiple selections. False by default.
		* @config MULTI_SELECT
		* @type Boolean
		* @default false
		*/
		this.cfg.addProperty(defCfg.MULTI_SELECT.key,	{ value:defCfg.MULTI_SELECT.value, handler:this.configOptions, validator:this.cfg.checkBoolean } );

		/**
		* The weekday the week begins on. Default is 0 (Sunday = 0, Monday = 1 ... Saturday = 6).
		* @config START_WEEKDAY
		* @type number
		* @default 0
		*/
		this.cfg.addProperty(defCfg.START_WEEKDAY.key,	{ value:defCfg.START_WEEKDAY.value, handler:this.configOptions, validator:this.cfg.checkNumber  } );
	
		/**
		* True if the Calendar should show weekday labels. True by default.
		* @config SHOW_WEEKDAYS
		* @type Boolean
		* @default true
		*/
		this.cfg.addProperty(defCfg.SHOW_WEEKDAYS.key,	{ value:defCfg.SHOW_WEEKDAYS.value, handler:this.configOptions, validator:this.cfg.checkBoolean  } );
	
		/**
		* True if the Calendar should show week row headers. False by default.
		* @config SHOW_WEEK_HEADER
		* @type Boolean
		* @default false
		*/
		this.cfg.addProperty(defCfg.SHOW_WEEK_HEADER.key, { value:defCfg.SHOW_WEEK_HEADER.value, handler:this.configOptions, validator:this.cfg.checkBoolean } );
	
		/**
		* True if the Calendar should show week row footers. False by default.
		* @config SHOW_WEEK_FOOTER
		* @type Boolean
		* @default false
		*/	
		this.cfg.addProperty(defCfg.SHOW_WEEK_FOOTER.key,{ value:defCfg.SHOW_WEEK_FOOTER.value, handler:this.configOptions, validator:this.cfg.checkBoolean } );
	
		/**
		* True if the Calendar should suppress weeks that are not a part of the current month. False by default.
		* @config HIDE_BLANK_WEEKS
		* @type Boolean
		* @default false
		*/	
		this.cfg.addProperty(defCfg.HIDE_BLANK_WEEKS.key, { value:defCfg.HIDE_BLANK_WEEKS.value, handler:this.configOptions, validator:this.cfg.checkBoolean } );
		
		/**
		* The image that should be used for the left navigation arrow.
		* @config NAV_ARROW_LEFT
		* @type String
		* @deprecated	You can customize the image by overriding the default CSS class for the left arrow - "calnavleft"  
		* @default null
		*/	
		this.cfg.addProperty(defCfg.NAV_ARROW_LEFT.key,	{ value:defCfg.NAV_ARROW_LEFT.value, handler:this.configOptions } );
	
		/**
		* The image that should be used for the right navigation arrow.
		* @config NAV_ARROW_RIGHT
		* @type String
		* @deprecated	You can customize the image by overriding the default CSS class for the right arrow - "calnavright"
		* @default null
		*/	
		this.cfg.addProperty(defCfg.NAV_ARROW_RIGHT.key, { value:defCfg.NAV_ARROW_RIGHT.value, handler:this.configOptions } );
	
		// Locale properties
	
		/**
		* The short month labels for the current locale.
		* @config MONTHS_SHORT
		* @type String[]
		* @default ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
		*/
		this.cfg.addProperty(defCfg.MONTHS_SHORT.key,	{ value:defCfg.MONTHS_SHORT.value, handler:this.configLocale } );
		
		/**
		* The long month labels for the current locale.
		* @config MONTHS_LONG
		* @type String[]
		* @default ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
		*/	
		this.cfg.addProperty(defCfg.MONTHS_LONG.key,		{ value:defCfg.MONTHS_LONG.value, handler:this.configLocale } );

		/**
		* The 1-character weekday labels for the current locale.
		* @config WEEKDAYS_1CHAR
		* @type String[]
		* @default ["S", "M", "T", "W", "T", "F", "S"]
		*/	
		this.cfg.addProperty(defCfg.WEEKDAYS_1CHAR.key,	{ value:defCfg.WEEKDAYS_1CHAR.value, handler:this.configLocale } );
		
		/**
		* The short weekday labels for the current locale.
		* @config WEEKDAYS_SHORT
		* @type String[]
		* @default ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"]
		*/	
		this.cfg.addProperty(defCfg.WEEKDAYS_SHORT.key,	{ value:defCfg.WEEKDAYS_SHORT.value, handler:this.configLocale } );
		
		/**
		* The medium weekday labels for the current locale.
		* @config WEEKDAYS_MEDIUM
		* @type String[]
		* @default ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
		*/	
		this.cfg.addProperty(defCfg.WEEKDAYS_MEDIUM.key,	{ value:defCfg.WEEKDAYS_MEDIUM.value, handler:this.configLocale } );
		
		/**
		* The long weekday labels for the current locale.
		* @config WEEKDAYS_LONG
		* @type String[]
		* @default ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
		*/	
		this.cfg.addProperty(defCfg.WEEKDAYS_LONG.key,	{ value:defCfg.WEEKDAYS_LONG.value, handler:this.configLocale } );
	
		/**
		* Refreshes the locale values used to build the Calendar.
		* @method refreshLocale
		* @private
		*/
		var refreshLocale = function() {
			this.cfg.refireEvent(defCfg.LOCALE_MONTHS.key);
			this.cfg.refireEvent(defCfg.LOCALE_WEEKDAYS.key);
		};
	
		this.cfg.subscribeToConfigEvent(defCfg.START_WEEKDAY.key, refreshLocale, this, true);
		this.cfg.subscribeToConfigEvent(defCfg.MONTHS_SHORT.key, refreshLocale, this, true);
		this.cfg.subscribeToConfigEvent(defCfg.MONTHS_LONG.key, refreshLocale, this, true);
		this.cfg.subscribeToConfigEvent(defCfg.WEEKDAYS_1CHAR.key, refreshLocale, this, true);
		this.cfg.subscribeToConfigEvent(defCfg.WEEKDAYS_SHORT.key, refreshLocale, this, true);
		this.cfg.subscribeToConfigEvent(defCfg.WEEKDAYS_MEDIUM.key, refreshLocale, this, true);
		this.cfg.subscribeToConfigEvent(defCfg.WEEKDAYS_LONG.key, refreshLocale, this, true);
		
		/**
		* The setting that determines which length of month labels should be used. Possible values are "short" and "long".
		* @config LOCALE_MONTHS
		* @type String
		* @default "long"
		*/	
		this.cfg.addProperty(defCfg.LOCALE_MONTHS.key,	{ value:defCfg.LOCALE_MONTHS.value, handler:this.configLocaleValues } );
		
		/**
		* The setting that determines which length of weekday labels should be used. Possible values are "1char", "short", "medium", and "long".
		* @config LOCALE_WEEKDAYS
		* @type String
		* @default "short"
		*/	
		this.cfg.addProperty(defCfg.LOCALE_WEEKDAYS.key,	{ value:defCfg.LOCALE_WEEKDAYS.value, handler:this.configLocaleValues } );
	
		/**
		* The value used to delimit individual dates in a date string passed to various Calendar functions.
		* @config DATE_DELIMITER
		* @type String
		* @default ","
		*/	
		this.cfg.addProperty(defCfg.DATE_DELIMITER.key,		{ value:defCfg.DATE_DELIMITER.value, handler:this.configLocale } );
	
		/**
		* The value used to delimit date fields in a date string passed to various Calendar functions.
		* @config DATE_FIELD_DELIMITER
		* @type String
		* @default "/"
		*/	
		this.cfg.addProperty(defCfg.DATE_FIELD_DELIMITER.key, { value:defCfg.DATE_FIELD_DELIMITER.value, handler:this.configLocale } );
	
		/**
		* The value used to delimit date ranges in a date string passed to various Calendar functions.
		* @config DATE_RANGE_DELIMITER
		* @type String
		* @default "-"
		*/
		this.cfg.addProperty(defCfg.DATE_RANGE_DELIMITER.key, { value:defCfg.DATE_RANGE_DELIMITER.value, handler:this.configLocale } );
	
		/**
		* The position of the month in a month/year date string
		* @config MY_MONTH_POSITION
		* @type Number
		* @default 1
		*/
		this.cfg.addProperty(defCfg.MY_MONTH_POSITION.key,	{ value:defCfg.MY_MONTH_POSITION.value, handler:this.configLocale, validator:this.cfg.checkNumber } );
	
		/**
		* The position of the year in a month/year date string
		* @config MY_YEAR_POSITION
		* @type Number
		* @default 2
		*/
		this.cfg.addProperty(defCfg.MY_YEAR_POSITION.key,	{ value:defCfg.MY_YEAR_POSITION.value, handler:this.configLocale, validator:this.cfg.checkNumber } );
	
		/**
		* The position of the month in a month/day date string
		* @config MD_MONTH_POSITION
		* @type Number
		* @default 1
		*/
		this.cfg.addProperty(defCfg.MD_MONTH_POSITION.key,	{ value:defCfg.MD_MONTH_POSITION.value, handler:this.configLocale, validator:this.cfg.checkNumber } );
	
		/**
		* The position of the day in a month/year date string
		* @config MD_DAY_POSITION
		* @type Number
		* @default 2
		*/
		this.cfg.addProperty(defCfg.MD_DAY_POSITION.key,		{ value:defCfg.MD_DAY_POSITION.value, handler:this.configLocale, validator:this.cfg.checkNumber } );
	
		/**
		* The position of the month in a month/day/year date string
		* @config MDY_MONTH_POSITION
		* @type Number
		* @default 1
		*/
		this.cfg.addProperty(defCfg.MDY_MONTH_POSITION.key,	{ value:defCfg.MDY_MONTH_POSITION.value, handler:this.configLocale, validator:this.cfg.checkNumber } );
	
		/**
		* The position of the day in a month/day/year date string
		* @config MDY_DAY_POSITION
		* @type Number
		* @default 2
		*/
		this.cfg.addProperty(defCfg.MDY_DAY_POSITION.key,	{ value:defCfg.MDY_DAY_POSITION.value, handler:this.configLocale, validator:this.cfg.checkNumber } );
	
		/**
		* The position of the year in a month/day/year date string
		* @config MDY_YEAR_POSITION
		* @type Number
		* @default 3
		*/
		this.cfg.addProperty(defCfg.MDY_YEAR_POSITION.key,	{ value:defCfg.MDY_YEAR_POSITION.value, handler:this.configLocale, validator:this.cfg.checkNumber } );
		
		/**
		* The position of the month in the month year label string used as the Calendar header
		* @config MY_LABEL_MONTH_POSITION
		* @type Number
		* @default 1
		*/
		this.cfg.addProperty(defCfg.MY_LABEL_MONTH_POSITION.key,	{ value:defCfg.MY_LABEL_MONTH_POSITION.value, handler:this.configLocale, validator:this.cfg.checkNumber } );
	
		/**
		* The position of the year in the month year label string used as the Calendar header
		* @config MY_LABEL_YEAR_POSITION
		* @type Number
		* @default 2
		*/
		this.cfg.addProperty(defCfg.MY_LABEL_YEAR_POSITION.key,	{ value:defCfg.MY_LABEL_YEAR_POSITION.value, handler:this.configLocale, validator:this.cfg.checkNumber } );
		
		/**
		* The suffix used after the month when rendering the Calendar header
		* @config MY_LABEL_MONTH_SUFFIX
		* @type String
		* @default " "
		*/
		this.cfg.addProperty(defCfg.MY_LABEL_MONTH_SUFFIX.key,	{ value:defCfg.MY_LABEL_MONTH_SUFFIX.value, handler:this.configLocale } );
		
		/**
		* The suffix used after the year when rendering the Calendar header
		* @config MY_LABEL_YEAR_SUFFIX
		* @type String
		* @default ""
		*/
		this.cfg.addProperty(defCfg.MY_LABEL_YEAR_SUFFIX.key, { value:defCfg.MY_LABEL_YEAR_SUFFIX.value, handler:this.configLocale } );

		/**
		* Configuration for the Month/Year CalendarNavigator UI which allows the user to jump directly to a 
		* specific Month/Year without having to scroll sequentially through months.
		* <p>
		* Setting this property to null (default value) or false, will disable the CalendarNavigator UI.
		* </p>
		* <p>
		* Setting this property to true will enable the CalendarNavigatior UI with the default CalendarNavigator configuration values.
		* </p>
		* <p>
		* This property can also be set to an object literal containing configuration properties for the CalendarNavigator UI.
		* The configuration object expects the the following case-sensitive properties, with the "strings" property being a nested object.
		* Any properties which are not provided will use the default values (defined in the CalendarNavigator class).
		* </p>
		* <dl>
		* <dt>strings</dt>
		* <dd><em>Object</em> :  An object with the properties shown below, defining the string labels to use in the Navigator's UI
		*     <dl>
		*         <dt>month</dt><dd><em>String</em> : The string to use for the month label. Defaults to "Month".</dd>
		*         <dt>year</dt><dd><em>String</em> : The string to use for the year label. Defaults to "Year".</dd>
		*         <dt>submit</dt><dd><em>String</em> : The string to use for the submit button label. Defaults to "Okay".</dd>
		*         <dt>cancel</dt><dd><em>String</em> : The string to use for the cancel button label. Defaults to "Cancel".</dd>
		*         <dt>invalidYear</dt><dd><em>String</em> : The string to use for invalid year values. Defaults to "Year needs to be a number".</dd>
		*     </dl>
		* </dd>
		* <dt>monthFormat</dt><dd><em>String</em> : The month format to use. Either YAHOO.widget.Calendar.LONG, or YAHOO.widget.Calendar.SHORT. Defaults to YAHOO.widget.Calendar.LONG</dd>
		* <dt>initialFocus</dt><dd><em>String</em> : Either "year" or "month" specifying which input control should get initial focus. Defaults to "year"</dd>
		* </dl>
		* <p>E.g.</p>
		* <pre>
		* var navConfig = {
		*	  strings: {
		*		  month:"Calendar Month",
		*		  year:"Calendar Year",
		*		  submit: "Submit",
		*		  cancel: "Cancel",
		*		  invalidYear: "Please enter a valid year"
		*	  },
		*	  monthFormat: YAHOO.widget.Calendar.SHORT,
		*	  initialFocus: "month"
		* }
		* </pre>
		* @config navigator
		* @type {Object|Boolean}
		* @default null
		*/
		this.cfg.addProperty(defCfg.NAV.key, { value:defCfg.NAV.value, handler:this.configNavigator } );
	},

	/**
	* The default handler for the "pagedate" property
	* @method configPageDate
	*/
	configPageDate : function(type, args, obj) {
		this.cfg.setProperty(YAHOO.widget.Calendar._DEFAULT_CONFIG.PAGEDATE.key, this._parsePageDate(args[0]), true);
	},

	/**
	* The default handler for the "mindate" property
	* @method configMinDate
	*/
	configMinDate : function(type, args, obj) {
		var val = args[0];
		if (YAHOO.lang.isString(val)) {
			val = this._parseDate(val);
			this.cfg.setProperty(YAHOO.widget.Calendar._DEFAULT_CONFIG.MINDATE.key, YAHOO.widget.DateMath.getDate(val[0],(val[1]-1),val[2]));
		}
	},

	/**
	* The default handler for the "maxdate" property
	* @method configMaxDate
	*/
	configMaxDate : function(type, args, obj) {
		var val = args[0];
		if (YAHOO.lang.isString(val)) {
			val = this._parseDate(val);
			this.cfg.setProperty(YAHOO.widget.Calendar._DEFAULT_CONFIG.MAXDATE.key, YAHOO.widget.DateMath.getDate(val[0],(val[1]-1),val[2]));
		}
	},
	
	/**
	* The default handler for the "selected" property
	* @method configSelected
	*/
	configSelected : function(type, args, obj) {
		var selected = args[0];
		var cfgSelected = YAHOO.widget.Calendar._DEFAULT_CONFIG.SELECTED.key;
		
		if (selected) {
			if (YAHOO.lang.isString(selected)) {
				this.cfg.setProperty(cfgSelected, this._parseDates(selected), true);
			} 
		}
		if (! this._selectedDates) {
			this._selectedDates = this.cfg.getProperty(cfgSelected);
		}
	},
	
	/**
	* The default handler for all configuration options properties
	* @method configOptions
	*/
	configOptions : function(type, args, obj) {
		this.Options[type.toUpperCase()] = args[0];
	},
	
	/**
	* The default handler for all configuration locale properties
	* @method configLocale
	*/
	configLocale : function(type, args, obj) {
		var defCfg = YAHOO.widget.Calendar._DEFAULT_CONFIG;
		this.Locale[type.toUpperCase()] = args[0];
	
		this.cfg.refireEvent(defCfg.LOCALE_MONTHS.key);
		this.cfg.refireEvent(defCfg.LOCALE_WEEKDAYS.key);
	},
	
	/**
	* The default handler for all configuration locale field length properties
	* @method configLocaleValues
	*/
	configLocaleValues : function(type, args, obj) {
		var defCfg = YAHOO.widget.Calendar._DEFAULT_CONFIG; 
	
		type = type.toLowerCase();
		var val = args[0];
	
		switch (type) {
			case defCfg.LOCALE_MONTHS.key:
				switch (val) {
					case YAHOO.widget.Calendar.SHORT:
						this.Locale.LOCALE_MONTHS = this.cfg.getProperty(defCfg.MONTHS_SHORT.key).concat();
						break;
					case YAHOO.widget.Calendar.LONG:
						this.Locale.LOCALE_MONTHS = this.cfg.getProperty(defCfg.MONTHS_LONG.key).concat();
						break;
				}
				break;
			case defCfg.LOCALE_WEEKDAYS.key:
				switch (val) {
					case YAHOO.widget.Calendar.ONE_CHAR:
						this.Locale.LOCALE_WEEKDAYS = this.cfg.getProperty(defCfg.WEEKDAYS_1CHAR.key).concat();
						break;
					case YAHOO.widget.Calendar.SHORT:
						this.Locale.LOCALE_WEEKDAYS = this.cfg.getProperty(defCfg.WEEKDAYS_SHORT.key).concat();
						break;
					case YAHOO.widget.Calendar.MEDIUM:
						this.Locale.LOCALE_WEEKDAYS = this.cfg.getProperty(defCfg.WEEKDAYS_MEDIUM.key).concat();
						break;
					case YAHOO.widget.Calendar.LONG:
						this.Locale.LOCALE_WEEKDAYS = this.cfg.getProperty(defCfg.WEEKDAYS_LONG.key).concat();
						break;
				}
				
				var START_WEEKDAY = this.cfg.getProperty(defCfg.START_WEEKDAY.key);
	
				if (START_WEEKDAY > 0) {
					for (var w=0;w<START_WEEKDAY;++w) {
						this.Locale.LOCALE_WEEKDAYS.push(this.Locale.LOCALE_WEEKDAYS.shift());
					}
				}
				break;
		}
	},

	/**
	 * The default handler for the "navigator" property
	 * @method configNavigator
	 */
	configNavigator : function(type, args, obj) {
		var val = args[0];
		if (YAHOO.widget.CalendarNavigator && (val === true || YAHOO.lang.isObject(val))) {
			if (!this.oNavigator) {
				this.oNavigator = new YAHOO.widget.CalendarNavigator(this);
				// Cleanup DOM Refs/Events before innerHTML is removed.
				function erase() {
					if (!this.pages) {
						this.oNavigator.erase();
					}
				}
				this.beforeRenderEvent.subscribe(erase, this, true);
			}
		} else {
			if (this.oNavigator) {
				this.oNavigator.destroy();
				this.oNavigator = null;
			}
		}
	},

	/**
	* Defines the style constants for the Calendar
	* @method initStyles
	*/
	initStyles : function() {

		var defStyle = YAHOO.widget.Calendar._STYLES;

		this.Style = {
			/**
			* @property Style.CSS_ROW_HEADER
			*/
			CSS_ROW_HEADER: defStyle.CSS_ROW_HEADER,
			/**
			* @property Style.CSS_ROW_FOOTER
			*/
			CSS_ROW_FOOTER: defStyle.CSS_ROW_FOOTER,
			/**
			* @property Style.CSS_CELL
			*/
			CSS_CELL : defStyle.CSS_CELL,
			/**
			* @property Style.CSS_CELL_SELECTOR
			*/
			CSS_CELL_SELECTOR : defStyle.CSS_CELL_SELECTOR,
			/**
			* @property Style.CSS_CELL_SELECTED
			*/
			CSS_CELL_SELECTED : defStyle.CSS_CELL_SELECTED,
			/**
			* @property Style.CSS_CELL_SELECTABLE
			*/
			CSS_CELL_SELECTABLE : defStyle.CSS_CELL_SELECTABLE,
			/**
			* @property Style.CSS_CELL_RESTRICTED
			*/
			CSS_CELL_RESTRICTED : defStyle.CSS_CELL_RESTRICTED,
			/**
			* @property Style.CSS_CELL_TODAY
			*/
			CSS_CELL_TODAY : defStyle.CSS_CELL_TODAY,
			/**
			* @property Style.CSS_CELL_OOM
			*/
			CSS_CELL_OOM : defStyle.CSS_CELL_OOM,
			/**
			* @property Style.CSS_CELL_OOB
			*/
			CSS_CELL_OOB : defStyle.CSS_CELL_OOB,
			/**
			* @property Style.CSS_HEADER
			*/
			CSS_HEADER : defStyle.CSS_HEADER,
			/**
			* @property Style.CSS_HEADER_TEXT
			*/
			CSS_HEADER_TEXT : defStyle.CSS_HEADER_TEXT,
			/**
			* @property Style.CSS_BODY
			*/
			CSS_BODY : defStyle.CSS_BODY,
			/**
			* @property Style.CSS_WEEKDAY_CELL
			*/
			CSS_WEEKDAY_CELL : defStyle.CSS_WEEKDAY_CELL,
			/**
			* @property Style.CSS_WEEKDAY_ROW
			*/
			CSS_WEEKDAY_ROW : defStyle.CSS_WEEKDAY_ROW,
			/**
			* @property Style.CSS_FOOTER
			*/
			CSS_FOOTER : defStyle.CSS_FOOTER,
			/**
			* @property Style.CSS_CALENDAR
			*/
			CSS_CALENDAR : defStyle.CSS_CALENDAR,
			/**
			* @property Style.CSS_SINGLE
			*/
			CSS_SINGLE : defStyle.CSS_SINGLE,
			/**
			* @property Style.CSS_CONTAINER
			*/
			CSS_CONTAINER : defStyle.CSS_CONTAINER,
			/**
			* @property Style.CSS_NAV_LEFT
			*/
			CSS_NAV_LEFT : defStyle.CSS_NAV_LEFT,
			/**
			* @property Style.CSS_NAV_RIGHT
			*/
			CSS_NAV_RIGHT : defStyle.CSS_NAV_RIGHT,
			/**
			* @property Style.CSS_NAV
			*/
			CSS_NAV : defStyle.CSS_NAV,
			/**
			* @property Style.CSS_CLOSE
			*/
			CSS_CLOSE : defStyle.CSS_CLOSE,
			/**
			* @property Style.CSS_CELL_TOP
			*/
			CSS_CELL_TOP : defStyle.CSS_CELL_TOP,
			/**
			* @property Style.CSS_CELL_LEFT
			*/
			CSS_CELL_LEFT : defStyle.CSS_CELL_LEFT,
			/**
			* @property Style.CSS_CELL_RIGHT
			*/
			CSS_CELL_RIGHT : defStyle.CSS_CELL_RIGHT,
			/**
			* @property Style.CSS_CELL_BOTTOM
			*/
			CSS_CELL_BOTTOM : defStyle.CSS_CELL_BOTTOM,
			/**
			* @property Style.CSS_CELL_HOVER
			*/
			CSS_CELL_HOVER : defStyle.CSS_CELL_HOVER,
			/**
			* @property Style.CSS_CELL_HIGHLIGHT1
			*/
			CSS_CELL_HIGHLIGHT1 : defStyle.CSS_CELL_HIGHLIGHT1,
			/**
			* @property Style.CSS_CELL_HIGHLIGHT2
			*/
			CSS_CELL_HIGHLIGHT2 : defStyle.CSS_CELL_HIGHLIGHT2,
			/**
			* @property Style.CSS_CELL_HIGHLIGHT3
			*/
			CSS_CELL_HIGHLIGHT3 : defStyle.CSS_CELL_HIGHLIGHT3,
			/**
			* @property Style.CSS_CELL_HIGHLIGHT4
			*/
			CSS_CELL_HIGHLIGHT4 : defStyle.CSS_CELL_HIGHLIGHT4
		};
	},
	
	/**
	* Builds the date label that will be displayed in the calendar header or
	* footer, depending on configuration.
	* @method buildMonthLabel
	* @return	{String}	The formatted calendar month label
	*/
	buildMonthLabel : function() {
		var pageDate = this.cfg.getProperty(YAHOO.widget.Calendar._DEFAULT_CONFIG.PAGEDATE.key);
	
		var monthLabel  = this.Locale.LOCALE_MONTHS[pageDate.getMonth()] + this.Locale.MY_LABEL_MONTH_SUFFIX;
		var yearLabel = pageDate.getFullYear() + this.Locale.MY_LABEL_YEAR_SUFFIX;

		if (this.Locale.MY_LABEL_MONTH_POSITION == 2 || this.Locale.MY_LABEL_YEAR_POSITION == 1) {
			return yearLabel + monthLabel;
		} else {
			return monthLabel + yearLabel;
		}
	},
	
	/**
	* Builds the date digit that will be displayed in calendar cells
	* @method buildDayLabel
	* @param {Date}	workingDate	The current working date
	* @return	{String}	The formatted day label
	*/
	buildDayLabel : function(workingDate) {
		return workingDate.getDate();
	},
	
	/**
	 * Creates the title bar element and adds it to Calendar container DIV
	 * 
	 * @method createTitleBar
	 * @param {String} strTitle The title to display in the title bar
	 * @return The title bar element
	 */
	createTitleBar : function(strTitle) {
		var tDiv = YAHOO.util.Dom.getElementsByClassName(YAHOO.widget.CalendarGroup.CSS_2UPTITLE, "div", this.oDomContainer)[0] || document.createElement("div");
		tDiv.className = YAHOO.widget.CalendarGroup.CSS_2UPTITLE;
		tDiv.innerHTML = strTitle;
		this.oDomContainer.insertBefore(tDiv, this.oDomContainer.firstChild);
	
		YAHOO.util.Dom.addClass(this.oDomContainer, "withtitle");
	
		return tDiv;
	},
	
	/**
	 * Removes the title bar element from the DOM
	 * 
	 * @method removeTitleBar
	 */
	removeTitleBar : function() {
		var tDiv = YAHOO.util.Dom.getElementsByClassName(YAHOO.widget.CalendarGroup.CSS_2UPTITLE, "div", this.oDomContainer)[0] || null;
		if (tDiv) {
			YAHOO.util.Event.purgeElement(tDiv);
			this.oDomContainer.removeChild(tDiv);
		}
		YAHOO.util.Dom.removeClass(this.oDomContainer, "withtitle");
	},
	
	/**
	 * Creates the close button HTML element and adds it to Calendar container DIV
	 * 
	 * @method createCloseButton
	 * @return The close HTML element created
	 */
	createCloseButton : function() {
		var Dom = YAHOO.util.Dom,
			Event = YAHOO.util.Event,
			cssClose = YAHOO.widget.CalendarGroup.CSS_2UPCLOSE,
			DEPR_CLOSE_PATH = "us/my/bn/x_d.gif";
	
		var lnk = Dom.getElementsByClassName("link-close", "a", this.oDomContainer)[0];
	
		if (!lnk) {
			lnk = document.createElement("a");  
			Event.addListener(lnk, "click", function(e, cal) {
				cal.hide(); 
				Event.preventDefault(e);
			}, this);        
		}
	
		lnk.href = "#";
		lnk.className = "link-close";
	
		if (YAHOO.widget.Calendar.IMG_ROOT !== null) {
			var img = Dom.getElementsByClassName(cssClose, "img", lnk)[0] || document.createElement("img");
			img.src = YAHOO.widget.Calendar.IMG_ROOT + DEPR_CLOSE_PATH;
			img.className = cssClose;
			lnk.appendChild(img);
		} else {
			lnk.innerHTML = '<span class="' + cssClose + ' ' + this.Style.CSS_CLOSE + '"></span>';
		}
		this.oDomContainer.appendChild(lnk);
	
		return lnk;
	},
	
	/**
	 * Removes the close button HTML element from the DOM
	 * 
	 * @method removeCloseButton
	 */
	removeCloseButton : function() {
		var btn = YAHOO.util.Dom.getElementsByClassName("link-close", "a", this.oDomContainer)[0] || null;
		if (btn) {
			YAHOO.util.Event.purgeElement(btn);
			this.oDomContainer.removeChild(btn);
		}
	},

	/**
	* Renders the calendar header.
	* @method renderHeader
	* @param {Array}	html	The current working HTML array
	* @return {Array} The current working HTML array
	*/
	renderHeader : function(html) {
		var colSpan = 7;

		var DEPR_NAV_LEFT = "us/tr/callt.gif";
		var DEPR_NAV_RIGHT = "us/tr/calrt.gif";	
		var defCfg = YAHOO.widget.Calendar._DEFAULT_CONFIG;
		
		if (this.cfg.getProperty(defCfg.SHOW_WEEK_HEADER.key)) {
			colSpan += 1;
		}
	
		if (this.cfg.getProperty(defCfg.SHOW_WEEK_FOOTER.key)) {
			colSpan += 1;
		}

		html[html.length] = "<thead>";
		html[html.length] =		"<tr>";
		html[html.length] =			'<th colspan="' + colSpan + '" class="' + this.Style.CSS_HEADER_TEXT + '">';
		html[html.length] =				'<div class="' + this.Style.CSS_HEADER + '">';

		var renderLeft, renderRight = false;

		if (this.parent) {
			if (this.index === 0) {
				renderLeft = true;
			}
			if (this.index == (this.parent.cfg.getProperty("pages") -1)) {
				renderRight = true;
			}
		} else {
			renderLeft = true;
			renderRight = true;
		}

		if (renderLeft) {
			var leftArrow = this.cfg.getProperty(defCfg.NAV_ARROW_LEFT.key);
			// Check for deprecated customization - If someone set IMG_ROOT, but didn't set NAV_ARROW_LEFT, then set NAV_ARROW_LEFT to the old deprecated value
			if (leftArrow === null && YAHOO.widget.Calendar.IMG_ROOT !== null) {
				leftArrow = YAHOO.widget.Calendar.IMG_ROOT + DEPR_NAV_LEFT;
			}
			var leftStyle = (leftArrow === null) ? "" : ' style="background-image:url(' + leftArrow + ')"';
			html[html.length] = '<a class="' + this.Style.CSS_NAV_LEFT + '"' + leftStyle + ' >&#160;</a>';
		}

		var lbl = this.buildMonthLabel();
		var cal = this.parent || this;
		if (cal.cfg.getProperty("navigator")) {
			lbl = "<a class=\"" + this.Style.CSS_NAV + "\" href=\"#\">" + lbl + "</a>";
		}
		html[html.length] = lbl;

		if (renderRight) {
			var rightArrow = this.cfg.getProperty(defCfg.NAV_ARROW_RIGHT.key);
			if (rightArrow === null && YAHOO.widget.Calendar.IMG_ROOT !== null) {
				rightArrow = YAHOO.widget.Calendar.IMG_ROOT + DEPR_NAV_RIGHT;
			}
			var rightStyle = (rightArrow === null) ? "" : ' style="background-image:url(' + rightArrow + ')"';
			html[html.length] = '<a class="' + this.Style.CSS_NAV_RIGHT + '"' + rightStyle + ' >&#160;</a>';
		}

		html[html.length] =	'</div>\n</th>\n</tr>';

		if (this.cfg.getProperty(defCfg.SHOW_WEEKDAYS.key)) {
			html = this.buildWeekdays(html);
		}
		
		html[html.length] = '</thead>';
	
		return html;
	},
	
	/**
	* Renders the Calendar's weekday headers.
	* @method buildWeekdays
	* @param {Array}	html	The current working HTML array
	* @return {Array} The current working HTML array
	*/
	buildWeekdays : function(html) {
	
		var defCfg = YAHOO.widget.Calendar._DEFAULT_CONFIG;
	
		html[html.length] = '<tr class="' + this.Style.CSS_WEEKDAY_ROW + '">';
	
		if (this.cfg.getProperty(defCfg.SHOW_WEEK_HEADER.key)) {
			html[html.length] = '<th>&#160;</th>';
		}
	
		for(var i=0;i<this.Locale.LOCALE_WEEKDAYS.length;++i) {
			html[html.length] = '<th class="calweekdaycell">' + this.Locale.LOCALE_WEEKDAYS[i] + '</th>';
		}
	
		if (this.cfg.getProperty(defCfg.SHOW_WEEK_FOOTER.key)) {
			html[html.length] = '<th>&#160;</th>';
		}
	
		html[html.length] = '</tr>';
	
		return html;
	},
	
	/**
	* Renders the calendar body.
	* @method renderBody
	* @param {Date}	workingDate	The current working Date being used for the render process
	* @param {Array}	html	The current working HTML array
	* @return {Array} The current working HTML array
	*/
	renderBody : function(workingDate, html) {

		var DM = YAHOO.widget.DateMath,
			CAL = YAHOO.widget.Calendar,
			D = YAHOO.util.Dom,
			defCfg = CAL._DEFAULT_CONFIG;

		var startDay = this.cfg.getProperty(defCfg.START_WEEKDAY.key);

		this.preMonthDays = workingDate.getDay();
		if (startDay > 0) {
			this.preMonthDays -= startDay;
		}
		if (this.preMonthDays < 0) {
			this.preMonthDays += 7;
		}

		this.monthDays = DM.findMonthEnd(workingDate).getDate();
		this.postMonthDays = CAL.DISPLAY_DAYS-this.preMonthDays-this.monthDays;


		workingDate = DM.subtract(workingDate, DM.DAY, this.preMonthDays);
	
		var weekNum,
			weekClass,
			weekPrefix = "w",
			cellPrefix = "_cell",
			workingDayPrefix = "wd",
			dayPrefix = "d",
			cellRenderers,
			renderer,
			todayYear = this.today.getFullYear(),
			todayMonth = this.today.getMonth(),
			todayDate = this.today.getDate(),
			useDate = this.cfg.getProperty(defCfg.PAGEDATE.key),
			hideBlankWeeks = this.cfg.getProperty(defCfg.HIDE_BLANK_WEEKS.key),
			showWeekFooter = this.cfg.getProperty(defCfg.SHOW_WEEK_FOOTER.key),
			showWeekHeader = this.cfg.getProperty(defCfg.SHOW_WEEK_HEADER.key),
			mindate = this.cfg.getProperty(defCfg.MINDATE.key),
			maxdate = this.cfg.getProperty(defCfg.MAXDATE.key);

		if (mindate) {
			mindate = DM.clearTime(mindate);
		}
		if (maxdate) {
			maxdate = DM.clearTime(maxdate);
		}

		html[html.length] = '<tbody class="m' + (useDate.getMonth()+1) + ' ' + this.Style.CSS_BODY + '">';

		var i = 0,
			tempDiv = document.createElement("div"),
			cell = document.createElement("td");

		tempDiv.appendChild(cell);

		var cal = this.parent || this;

		for (var r=0;r<6;r++) {
			weekNum = DM.getWeekNumber(workingDate, startDay);
			weekClass = weekPrefix + weekNum;

			// Local OOM check for performance, since we already have pagedate
			if (r !== 0 && hideBlankWeeks === true && workingDate.getMonth() != useDate.getMonth()) {
				break;
			} else {
				html[html.length] = '<tr class="' + weekClass + '">';

				if (showWeekHeader) { html = this.renderRowHeader(weekNum, html); }

				for (var d=0; d < 7; d++){ // Render actual days

					cellRenderers = [];

					this.clearElement(cell);
					cell.className = this.Style.CSS_CELL;
					cell.id = this.id + cellPrefix + i;

					if (workingDate.getDate()		== todayDate && 
						workingDate.getMonth()		== todayMonth &&
						workingDate.getFullYear()	== todayYear) {
						cellRenderers[cellRenderers.length]=cal.renderCellStyleToday;
					}

					var workingArray = [workingDate.getFullYear(),workingDate.getMonth()+1,workingDate.getDate()];
					this.cellDates[this.cellDates.length] = workingArray; // Add this date to cellDates

					// Local OOM check for performance, since we already have pagedate
					if (workingDate.getMonth() != useDate.getMonth()) {
						cellRenderers[cellRenderers.length]=cal.renderCellNotThisMonth;
					} else {
						D.addClass(cell, workingDayPrefix + workingDate.getDay());
						D.addClass(cell, dayPrefix + workingDate.getDate());

						for (var s=0;s<this.renderStack.length;++s) {

							renderer = null;

							var rArray = this.renderStack[s],
								type = rArray[0],
								month,
								day,
								year;

							switch (type) {
								case CAL.DATE:
									month = rArray[1][1];
									day = rArray[1][2];
									year = rArray[1][0];

									if (workingDate.getMonth()+1 == month && workingDate.getDate() == day && workingDate.getFullYear() == year) {
										renderer = rArray[2];
										this.renderStack.splice(s,1);
									}
									break;
								case CAL.MONTH_DAY:
									month = rArray[1][0];
									day = rArray[1][1];

									if (workingDate.getMonth()+1 == month && workingDate.getDate() == day) {
										renderer = rArray[2];
										this.renderStack.splice(s,1);
									}
									break;
								case CAL.RANGE:
									var date1 = rArray[1][0],
										date2 = rArray[1][1],
										d1month = date1[1],
										d1day = date1[2],
										d1year = date1[0],
										d1 = DM.getDate(d1year, d1month-1, d1day),
										d2month = date2[1],
										d2day = date2[2],
										d2year = date2[0],
										d2 = DM.getDate(d2year, d2month-1, d2day);

									if (workingDate.getTime() >= d1.getTime() && workingDate.getTime() <= d2.getTime()) {
										renderer = rArray[2];
	
										if (workingDate.getTime()==d2.getTime()) { 
											this.renderStack.splice(s,1);
										}
									}
									break;
								case CAL.WEEKDAY:
									var weekday = rArray[1][0];
									if (workingDate.getDay()+1 == weekday) {
										renderer = rArray[2];
									}
									break;
								case CAL.MONTH:
									month = rArray[1][0];
									if (workingDate.getMonth()+1 == month) {
										renderer = rArray[2];
									}
									break;
							}

							if (renderer) {
								cellRenderers[cellRenderers.length]=renderer;
							}
						}

					}

					if (this._indexOfSelectedFieldArray(workingArray) > -1) {
						cellRenderers[cellRenderers.length]=cal.renderCellStyleSelected; 
					}

					if ((mindate && (workingDate.getTime() < mindate.getTime())) ||
						(maxdate && (workingDate.getTime() > maxdate.getTime()))
					) {
						cellRenderers[cellRenderers.length]=cal.renderOutOfBoundsDate;
					} else {
						cellRenderers[cellRenderers.length]=cal.styleCellDefault;
						cellRenderers[cellRenderers.length]=cal.renderCellDefault;	
					}

					for (var x=0; x < cellRenderers.length; ++x) {
						if (cellRenderers[x].call(cal, workingDate, cell) == CAL.STOP_RENDER) {
							break;
						}
					}

					workingDate.setTime(workingDate.getTime() + DM.ONE_DAY_MS);
					// Just in case we crossed DST/Summertime boundaries
					workingDate = DM.clearTime(workingDate);

					if (i >= 0 && i <= 6) {
						D.addClass(cell, this.Style.CSS_CELL_TOP);
					}
					if ((i % 7) === 0) {
						D.addClass(cell, this.Style.CSS_CELL_LEFT);
					}
					if (((i+1) % 7) === 0) {
						D.addClass(cell, this.Style.CSS_CELL_RIGHT);
					}

					var postDays = this.postMonthDays; 
					if (hideBlankWeeks && postDays >= 7) {
						var blankWeeks = Math.floor(postDays/7);
						for (var p=0;p<blankWeeks;++p) {
							postDays -= 7;
						}
					}
					
					if (i >= ((this.preMonthDays+postDays+this.monthDays)-7)) {
						D.addClass(cell, this.Style.CSS_CELL_BOTTOM);
					}
	
					html[html.length] = tempDiv.innerHTML;
					i++;
				}
	
				if (showWeekFooter) { html = this.renderRowFooter(weekNum, html); }
	
				html[html.length] = '</tr>';
			}
		}
	
		html[html.length] = '</tbody>';
	
		return html;
	},
	
	/**
	* Renders the calendar footer. In the default implementation, there is
	* no footer.
	* @method renderFooter
	* @param {Array}	html	The current working HTML array
	* @return {Array} The current working HTML array
	*/
	renderFooter : function(html) { return html; },
	
	/**
	* Renders the calendar after it has been configured. The render() method has a specific call chain that will execute
	* when the method is called: renderHeader, renderBody, renderFooter.
	* Refer to the documentation for those methods for information on 
	* individual render tasks.
	* @method render
	*/
	render : function() {
		this.beforeRenderEvent.fire();
	
		var defCfg = YAHOO.widget.Calendar._DEFAULT_CONFIG;
	
		// Find starting day of the current month
		var workingDate = YAHOO.widget.DateMath.findMonthStart(this.cfg.getProperty(defCfg.PAGEDATE.key));
	
		this.resetRenderers();
		this.cellDates.length = 0;

		YAHOO.util.Event.purgeElement(this.oDomContainer, true);

		var html = [];
	
		html[html.length] = '<table cellSpacing="0" class="' + this.Style.CSS_CALENDAR + ' y' + workingDate.getFullYear() + '" id="' + this.id + '">';
		html = this.renderHeader(html);
		html = this.renderBody(workingDate, html);
		html = this.renderFooter(html);
		html[html.length] = '</table>';

		this.oDomContainer.innerHTML = html.join("\n");

		this.applyListeners();
		this.cells = this.oDomContainer.getElementsByTagName("td");
	
		this.cfg.refireEvent(defCfg.TITLE.key);
		this.cfg.refireEvent(defCfg.CLOSE.key);
		this.cfg.refireEvent(defCfg.IFRAME.key);
	
		this.renderEvent.fire();
	},

	/**
	* Applies the Calendar's DOM listeners to applicable elements.
	* @method applyListeners
	*/
	applyListeners : function() {
		var root = this.oDomContainer;
		var cal = this.parent || this;
		var anchor = "a";
		var mousedown = "mousedown";

		var linkLeft = YAHOO.util.Dom.getElementsByClassName(this.Style.CSS_NAV_LEFT, anchor, root);
		var linkRight = YAHOO.util.Dom.getElementsByClassName(this.Style.CSS_NAV_RIGHT, anchor, root);
	
		if (linkLeft && linkLeft.length > 0) {
			this.linkLeft = linkLeft[0];
			YAHOO.util.Event.addListener(this.linkLeft, mousedown, cal.previousMonth, cal, true);
		}

		if (linkRight && linkRight.length > 0) {
			this.linkRight = linkRight[0];
			YAHOO.util.Event.addListener(this.linkRight, mousedown, cal.nextMonth, cal, true);
		}

		if (cal.cfg.getProperty("navigator") !== null) {
			this.applyNavListeners();
		}

		if (this.domEventMap) {
			var el,elements;
			for (var cls in this.domEventMap) {	
				if (YAHOO.lang.hasOwnProperty(this.domEventMap, cls)) {
					var items = this.domEventMap[cls];
	
					if (! (items instanceof Array)) {
						items = [items];
					}
	
					for (var i=0;i<items.length;i++)	{
						var item = items[i];
						elements = YAHOO.util.Dom.getElementsByClassName(cls, item.tag, this.oDomContainer);
	
						for (var c=0;c<elements.length;c++) {
							el = elements[c];
							 YAHOO.util.Event.addListener(el, item.event, item.handler, item.scope, item.correct );
						}
					}
				}
			}
		}
	
		YAHOO.util.Event.addListener(this.oDomContainer, "click", this.doSelectCell, this);
		YAHOO.util.Event.addListener(this.oDomContainer, "mouseover", this.doCellMouseOver, this);
		YAHOO.util.Event.addListener(this.oDomContainer, "mouseout", this.doCellMouseOut, this);
	},

	applyNavListeners : function() {

		var E = YAHOO.util.Event;

		var calParent = this.parent || this;
		var cal = this;

		var navBtns = YAHOO.util.Dom.getElementsByClassName(this.Style.CSS_NAV, "a", this.oDomContainer);

		if (navBtns.length > 0) {

			function show(e, obj) {
				var target = E.getTarget(e);
				// this == navBtn
				if (this === target || YAHOO.util.Dom.isAncestor(this, target)) {
					E.preventDefault(e);
				}
				var navigator = calParent.oNavigator;
				if (navigator) {
					var pgdate = cal.cfg.getProperty("pagedate");
					navigator.setYear(pgdate.getFullYear());
					navigator.setMonth(pgdate.getMonth());
					navigator.show();
				}
			}
			E.addListener(navBtns, "click", show);
		}
	},

	/**
	* Retrieves the Date object for the specified Calendar cell
	* @method getDateByCellId
	* @param {String}	id	The id of the cell
	* @return {Date} The Date object for the specified Calendar cell
	*/
	getDateByCellId : function(id) {
		var date = this.getDateFieldsByCellId(id);
		return YAHOO.widget.DateMath.getDate(date[0],date[1]-1,date[2]);
	},
	
	/**
	* Retrieves the Date object for the specified Calendar cell
	* @method getDateFieldsByCellId
	* @param {String}	id	The id of the cell
	* @return {Array}	The array of Date fields for the specified Calendar cell
	*/
	getDateFieldsByCellId : function(id) {
		id = id.toLowerCase().split("_cell")[1];
		id = parseInt(id, 10);
		return this.cellDates[id];
	},
	
	/**
	 * Find the Calendar's cell index for a given date.
	 * If the date is not found, the method returns -1.
	 * <p>
	 * The returned index can be used to lookup the cell HTMLElement  
	 * using the Calendar's cells array or passed to selectCell to select 
	 * cells by index. 
	 * </p>
	 *
	 * See <a href="#cells">cells</a>, <a href="#selectCell">selectCell</a>.
	 *
	 * @method getCellIndex
	 * @param {Date} date JavaScript Date object, for which to find a cell index.
	 * @return {Number} The index of the date in Calendars cellDates/cells arrays, or -1 if the date 
	 * is not on the curently rendered Calendar page.
	 */
	getCellIndex : function(date) {
		var idx = -1;
		if (date) {
			var m = date.getMonth(),
				y = date.getFullYear(),
				d = date.getDate(),
				dates = this.cellDates;

			for (var i = 0; i < dates.length; ++i) {
				var cellDate = dates[i];
				if (cellDate[0] === y && cellDate[1] === m+1 && cellDate[2] === d) {
					idx = i;
					break;
				}
			}
		}
		return idx;
	},
	
	// BEGIN BUILT-IN TABLE CELL RENDERERS
	
	/**
	* Renders a cell that falls before the minimum date or after the maximum date.
	* widget class.
	* @method renderOutOfBoundsDate
	* @param {Date}					workingDate		The current working Date object being used to generate the calendar
	* @param {HTMLTableCellElement}	cell			The current working cell in the calendar
	* @return {String} YAHOO.widget.Calendar.STOP_RENDER if rendering should stop with this style, null or nothing if rendering
	*			should not be terminated
	*/
	renderOutOfBoundsDate : function(workingDate, cell) {
		YAHOO.util.Dom.addClass(cell, this.Style.CSS_CELL_OOB);
		cell.innerHTML = workingDate.getDate();
		return YAHOO.widget.Calendar.STOP_RENDER;
	},
	
	/**
	* Renders the row header for a week.
	* @method renderRowHeader
	* @param {Number}	weekNum	The week number of the current row
	* @param {Array}	cell	The current working HTML array
	*/
	renderRowHeader : function(weekNum, html) {
		html[html.length] = '<th class="calrowhead">' + weekNum + '</th>';
		return html;
	},
	
	/**
	* Renders the row footer for a week.
	* @method renderRowFooter
	* @param {Number}	weekNum	The week number of the current row
	* @param {Array}	cell	The current working HTML array
	*/
	renderRowFooter : function(weekNum, html) {
		html[html.length] = '<th class="calrowfoot">' + weekNum + '</th>';
		return html;
	},
	
	/**
	* Renders a single standard calendar cell in the calendar widget table.
	* All logic for determining how a standard default cell will be rendered is 
	* encapsulated in this method, and must be accounted for when extending the
	* widget class.
	* @method renderCellDefault
	* @param {Date}					workingDate		The current working Date object being used to generate the calendar
	* @param {HTMLTableCellElement}	cell			The current working cell in the calendar
	*/
	renderCellDefault : function(workingDate, cell) {
		cell.innerHTML = '<a href="#" class="' + this.Style.CSS_CELL_SELECTOR + '">' + this.buildDayLabel(workingDate) + "</a>";
	},
	
	/**
	* Styles a selectable cell.
	* @method styleCellDefault
	* @param {Date}					workingDate		The current working Date object being used to generate the calendar
	* @param {HTMLTableCellElement}	cell			The current working cell in the calendar
	*/
	styleCellDefault : function(workingDate, cell) {
		YAHOO.util.Dom.addClass(cell, this.Style.CSS_CELL_SELECTABLE);
	},
	
	
	/**
	* Renders a single standard calendar cell using the CSS hightlight1 style
	* @method renderCellStyleHighlight1
	* @param {Date}					workingDate		The current working Date object being used to generate the calendar
	* @param {HTMLTableCellElement}	cell			The current working cell in the calendar
	*/
	renderCellStyleHighlight1 : function(workingDate, cell) {
		YAHOO.util.Dom.addClass(cell, this.Style.CSS_CELL_HIGHLIGHT1);
	},
	
	/**
	* Renders a single standard calendar cell using the CSS hightlight2 style
	* @method renderCellStyleHighlight2
	* @param {Date}					workingDate		The current working Date object being used to generate the calendar
	* @param {HTMLTableCellElement}	cell			The current working cell in the calendar
	*/
	renderCellStyleHighlight2 : function(workingDate, cell) {
		YAHOO.util.Dom.addClass(cell, this.Style.CSS_CELL_HIGHLIGHT2);
	},
	
	/**
	* Renders a single standard calendar cell using the CSS hightlight3 style
	* @method renderCellStyleHighlight3
	* @param {Date}					workingDate		The current working Date object being used to generate the calendar
	* @param {HTMLTableCellElement}	cell			The current working cell in the calendar
	*/
	renderCellStyleHighlight3 : function(workingDate, cell) {
		YAHOO.util.Dom.addClass(cell, this.Style.CSS_CELL_HIGHLIGHT3);
	},
	
	/**
	* Renders a single standard calendar cell using the CSS hightlight4 style
	* @method renderCellStyleHighlight4
	* @param {Date}					workingDate		The current working Date object being used to generate the calendar
	* @param {HTMLTableCellElement}	cell			The current working cell in the calendar
	*/
	renderCellStyleHighlight4 : function(workingDate, cell) {
		YAHOO.util.Dom.addClass(cell, this.Style.CSS_CELL_HIGHLIGHT4);
	},
	
	/**
	* Applies the default style used for rendering today's date to the current calendar cell
	* @method renderCellStyleToday
	* @param {Date}					workingDate		The current working Date object being used to generate the calendar
	* @param {HTMLTableCellElement}	cell			The current working cell in the calendar
	*/
	renderCellStyleToday : function(workingDate, cell) {
		YAHOO.util.Dom.addClass(cell, this.Style.CSS_CELL_TODAY);
	},
	
	/**
	* Applies the default style used for rendering selected dates to the current calendar cell
	* @method renderCellStyleSelected
	* @param {Date}					workingDate		The current working Date object being used to generate the calendar
	* @param {HTMLTableCellElement}	cell			The current working cell in the calendar
	* @return {String} YAHOO.widget.Calendar.STOP_RENDER if rendering should stop with this style, null or nothing if rendering
	*			should not be terminated
	*/
	renderCellStyleSelected : function(workingDate, cell) {
		YAHOO.util.Dom.addClass(cell, this.Style.CSS_CELL_SELECTED);
	},
	
	/**
	* Applies the default style used for rendering dates that are not a part of the current
	* month (preceding or trailing the cells for the current month)
	* @method renderCellNotThisMonth
	* @param {Date}					workingDate		The current working Date object being used to generate the calendar
	* @param {HTMLTableCellElement}	cell			The current working cell in the calendar
	* @return {String} YAHOO.widget.Calendar.STOP_RENDER if rendering should stop with this style, null or nothing if rendering
	*			should not be terminated
	*/
	renderCellNotThisMonth : function(workingDate, cell) {
		YAHOO.util.Dom.addClass(cell, this.Style.CSS_CELL_OOM);
		cell.innerHTML=workingDate.getDate();
		return YAHOO.widget.Calendar.STOP_RENDER;
	},
	
	/**
	* Renders the current calendar cell as a non-selectable "black-out" date using the default
	* restricted style.
	* @method renderBodyCellRestricted
	* @param {Date}					workingDate		The current working Date object being used to generate the calendar
	* @param {HTMLTableCellElement}	cell			The current working cell in the calendar
	* @return {String} YAHOO.widget.Calendar.STOP_RENDER if rendering should stop with this style, null or nothing if rendering
	*			should not be terminated
	*/
	renderBodyCellRestricted : function(workingDate, cell) {
		YAHOO.util.Dom.addClass(cell, this.Style.CSS_CELL);
		YAHOO.util.Dom.addClass(cell, this.Style.CSS_CELL_RESTRICTED);
		cell.innerHTML=workingDate.getDate();
		return YAHOO.widget.Calendar.STOP_RENDER;
	},
	
	// END BUILT-IN TABLE CELL RENDERERS
	
	// BEGIN MONTH NAVIGATION METHODS
	
	/**
	* Adds the designated number of months to the current calendar month, and sets the current
	* calendar page date to the new month.
	* @method addMonths
	* @param {Number}	count	The number of months to add to the current calendar
	*/
	addMonths : function(count) {
		var cfgPageDate = YAHOO.widget.Calendar._DEFAULT_CONFIG.PAGEDATE.key;
		this.cfg.setProperty(cfgPageDate, YAHOO.widget.DateMath.add(this.cfg.getProperty(cfgPageDate), YAHOO.widget.DateMath.MONTH, count));
		this.resetRenderers();
		this.changePageEvent.fire();
	},
	
	/**
	* Subtracts the designated number of months from the current calendar month, and sets the current
	* calendar page date to the new month.
	* @method subtractMonths
	* @param {Number}	count	The number of months to subtract from the current calendar
	*/
	subtractMonths : function(count) {
		var cfgPageDate = YAHOO.widget.Calendar._DEFAULT_CONFIG.PAGEDATE.key;
		this.cfg.setProperty(cfgPageDate, YAHOO.widget.DateMath.subtract(this.cfg.getProperty(cfgPageDate), YAHOO.widget.DateMath.MONTH, count));
		this.resetRenderers();
		this.changePageEvent.fire();
	},
	
	/**
	* Adds the designated number of years to the current calendar, and sets the current
	* calendar page date to the new month.
	* @method addYears
	* @param {Number}	count	The number of years to add to the current calendar
	*/
	addYears : function(count) {
		var cfgPageDate = YAHOO.widget.Calendar._DEFAULT_CONFIG.PAGEDATE.key;
		this.cfg.setProperty(cfgPageDate, YAHOO.widget.DateMath.add(this.cfg.getProperty(cfgPageDate), YAHOO.widget.DateMath.YEAR, count));
		this.resetRenderers();
		this.changePageEvent.fire();
	},
	
	/**
	* Subtcats the designated number of years from the current calendar, and sets the current
	* calendar page date to the new month.
	* @method subtractYears
	* @param {Number}	count	The number of years to subtract from the current calendar
	*/
	subtractYears : function(count) {
		var cfgPageDate = YAHOO.widget.Calendar._DEFAULT_CONFIG.PAGEDATE.key;
		this.cfg.setProperty(cfgPageDate, YAHOO.widget.DateMath.subtract(this.cfg.getProperty(cfgPageDate), YAHOO.widget.DateMath.YEAR, count));
		this.resetRenderers();
		this.changePageEvent.fire();
	},
	
	/**
	* Navigates to the next month page in the calendar widget.
	* @method nextMonth
	*/
	nextMonth : function() {
		this.addMonths(1);
	},
	
	/**
	* Navigates to the previous month page in the calendar widget.
	* @method previousMonth
	*/
	previousMonth : function() {
		this.subtractMonths(1);
	},
	
	/**
	* Navigates to the next year in the currently selected month in the calendar widget.
	* @method nextYear
	*/
	nextYear : function() {
		this.addYears(1);
	},
	
	/**
	* Navigates to the previous year in the currently selected month in the calendar widget.
	* @method previousYear
	*/
	previousYear : function() {
		this.subtractYears(1);
	},
	
	// END MONTH NAVIGATION METHODS
	
	// BEGIN SELECTION METHODS
	
	/**
	* Resets the calendar widget to the originally selected month and year, and 
	* sets the calendar to the initial selection(s).
	* @method reset
	*/
	reset : function() {
		var defCfg = YAHOO.widget.Calendar._DEFAULT_CONFIG;
		this.cfg.resetProperty(defCfg.SELECTED.key);
		this.cfg.resetProperty(defCfg.PAGEDATE.key);
		this.resetEvent.fire();
	},
	
	/**
	* Clears the selected dates in the current calendar widget and sets the calendar
	* to the current month and year.
	* @method clear
	*/
	clear : function() {
		var defCfg = YAHOO.widget.Calendar._DEFAULT_CONFIG;
		this.cfg.setProperty(defCfg.SELECTED.key, []);
		this.cfg.setProperty(defCfg.PAGEDATE.key, new Date(this.today.getTime()));
		this.clearEvent.fire();
	},
	
	/**
	* Selects a date or a collection of dates on the current calendar. This method, by default,
	* does not call the render method explicitly. Once selection has completed, render must be 
	* called for the changes to be reflected visually.
	*
	* Any dates which are OOB (out of bounds, not selectable) will not be selected and the array of 
	* selected dates passed to the selectEvent will not contain OOB dates.
	* 
	* If all dates are OOB, the no state change will occur; beforeSelect and select events will not be fired.
	*
	* @method select
	* @param	{String/Date/Date[]}	date	The date string of dates to select in the current calendar. Valid formats are
	*								individual date(s) (12/24/2005,12/26/2005) or date range(s) (12/24/2005-1/1/2006).
	*								Multiple comma-delimited dates can also be passed to this method (12/24/2005,12/11/2005-12/13/2005).
	*								This method can also take a JavaScript Date object or an array of Date objects.
	* @return	{Date[]}			Array of JavaScript Date objects representing all individual dates that are currently selected.
	*/
	select : function(date) {
	
		var aToBeSelected = this._toFieldArray(date);
	
		// Filtered array of valid dates
		var validDates = [];
		var selected = [];
		var cfgSelected = YAHOO.widget.Calendar._DEFAULT_CONFIG.SELECTED.key;
		
		for (var a=0; a < aToBeSelected.length; ++a) {
			var toSelect = aToBeSelected[a];
	
			if (!this.isDateOOB(this._toDate(toSelect))) {
				
				if (validDates.length === 0) {
					this.beforeSelectEvent.fire();
					selected = this.cfg.getProperty(cfgSelected);
				}
	
				validDates.push(toSelect);
				
				if (this._indexOfSelectedFieldArray(toSelect) == -1) { 
					selected[selected.length] = toSelect;
				}
			}
		}
		
	
		if (validDates.length > 0) {
			if (this.parent) {
				this.parent.cfg.setProperty(cfgSelected, selected);
			} else {
				this.cfg.setProperty(cfgSelected, selected);
			}
			this.selectEvent.fire(validDates);
		}
	
		return this.getSelectedDates();
	},
	
	/**
	* Selects a date on the current calendar by referencing the index of the cell that should be selected.
	* This method is used to easily select a single cell (usually with a mouse click) without having to do
	* a full render. The selected style is applied to the cell directly.
	*
	* If the cell is not marked with the CSS_CELL_SELECTABLE class (as is the case by default for out of month 
	* or out of bounds cells), it will not be selected and in such a case beforeSelect and select events will not be fired.
	* 
	* @method selectCell
	* @param	{Number}	cellIndex	The index of the cell to select in the current calendar. 
	* @return	{Date[]}	Array of JavaScript Date objects representing all individual dates that are currently selected.
	*/
	selectCell : function(cellIndex) {
	
		var cell = this.cells[cellIndex];
		var cellDate = this.cellDates[cellIndex];
		var dCellDate = this._toDate(cellDate);
		
		var selectable = YAHOO.util.Dom.hasClass(cell, this.Style.CSS_CELL_SELECTABLE);
	
		if (selectable) {
	
			this.beforeSelectEvent.fire();
	
			var cfgSelected = YAHOO.widget.Calendar._DEFAULT_CONFIG.SELECTED.key;
			var selected = this.cfg.getProperty(cfgSelected);
	
			var selectDate = cellDate.concat();
	
			if (this._indexOfSelectedFieldArray(selectDate) == -1) {
				selected[selected.length] = selectDate;
			}
			if (this.parent) {
				this.parent.cfg.setProperty(cfgSelected, selected);
			} else {
				this.cfg.setProperty(cfgSelected, selected);
			}
			this.renderCellStyleSelected(dCellDate,cell);
			this.selectEvent.fire([selectDate]);
	
			this.doCellMouseOut.call(cell, null, this);		
		}
	
		return this.getSelectedDates();
	},
	
	/**
	* Deselects a date or a collection of dates on the current calendar. This method, by default,
	* does not call the render method explicitly. Once deselection has completed, render must be 
	* called for the changes to be reflected visually.
	* 
	* The method will not attempt to deselect any dates which are OOB (out of bounds, and hence not selectable) 
	* and the array of deselected dates passed to the deselectEvent will not contain any OOB dates.
	* 
	* If all dates are OOB, beforeDeselect and deselect events will not be fired.
	* 
	* @method deselect
	* @param	{String/Date/Date[]}	date	The date string of dates to deselect in the current calendar. Valid formats are
	*								individual date(s) (12/24/2005,12/26/2005) or date range(s) (12/24/2005-1/1/2006).
	*								Multiple comma-delimited dates can also be passed to this method (12/24/2005,12/11/2005-12/13/2005).
	*								This method can also take a JavaScript Date object or an array of Date objects.	
	* @return	{Date[]}			Array of JavaScript Date objects representing all individual dates that are currently selected.
	*/
	deselect : function(date) {
	
		var aToBeDeselected = this._toFieldArray(date);
	
		var validDates = [];
		var selected = [];
		var cfgSelected = YAHOO.widget.Calendar._DEFAULT_CONFIG.SELECTED.key;
	
		for (var a=0; a < aToBeDeselected.length; ++a) {
			var toDeselect = aToBeDeselected[a];
	
			if (!this.isDateOOB(this._toDate(toDeselect))) {
	
				if (validDates.length === 0) {
					this.beforeDeselectEvent.fire();
					selected = this.cfg.getProperty(cfgSelected);
				}
	
				validDates.push(toDeselect);
	
				var index = this._indexOfSelectedFieldArray(toDeselect);
				if (index != -1) {	
					selected.splice(index,1);
				}
			}
		}
	
	
		if (validDates.length > 0) {
			if (this.parent) {
				this.parent.cfg.setProperty(cfgSelected, selected);
			} else {
				this.cfg.setProperty(cfgSelected, selected);
			}
			this.deselectEvent.fire(validDates);
		}
	
		return this.getSelectedDates();
	},
	
	/**
	* Deselects a date on the current calendar by referencing the index of the cell that should be deselected.
	* This method is used to easily deselect a single cell (usually with a mouse click) without having to do
	* a full render. The selected style is removed from the cell directly.
	* 
	* If the cell is not marked with the CSS_CELL_SELECTABLE class (as is the case by default for out of month 
	* or out of bounds cells), the method will not attempt to deselect it and in such a case, beforeDeselect and 
	* deselect events will not be fired.
	* 
	* @method deselectCell
	* @param	{Number}	cellIndex	The index of the cell to deselect in the current calendar. 
	* @return	{Date[]}	Array of JavaScript Date objects representing all individual dates that are currently selected.
	*/
	deselectCell : function(cellIndex) {
		var cell = this.cells[cellIndex];
		var cellDate = this.cellDates[cellIndex];
		var cellDateIndex = this._indexOfSelectedFieldArray(cellDate);
		
		var selectable = YAHOO.util.Dom.hasClass(cell, this.Style.CSS_CELL_SELECTABLE);
	
		if (selectable) {
	
			this.beforeDeselectEvent.fire();
	
			var defCfg = YAHOO.widget.Calendar._DEFAULT_CONFIG;
			var selected = this.cfg.getProperty(defCfg.SELECTED.key);
	
			var dCellDate = this._toDate(cellDate);
			var selectDate = cellDate.concat();
	
			if (cellDateIndex > -1) {
				if (this.cfg.getProperty(defCfg.PAGEDATE.key).getMonth() == dCellDate.getMonth() &&
					this.cfg.getProperty(defCfg.PAGEDATE.key).getFullYear() == dCellDate.getFullYear()) {
					YAHOO.util.Dom.removeClass(cell, this.Style.CSS_CELL_SELECTED);
				}
				selected.splice(cellDateIndex, 1);
			}
	
			if (this.parent) {
				this.parent.cfg.setProperty(defCfg.SELECTED.key, selected);
			} else {
				this.cfg.setProperty(defCfg.SELECTED.key, selected);
			}
	
			this.deselectEvent.fire(selectDate);
		}
	
		return this.getSelectedDates();
	},
	
	/**
	* Deselects all dates on the current calendar.
	* @method deselectAll
	* @return {Date[]}		Array of JavaScript Date objects representing all individual dates that are currently selected.
	*						Assuming that this function executes properly, the return value should be an empty array.
	*						However, the empty array is returned for the sake of being able to check the selection status
	*						of the calendar.
	*/
	deselectAll : function() {
		this.beforeDeselectEvent.fire();
		
		var cfgSelected = YAHOO.widget.Calendar._DEFAULT_CONFIG.SELECTED.key;
	
		var selected = this.cfg.getProperty(cfgSelected);
		var count = selected.length;
		var sel = selected.concat();
	
		if (this.parent) {
			this.parent.cfg.setProperty(cfgSelected, []);
		} else {
			this.cfg.setProperty(cfgSelected, []);
		}
		
		if (count > 0) {
			this.deselectEvent.fire(sel);
		}
	
		return this.getSelectedDates();
	},
	
	// END SELECTION METHODS
	
	// BEGIN TYPE CONVERSION METHODS
	
	/**
	* Converts a date (either a JavaScript Date object, or a date string) to the internal data structure
	* used to represent dates: [[yyyy,mm,dd],[yyyy,mm,dd]].
	* @method _toFieldArray
	* @private
	* @param	{String/Date/Date[]}	date	The date string of dates to deselect in the current calendar. Valid formats are
	*								individual date(s) (12/24/2005,12/26/2005) or date range(s) (12/24/2005-1/1/2006).
	*								Multiple comma-delimited dates can also be passed to this method (12/24/2005,12/11/2005-12/13/2005).
	*								This method can also take a JavaScript Date object or an array of Date objects.	
	* @return {Array[](Number[])}	Array of date field arrays
	*/
	_toFieldArray : function(date) {
		var returnDate = [];
	
		if (date instanceof Date) {
			returnDate = [[date.getFullYear(), date.getMonth()+1, date.getDate()]];
		} else if (YAHOO.lang.isString(date)) {
			returnDate = this._parseDates(date);
		} else if (YAHOO.lang.isArray(date)) {
			for (var i=0;i<date.length;++i) {
				var d = date[i];
				returnDate[returnDate.length] = [d.getFullYear(),d.getMonth()+1,d.getDate()];
			}
		}
		
		return returnDate;
	},
	
	/**
	* Converts a date field array [yyyy,mm,dd] to a JavaScript Date object. The date field array
	* is the format in which dates are as provided as arguments to selectEvent and deselectEvent listeners.
	* 
	* @method toDate
	* @param	{Number[]}	dateFieldArray	The date field array to convert to a JavaScript Date.
	* @return	{Date}	JavaScript Date object representing the date field array.
	*/
	toDate : function(dateFieldArray) {
		return this._toDate(dateFieldArray);
	},
	
	/**
	* Converts a date field array [yyyy,mm,dd] to a JavaScript Date object.
	* @method _toDate
	* @private
	* @deprecated Made public, toDate 
	* @param	{Number[]}		dateFieldArray	The date field array to convert to a JavaScript Date.
	* @return	{Date}	JavaScript Date object representing the date field array
	*/
	_toDate : function(dateFieldArray) {
		if (dateFieldArray instanceof Date) {
			return dateFieldArray;
		} else {
			return YAHOO.widget.DateMath.getDate(dateFieldArray[0],dateFieldArray[1]-1,dateFieldArray[2]);
		}
	},
	
	// END TYPE CONVERSION METHODS 
	
	// BEGIN UTILITY METHODS
	
	/**
	* Converts a date field array [yyyy,mm,dd] to a JavaScript Date object.
	* @method _fieldArraysAreEqual
	* @private
	* @param	{Number[]}	array1	The first date field array to compare
	* @param	{Number[]}	array2	The first date field array to compare
	* @return	{Boolean}	The boolean that represents the equality of the two arrays
	*/
	_fieldArraysAreEqual : function(array1, array2) {
		var match = false;
	
		if (array1[0]==array2[0]&&array1[1]==array2[1]&&array1[2]==array2[2]) {
			match=true;	
		}
	
		return match;
	},
	
	/**
	* Gets the index of a date field array [yyyy,mm,dd] in the current list of selected dates.
	* @method	_indexOfSelectedFieldArray
	* @private
	* @param	{Number[]}		find	The date field array to search for
	* @return	{Number}			The index of the date field array within the collection of selected dates.
	*								-1 will be returned if the date is not found.
	*/
	_indexOfSelectedFieldArray : function(find) {
		var selected = -1;
		var seldates = this.cfg.getProperty(YAHOO.widget.Calendar._DEFAULT_CONFIG.SELECTED.key);
	
		for (var s=0;s<seldates.length;++s) {
			var sArray = seldates[s];
			if (find[0]==sArray[0]&&find[1]==sArray[1]&&find[2]==sArray[2]) {
				selected = s;
				break;
			}
		}
	
		return selected;
	},
	
	/**
	* Determines whether a given date is OOM (out of month).
	* @method	isDateOOM
	* @param	{Date}	date	The JavaScript Date object for which to check the OOM status
	* @return	{Boolean}	true if the date is OOM
	*/
	isDateOOM : function(date) {
		return (date.getMonth() != this.cfg.getProperty(YAHOO.widget.Calendar._DEFAULT_CONFIG.PAGEDATE.key).getMonth());
	},
	
	/**
	* Determines whether a given date is OOB (out of bounds - less than the mindate or more than the maxdate).
	*
	* @method	isDateOOB
	* @param	{Date}	date	The JavaScript Date object for which to check the OOB status
	* @return	{Boolean}	true if the date is OOB
	*/
	isDateOOB : function(date) {
		var defCfg = YAHOO.widget.Calendar._DEFAULT_CONFIG;
		
		var minDate = this.cfg.getProperty(defCfg.MINDATE.key);
		var maxDate = this.cfg.getProperty(defCfg.MAXDATE.key);
		var dm = YAHOO.widget.DateMath;
		
		if (minDate) {
			minDate = dm.clearTime(minDate);
		} 
		if (maxDate) {
			maxDate = dm.clearTime(maxDate);
		}
	
		var clearedDate = new Date(date.getTime());
		clearedDate = dm.clearTime(clearedDate);
	
		return ((minDate && clearedDate.getTime() < minDate.getTime()) || (maxDate && clearedDate.getTime() > maxDate.getTime()));
	},
	
	/**
	 * Parses a pagedate configuration property value. The value can either be specified as a string of form "mm/yyyy" or a Date object 
	 * and is parsed into a Date object normalized to the first day of the month. If no value is passed in, the month and year from today's date are used to create the Date object 
	 * @method	_parsePageDate
	 * @private
	 * @param {Date|String}	date	Pagedate value which needs to be parsed
	 * @return {Date}	The Date object representing the pagedate
	 */
	_parsePageDate : function(date) {
		var parsedDate;
		
		var defCfg = YAHOO.widget.Calendar._DEFAULT_CONFIG;
	
		if (date) {
			if (date instanceof Date) {
				parsedDate = YAHOO.widget.DateMath.findMonthStart(date);
			} else {
				var month, year, aMonthYear;
				aMonthYear = date.split(this.cfg.getProperty(defCfg.DATE_FIELD_DELIMITER.key));
				month = parseInt(aMonthYear[this.cfg.getProperty(defCfg.MY_MONTH_POSITION.key)-1], 10)-1;
				year = parseInt(aMonthYear[this.cfg.getProperty(defCfg.MY_YEAR_POSITION.key)-1], 10);

				parsedDate = YAHOO.widget.DateMath.getDate(year, month, 1);
			}
		} else {
			parsedDate = YAHOO.widget.DateMath.getDate(this.today.getFullYear(), this.today.getMonth(), 1);
		}
		return parsedDate;
	},
	
	// END UTILITY METHODS
	
	// BEGIN EVENT HANDLERS
	
	/**
	* Event executed before a date is selected in the calendar widget.
	* @deprecated Event handlers for this event should be susbcribed to beforeSelectEvent.
	*/
	onBeforeSelect : function() {
		if (this.cfg.getProperty(YAHOO.widget.Calendar._DEFAULT_CONFIG.MULTI_SELECT.key) === false) {
			if (this.parent) {
				this.parent.callChildFunction("clearAllBodyCellStyles", this.Style.CSS_CELL_SELECTED);
				this.parent.deselectAll();
			} else {
				this.clearAllBodyCellStyles(this.Style.CSS_CELL_SELECTED);
				this.deselectAll();
			}
		}
	},
	
	/**
	* Event executed when a date is selected in the calendar widget.
	* @param	{Array}	selected	An array of date field arrays representing which date or dates were selected. Example: [ [2006,8,6],[2006,8,7],[2006,8,8] ]
	* @deprecated Event handlers for this event should be susbcribed to selectEvent.
	*/
	onSelect : function(selected) { },
	
	/**
	* Event executed before a date is deselected in the calendar widget.
	* @deprecated Event handlers for this event should be susbcribed to beforeDeselectEvent.
	*/
	onBeforeDeselect : function() { },
	
	/**
	* Event executed when a date is deselected in the calendar widget.
	* @param	{Array}	selected	An array of date field arrays representing which date or dates were deselected. Example: [ [2006,8,6],[2006,8,7],[2006,8,8] ]
	* @deprecated Event handlers for this event should be susbcribed to deselectEvent.
	*/
	onDeselect : function(deselected) { },
	
	/**
	* Event executed when the user navigates to a different calendar page.
	* @deprecated Event handlers for this event should be susbcribed to changePageEvent.
	*/
	onChangePage : function() {
		this.render();
	},
	
	/**
	* Event executed when the calendar widget is rendered.
	* @deprecated Event handlers for this event should be susbcribed to renderEvent.
	*/
	onRender : function() { },
	
	/**
	* Event executed when the calendar widget is reset to its original state.
	* @deprecated Event handlers for this event should be susbcribed to resetEvemt.
	*/
	onReset : function() { this.render(); },
	
	/**
	* Event executed when the calendar widget is completely cleared to the current month with no selections.
	* @deprecated Event handlers for this event should be susbcribed to clearEvent.
	*/
	onClear : function() { this.render(); },
	
	/**
	* Validates the calendar widget. This method has no default implementation
	* and must be extended by subclassing the widget.
	* @return	Should return true if the widget validates, and false if
	* it doesn't.
	* @type Boolean
	*/
	validate : function() { return true; },
	
	// END EVENT HANDLERS
	
	// BEGIN DATE PARSE METHODS
	
	/**
	* Converts a date string to a date field array
	* @private
	* @param	{String}	sDate			Date string. Valid formats are mm/dd and mm/dd/yyyy.
	* @return				A date field array representing the string passed to the method
	* @type Array[](Number[])
	*/
	_parseDate : function(sDate) {
		var aDate = sDate.split(this.Locale.DATE_FIELD_DELIMITER);
		var rArray;
	
		if (aDate.length == 2) {
			rArray = [aDate[this.Locale.MD_MONTH_POSITION-1],aDate[this.Locale.MD_DAY_POSITION-1]];
			rArray.type = YAHOO.widget.Calendar.MONTH_DAY;
		} else {
			rArray = [aDate[this.Locale.MDY_YEAR_POSITION-1],aDate[this.Locale.MDY_MONTH_POSITION-1],aDate[this.Locale.MDY_DAY_POSITION-1]];
			rArray.type = YAHOO.widget.Calendar.DATE;
		}
	
		for (var i=0;i<rArray.length;i++) {
			rArray[i] = parseInt(rArray[i], 10);
		}
	
		return rArray;
	},
	
	/**
	* Converts a multi or single-date string to an array of date field arrays
	* @private
	* @param	{String}	sDates		Date string with one or more comma-delimited dates. Valid formats are mm/dd, mm/dd/yyyy, mm/dd/yyyy-mm/dd/yyyy
	* @return							An array of date field arrays
	* @type Array[](Number[])
	*/
	_parseDates : function(sDates) {
		var aReturn = [];
	
		var aDates = sDates.split(this.Locale.DATE_DELIMITER);
		
		for (var d=0;d<aDates.length;++d) {
			var sDate = aDates[d];
	
			if (sDate.indexOf(this.Locale.DATE_RANGE_DELIMITER) != -1) {
				// This is a range
				var aRange = sDate.split(this.Locale.DATE_RANGE_DELIMITER);
	
				var dateStart = this._parseDate(aRange[0]);
				var dateEnd = this._parseDate(aRange[1]);
	
				var fullRange = this._parseRange(dateStart, dateEnd);
				aReturn = aReturn.concat(fullRange);
			} else {
				// This is not a range
				var aDate = this._parseDate(sDate);
				aReturn.push(aDate);
			}
		}
		return aReturn;
	},
	
	/**
	* Converts a date range to the full list of included dates
	* @private
	* @param	{Number[]}	startDate	Date field array representing the first date in the range
	* @param	{Number[]}	endDate		Date field array representing the last date in the range
	* @return							An array of date field arrays
	* @type Array[](Number[])
	*/
	_parseRange : function(startDate, endDate) {
		var dCurrent = YAHOO.widget.DateMath.add(YAHOO.widget.DateMath.getDate(startDate[0],startDate[1]-1,startDate[2]),YAHOO.widget.DateMath.DAY,1);
		var dEnd     = YAHOO.widget.DateMath.getDate(endDate[0],  endDate[1]-1,  endDate[2]);
	
		var results = [];
		results.push(startDate);
		while (dCurrent.getTime() <= dEnd.getTime()) {
			results.push([dCurrent.getFullYear(),dCurrent.getMonth()+1,dCurrent.getDate()]);
			dCurrent = YAHOO.widget.DateMath.add(dCurrent,YAHOO.widget.DateMath.DAY,1);
		}
		return results;
	},
	
	// END DATE PARSE METHODS
	
	// BEGIN RENDERER METHODS
	
	/**
	* Resets the render stack of the current calendar to its original pre-render value.
	*/
	resetRenderers : function() {
		this.renderStack = this._renderStack.concat();
	},
	
	/**
	 * Removes all custom renderers added to the Calendar through the addRenderer, addMonthRenderer and 
	 * addWeekdayRenderer methods. Calendar's render method needs to be called after removing renderers 
	 * to re-render the Calendar without custom renderers applied.
	 */
	removeRenderers : function() {
		this._renderStack = [];
		this.renderStack = [];
	},

	/**
	* Clears the inner HTML, CSS class and style information from the specified cell.
	* @method clearElement
	* @param	{HTMLTableCellElement} cell The cell to clear
	*/ 
	clearElement : function(cell) {
		cell.innerHTML = "&#160;";
		cell.className="";
	},
	
	/**
	* Adds a renderer to the render stack. The function reference passed to this method will be executed
	* when a date cell matches the conditions specified in the date string for this renderer.
	* @method addRenderer
	* @param	{String}	sDates		A date string to associate with the specified renderer. Valid formats
	*									include date (12/24/2005), month/day (12/24), and range (12/1/2004-1/1/2005)
	* @param	{Function}	fnRender	The function executed to render cells that match the render rules for this renderer.
	*/
	addRenderer : function(sDates, fnRender) {
		var aDates = this._parseDates(sDates);
		for (var i=0;i<aDates.length;++i) {
			var aDate = aDates[i];
		
			if (aDate.length == 2) { // this is either a range or a month/day combo
				if (aDate[0] instanceof Array) { // this is a range
					this._addRenderer(YAHOO.widget.Calendar.RANGE,aDate,fnRender);
				} else { // this is a month/day combo
					this._addRenderer(YAHOO.widget.Calendar.MONTH_DAY,aDate,fnRender);
				}
			} else if (aDate.length == 3) {
				this._addRenderer(YAHOO.widget.Calendar.DATE,aDate,fnRender);
			}
		}
	},
	
	/**
	* The private method used for adding cell renderers to the local render stack.
	* This method is called by other methods that set the renderer type prior to the method call.
	* @method _addRenderer
	* @private
	* @param	{String}	type		The type string that indicates the type of date renderer being added.
	*									Values are YAHOO.widget.Calendar.DATE, YAHOO.widget.Calendar.MONTH_DAY, YAHOO.widget.Calendar.WEEKDAY,
	*									YAHOO.widget.Calendar.RANGE, YAHOO.widget.Calendar.MONTH
	* @param	{Array}		aDates		An array of dates used to construct the renderer. The format varies based
	*									on the renderer type
	* @param	{Function}	fnRender	The function executed to render cells that match the render rules for this renderer.
	*/
	_addRenderer : function(type, aDates, fnRender) {
		var add = [type,aDates,fnRender];
		this.renderStack.unshift(add);	
		this._renderStack = this.renderStack.concat();
	},

	/**
	* Adds a month to the render stack. The function reference passed to this method will be executed
	* when a date cell matches the month passed to this method.
	* @method addMonthRenderer
	* @param	{Number}	month		The month (1-12) to associate with this renderer
	* @param	{Function}	fnRender	The function executed to render cells that match the render rules for this renderer.
	*/
	addMonthRenderer : function(month, fnRender) {
		this._addRenderer(YAHOO.widget.Calendar.MONTH,[month],fnRender);
	},

	/**
	* Adds a weekday to the render stack. The function reference passed to this method will be executed
	* when a date cell matches the weekday passed to this method.
	* @method addWeekdayRenderer
	* @param	{Number}	weekday		The weekday (Sunday = 1, Monday = 2 ... Saturday = 7) to associate with this renderer
	* @param	{Function}	fnRender	The function executed to render cells that match the render rules for this renderer.
	*/
	addWeekdayRenderer : function(weekday, fnRender) {
		this._addRenderer(YAHOO.widget.Calendar.WEEKDAY,[weekday],fnRender);
	},

	// END RENDERER METHODS
	
	// BEGIN CSS METHODS
	
	/**
	* Removes all styles from all body cells in the current calendar table.
	* @method clearAllBodyCellStyles
	* @param	{style}	style The CSS class name to remove from all calendar body cells
	*/
	clearAllBodyCellStyles : function(style) {
		for (var c=0;c<this.cells.length;++c) {
			YAHOO.util.Dom.removeClass(this.cells[c],style);
		}
	},
	
	// END CSS METHODS
	
	// BEGIN GETTER/SETTER METHODS
	/**
	* Sets the calendar's month explicitly
	* @method setMonth
	* @param {Number}	month		The numeric month, from 0 (January) to 11 (December)
	*/
	setMonth : function(month) {
		var cfgPageDate = YAHOO.widget.Calendar._DEFAULT_CONFIG.PAGEDATE.key;
		var current = this.cfg.getProperty(cfgPageDate);
		current.setMonth(parseInt(month, 10));
		this.cfg.setProperty(cfgPageDate, current);
	},

	/**
	* Sets the calendar's year explicitly.
	* @method setYear
	* @param {Number}	year		The numeric 4-digit year
	*/
	setYear : function(year) {
		var cfgPageDate = YAHOO.widget.Calendar._DEFAULT_CONFIG.PAGEDATE.key;
		var current = this.cfg.getProperty(cfgPageDate);
		current.setFullYear(parseInt(year, 10));
		this.cfg.setProperty(cfgPageDate, current);
	},

	/**
	* Gets the list of currently selected dates from the calendar.
	* @method getSelectedDates
	* @return {Date[]} An array of currently selected JavaScript Date objects.
	*/
	getSelectedDates : function() {
		var returnDates = [];
		var selected = this.cfg.getProperty(YAHOO.widget.Calendar._DEFAULT_CONFIG.SELECTED.key);

		for (var d=0;d<selected.length;++d) {
			var dateArray = selected[d];

			var date = YAHOO.widget.DateMath.getDate(dateArray[0],dateArray[1]-1,dateArray[2]);
			returnDates.push(date);
		}

		returnDates.sort( function(a,b) { return a-b; } );
		return returnDates;
	},

	/// END GETTER/SETTER METHODS ///
	
	/**
	* Hides the Calendar's outer container from view.
	* @method hide
	*/
	hide : function() {
		if (this.beforeHideEvent.fire()) {
			this.oDomContainer.style.display = "none";
			this.hideEvent.fire();
		}
	},

	/**
	* Shows the Calendar's outer container.
	* @method show
	*/
	show : function() {
		if (this.beforeShowEvent.fire()) {
			this.oDomContainer.style.display = "block";
			this.showEvent.fire();
		}
	},

	/**
	* Returns a string representing the current browser.
	* @deprecated As of 2.3.0, environment information is available in YAHOO.env.ua
	* @see YAHOO.env.ua
	* @property browser
	* @type String
	*/
	browser : (function() {
				var ua = navigator.userAgent.toLowerCase();
					  if (ua.indexOf('opera')!=-1) { // Opera (check first in case of spoof)
						 return 'opera';
					  } else if (ua.indexOf('msie 7')!=-1) { // IE7
						 return 'ie7';
					  } else if (ua.indexOf('msie') !=-1) { // IE
						 return 'ie';
					  } else if (ua.indexOf('safari')!=-1) { // Safari (check before Gecko because it includes "like Gecko")
						 return 'safari';
					  } else if (ua.indexOf('gecko') != -1) { // Gecko
						 return 'gecko';
					  } else {
						 return false;
					  }
				})(),
	/**
	* Returns a string representation of the object.
	* @method toString
	* @return {String}	A string representation of the Calendar object.
	*/
	toString : function() {
		return "Calendar " + this.id;
	}
};

/**
* @namespace YAHOO.widget
* @class Calendar_Core
* @extends YAHOO.widget.Calendar
* @deprecated The old Calendar_Core class is no longer necessary.
*/
YAHOO.widget.Calendar_Core = YAHOO.widget.Calendar;

YAHOO.widget.Cal_Core = YAHOO.widget.Calendar;

/**
* YAHOO.widget.CalendarGroup is a special container class for YAHOO.widget.Calendar. This class facilitates
* the ability to have multi-page calendar views that share a single dataset and are
* dependent on each other.
*
* The calendar group instance will refer to each of its elements using a 0-based index.
* For example, to construct the placeholder for a calendar group widget with id "cal1" and
* containerId of "cal1Container", the markup would be as follows:
*	<xmp>
*		<div id="cal1Container_0"></div>
*		<div id="cal1Container_1"></div>
*	</xmp>
* The tables for the calendars ("cal1_0" and "cal1_1") will be inserted into those containers.
* 
* <p>
* <strong>NOTE: As of 2.4.0, the constructor's ID argument is optional.</strong>
* The CalendarGroup can be constructed by simply providing a container ID string, 
* or a reference to a container DIV HTMLElement (the element needs to exist 
* in the document).
* 
* E.g.:
*	<xmp>
*		var c = new YAHOO.widget.CalendarGroup("calContainer", configOptions);
*	</xmp>
* or:
*   <xmp>
*       var containerDiv = YAHOO.util.Dom.get("calContainer");
*		var c = new YAHOO.widget.CalendarGroup(containerDiv, configOptions);
*	</xmp>
* </p>
* <p>
* If not provided, the ID will be generated from the container DIV ID by adding an "_t" suffix.
* For example if an ID is not provided, and the container's ID is "calContainer", the CalendarGroup's ID will be set to "calContainer_t".
* </p>
* 
* @namespace YAHOO.widget
* @class CalendarGroup
* @constructor
* @param {String} id optional The id of the table element that will represent the CalendarGroup widget. As of 2.4.0, this argument is optional.
* @param {String | HTMLElement} container The id of the container div element that will wrap the CalendarGroup table, or a reference to a DIV element which exists in the document.
* @param {Object} config optional The configuration object containing the initial configuration values for the CalendarGroup.
*/
YAHOO.widget.CalendarGroup = function(id, containerId, config) {
	if (arguments.length > 0) {
		this.init.apply(this, arguments);
	}
};

YAHOO.widget.CalendarGroup.prototype = {

	/**
	* Initializes the calendar group. All subclasses must call this method in order for the
	* group to be initialized properly.
	* @method init
	* @param {String} id optional The id of the table element that will represent the CalendarGroup widget. As of 2.4.0, this argument is optional.
	* @param {String | HTMLElement} container The id of the container div element that will wrap the CalendarGroup table, or a reference to a DIV element which exists in the document.
	* @param {Object} config optional The configuration object containing the initial configuration values for the CalendarGroup.
	*/
	init : function(id, container, config) {

		// Normalize 2.4.0, pre 2.4.0 args
		var nArgs = this._parseArgs(arguments);

		id = nArgs.id;
		container = nArgs.container;
		config = nArgs.config;

		this.oDomContainer = YAHOO.util.Dom.get(container);

		if (!this.oDomContainer.id) {
			this.oDomContainer.id = YAHOO.util.Dom.generateId();
		}
		if (!id) {
			id = this.oDomContainer.id + "_t";
		}

		/**
		* The unique id associated with the CalendarGroup
		* @property id
		* @type String
		*/
		this.id = id;

		/**
		* The unique id associated with the CalendarGroup container
		* @property containerId
		* @type String
		*/
		this.containerId = this.oDomContainer.id;

		this.initEvents();
		this.initStyles();

		/**
		* The collection of Calendar pages contained within the CalendarGroup
		* @property pages
		* @type YAHOO.widget.Calendar[]
		*/
		this.pages = [];

		YAHOO.util.Dom.addClass(this.oDomContainer, YAHOO.widget.CalendarGroup.CSS_CONTAINER);
		YAHOO.util.Dom.addClass(this.oDomContainer, YAHOO.widget.CalendarGroup.CSS_MULTI_UP);

		/**
		* The Config object used to hold the configuration variables for the CalendarGroup
		* @property cfg
		* @type YAHOO.util.Config
		*/
		this.cfg = new YAHOO.util.Config(this);

		/**
		* The local object which contains the CalendarGroup's options
		* @property Options
		* @type Object
		*/
		this.Options = {};

		/**
		* The local object which contains the CalendarGroup's locale settings
		* @property Locale
		* @type Object
		*/
		this.Locale = {};

		this.setupConfig();

		if (config) {
			this.cfg.applyConfig(config, true);
		}

		this.cfg.fireQueue();

		// OPERA HACK FOR MISWRAPPED FLOATS
		if (YAHOO.env.ua.opera){
			this.renderEvent.subscribe(this._fixWidth, this, true);
			this.showEvent.subscribe(this._fixWidth, this, true);
		}

	},

	setupConfig : function() {

		var defCfg = YAHOO.widget.CalendarGroup._DEFAULT_CONFIG;

		/**
		* The number of pages to include in the CalendarGroup. This value can only be set once, in the CalendarGroup's constructor arguments.
		* @config pages
		* @type Number
		* @default 2
		*/
		this.cfg.addProperty(defCfg.PAGES.key, { value:defCfg.PAGES.value, validator:this.cfg.checkNumber, handler:this.configPages } );

		/**
		* The month/year representing the current visible Calendar date (mm/yyyy)
		* @config pagedate
		* @type String
		* @default today's date
		*/
		this.cfg.addProperty(defCfg.PAGEDATE.key, { value:new Date(), handler:this.configPageDate } );

		/**
		* The date or range of dates representing the current Calendar selection
		* @config selected
		* @type String
		* @default []
		*/
		this.cfg.addProperty(defCfg.SELECTED.key, { value:[], handler:this.configSelected } );

		/**
		* The title to display above the CalendarGroup's month header
		* @config title
		* @type String
		* @default ""
		*/
		this.cfg.addProperty(defCfg.TITLE.key, { value:defCfg.TITLE.value, handler:this.configTitle } );

		/**
		* Whether or not a close button should be displayed for this CalendarGroup
		* @config close
		* @type Boolean
		* @default false
		*/
		this.cfg.addProperty(defCfg.CLOSE.key, { value:defCfg.CLOSE.value, handler:this.configClose } );

		/**
		* Whether or not an iframe shim should be placed under the Calendar to prevent select boxes from bleeding through in Internet Explorer 6 and below.
		* This property is enabled by default for IE6 and below. It is disabled by default for other browsers for performance reasons, but can be 
		* enabled if required.
		* 
		* @config iframe
		* @type Boolean
		* @default true for IE6 and below, false for all other browsers
		*/
		this.cfg.addProperty(defCfg.IFRAME.key, { value:defCfg.IFRAME.value, handler:this.configIframe, validator:this.cfg.checkBoolean } );
	
		/**
		* The minimum selectable date in the current Calendar (mm/dd/yyyy)
		* @config mindate
		* @type String
		* @default null
		*/
		this.cfg.addProperty(defCfg.MINDATE.key, { value:defCfg.MINDATE.value, handler:this.delegateConfig } );
	
		/**
		* The maximum selectable date in the current Calendar (mm/dd/yyyy)
		* @config maxdate
		* @type String
		* @default null
		*/	
		this.cfg.addProperty(defCfg.MAXDATE.key, { value:defCfg.MAXDATE.value, handler:this.delegateConfig  } );
	
		// Options properties
	
		/**
		* True if the Calendar should allow multiple selections. False by default.
		* @config MULTI_SELECT
		* @type Boolean
		* @default false
		*/
		this.cfg.addProperty(defCfg.MULTI_SELECT.key,	{ value:defCfg.MULTI_SELECT.value, handler:this.delegateConfig, validator:this.cfg.checkBoolean } );
	
		/**
		* The weekday the week begins on. Default is 0 (Sunday).
		* @config START_WEEKDAY
		* @type number
		* @default 0
		*/	
		this.cfg.addProperty(defCfg.START_WEEKDAY.key,	{ value:defCfg.START_WEEKDAY.value, handler:this.delegateConfig, validator:this.cfg.checkNumber  } );
		
		/**
		* True if the Calendar should show weekday labels. True by default.
		* @config SHOW_WEEKDAYS
		* @type Boolean
		* @default true
		*/	
		this.cfg.addProperty(defCfg.SHOW_WEEKDAYS.key,	{ value:defCfg.SHOW_WEEKDAYS.value, handler:this.delegateConfig, validator:this.cfg.checkBoolean } );
		
		/**
		* True if the Calendar should show week row headers. False by default.
		* @config SHOW_WEEK_HEADER
		* @type Boolean
		* @default false
		*/	
		this.cfg.addProperty(defCfg.SHOW_WEEK_HEADER.key,{ value:defCfg.SHOW_WEEK_HEADER.value, handler:this.delegateConfig, validator:this.cfg.checkBoolean } );
		
		/**
		* True if the Calendar should show week row footers. False by default.
		* @config SHOW_WEEK_FOOTER
		* @type Boolean
		* @default false
		*/
		this.cfg.addProperty(defCfg.SHOW_WEEK_FOOTER.key,{ value:defCfg.SHOW_WEEK_FOOTER.value, handler:this.delegateConfig, validator:this.cfg.checkBoolean } );
		
		/**
		* True if the Calendar should suppress weeks that are not a part of the current month. False by default.
		* @config HIDE_BLANK_WEEKS
		* @type Boolean
		* @default false
		*/		
		this.cfg.addProperty(defCfg.HIDE_BLANK_WEEKS.key,{ value:defCfg.HIDE_BLANK_WEEKS.value, handler:this.delegateConfig, validator:this.cfg.checkBoolean } );
		
		/**
		* The image that should be used for the left navigation arrow.
		* @config NAV_ARROW_LEFT
		* @type String
		* @deprecated	You can customize the image by overriding the default CSS class for the left arrow - "calnavleft"
		* @default null
		*/		
		this.cfg.addProperty(defCfg.NAV_ARROW_LEFT.key,	{ value:defCfg.NAV_ARROW_LEFT.value, handler:this.delegateConfig } );
		
		/**
		* The image that should be used for the right navigation arrow.
		* @config NAV_ARROW_RIGHT
		* @type String
		* @deprecated	You can customize the image by overriding the default CSS class for the right arrow - "calnavright"
		* @default null
		*/		
		this.cfg.addProperty(defCfg.NAV_ARROW_RIGHT.key,	{ value:defCfg.NAV_ARROW_RIGHT.value, handler:this.delegateConfig } );
	
		// Locale properties
		
		/**
		* The short month labels for the current locale.
		* @config MONTHS_SHORT
		* @type String[]
		* @default ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
		*/
		this.cfg.addProperty(defCfg.MONTHS_SHORT.key,	{ value:defCfg.MONTHS_SHORT.value, handler:this.delegateConfig } );
		
		/**
		* The long month labels for the current locale.
		* @config MONTHS_LONG
		* @type String[]
		* @default ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
		*/		
		this.cfg.addProperty(defCfg.MONTHS_LONG.key,		{ value:defCfg.MONTHS_LONG.value, handler:this.delegateConfig } );
		
		/**
		* The 1-character weekday labels for the current locale.
		* @config WEEKDAYS_1CHAR
		* @type String[]
		* @default ["S", "M", "T", "W", "T", "F", "S"]
		*/		
		this.cfg.addProperty(defCfg.WEEKDAYS_1CHAR.key,	{ value:defCfg.WEEKDAYS_1CHAR.value, handler:this.delegateConfig } );
		
		/**
		* The short weekday labels for the current locale.
		* @config WEEKDAYS_SHORT
		* @type String[]
		* @default ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"]
		*/		
		this.cfg.addProperty(defCfg.WEEKDAYS_SHORT.key,	{ value:defCfg.WEEKDAYS_SHORT.value, handler:this.delegateConfig } );
		
		/**
		* The medium weekday labels for the current locale.
		* @config WEEKDAYS_MEDIUM
		* @type String[]
		* @default ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
		*/		
		this.cfg.addProperty(defCfg.WEEKDAYS_MEDIUM.key,	{ value:defCfg.WEEKDAYS_MEDIUM.value, handler:this.delegateConfig } );
		
		/**
		* The long weekday labels for the current locale.
		* @config WEEKDAYS_LONG
		* @type String[]
		* @default ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
		*/		
		this.cfg.addProperty(defCfg.WEEKDAYS_LONG.key,	{ value:defCfg.WEEKDAYS_LONG.value, handler:this.delegateConfig } );
	
		/**
		* The setting that determines which length of month labels should be used. Possible values are "short" and "long".
		* @config LOCALE_MONTHS
		* @type String
		* @default "long"
		*/
		this.cfg.addProperty(defCfg.LOCALE_MONTHS.key,	{ value:defCfg.LOCALE_MONTHS.value, handler:this.delegateConfig } );
	
		/**
		* The setting that determines which length of weekday labels should be used. Possible values are "1char", "short", "medium", and "long".
		* @config LOCALE_WEEKDAYS
		* @type String
		* @default "short"
		*/	
		this.cfg.addProperty(defCfg.LOCALE_WEEKDAYS.key,	{ value:defCfg.LOCALE_WEEKDAYS.value, handler:this.delegateConfig } );
	
		/**
		* The value used to delimit individual dates in a date string passed to various Calendar functions.
		* @config DATE_DELIMITER
		* @type String
		* @default ","
		*/
		this.cfg.addProperty(defCfg.DATE_DELIMITER.key,		{ value:defCfg.DATE_DELIMITER.value, handler:this.delegateConfig } );
	
		/**
		* The value used to delimit date fields in a date string passed to various Calendar functions.
		* @config DATE_FIELD_DELIMITER
		* @type String
		* @default "/"
		*/	
		this.cfg.addProperty(defCfg.DATE_FIELD_DELIMITER.key,{ value:defCfg.DATE_FIELD_DELIMITER.value, handler:this.delegateConfig } );
	
		/**
		* The value used to delimit date ranges in a date string passed to various Calendar functions.
		* @config DATE_RANGE_DELIMITER
		* @type String
		* @default "-"
		*/
		this.cfg.addProperty(defCfg.DATE_RANGE_DELIMITER.key,{ value:defCfg.DATE_RANGE_DELIMITER.value, handler:this.delegateConfig } );
	
		/**
		* The position of the month in a month/year date string
		* @config MY_MONTH_POSITION
		* @type Number
		* @default 1
		*/
		this.cfg.addProperty(defCfg.MY_MONTH_POSITION.key,	{ value:defCfg.MY_MONTH_POSITION.value, handler:this.delegateConfig, validator:this.cfg.checkNumber } );
		
		/**
		* The position of the year in a month/year date string
		* @config MY_YEAR_POSITION
		* @type Number
		* @default 2
		*/	
		this.cfg.addProperty(defCfg.MY_YEAR_POSITION.key,	{ value:defCfg.MY_YEAR_POSITION.value, handler:this.delegateConfig, validator:this.cfg.checkNumber } );
		
		/**
		* The position of the month in a month/day date string
		* @config MD_MONTH_POSITION
		* @type Number
		* @default 1
		*/	
		this.cfg.addProperty(defCfg.MD_MONTH_POSITION.key,	{ value:defCfg.MD_MONTH_POSITION.value, handler:this.delegateConfig, validator:this.cfg.checkNumber } );
		
		/**
		* The position of the day in a month/year date string
		* @config MD_DAY_POSITION
		* @type Number
		* @default 2
		*/	
		this.cfg.addProperty(defCfg.MD_DAY_POSITION.key,		{ value:defCfg.MD_DAY_POSITION.value, handler:this.delegateConfig, validator:this.cfg.checkNumber } );
		
		/**
		* The position of the month in a month/day/year date string
		* @config MDY_MONTH_POSITION
		* @type Number
		* @default 1
		*/	
		this.cfg.addProperty(defCfg.MDY_MONTH_POSITION.key,	{ value:defCfg.MDY_MONTH_POSITION.value, handler:this.delegateConfig, validator:this.cfg.checkNumber } );
		
		/**
		* The position of the day in a month/day/year date string
		* @config MDY_DAY_POSITION
		* @type Number
		* @default 2
		*/	
		this.cfg.addProperty(defCfg.MDY_DAY_POSITION.key,	{ value:defCfg.MDY_DAY_POSITION.value, handler:this.delegateConfig, validator:this.cfg.checkNumber } );
		
		/**
		* The position of the year in a month/day/year date string
		* @config MDY_YEAR_POSITION
		* @type Number
		* @default 3
		*/	
		this.cfg.addProperty(defCfg.MDY_YEAR_POSITION.key,	{ value:defCfg.MDY_YEAR_POSITION.value, handler:this.delegateConfig, validator:this.cfg.checkNumber } );
	
		/**
		* The position of the month in the month year label string used as the Calendar header
		* @config MY_LABEL_MONTH_POSITION
		* @type Number
		* @default 1
		*/
		this.cfg.addProperty(defCfg.MY_LABEL_MONTH_POSITION.key,	{ value:defCfg.MY_LABEL_MONTH_POSITION.value, handler:this.delegateConfig, validator:this.cfg.checkNumber } );
	
		/**
		* The position of the year in the month year label string used as the Calendar header
		* @config MY_LABEL_YEAR_POSITION
		* @type Number
		* @default 2
		*/
		this.cfg.addProperty(defCfg.MY_LABEL_YEAR_POSITION.key,	{ value:defCfg.MY_LABEL_YEAR_POSITION.value, handler:this.delegateConfig, validator:this.cfg.checkNumber } );
		
		/**
		* The suffix used after the month when rendering the Calendar header
		* @config MY_LABEL_MONTH_SUFFIX
		* @type String
		* @default " "
		*/
		this.cfg.addProperty(defCfg.MY_LABEL_MONTH_SUFFIX.key,	{ value:defCfg.MY_LABEL_MONTH_SUFFIX.value, handler:this.delegateConfig } );
		
		/**
		* The suffix used after the year when rendering the Calendar header
		* @config MY_LABEL_YEAR_SUFFIX
		* @type String
		* @default ""
		*/
		this.cfg.addProperty(defCfg.MY_LABEL_YEAR_SUFFIX.key, { value:defCfg.MY_LABEL_YEAR_SUFFIX.value, handler:this.delegateConfig } );

		/**
		* Configuration for the Month Year Navigation UI. By default it is disabled
		* @config NAV
		* @type Object
		* @default null
		*/
		this.cfg.addProperty(defCfg.NAV.key, { value:defCfg.NAV.value, handler:this.configNavigator } );
	},

	/**
	* Initializes CalendarGroup's built-in CustomEvents
	* @method initEvents
	*/
	initEvents : function() {
		var me = this;
		var strEvent = "Event";

		/**
		* Proxy subscriber to subscribe to the CalendarGroup's child Calendars' CustomEvents
		* @method sub
		* @private
		* @param {Function} fn	The function to subscribe to this CustomEvent
		* @param {Object}	obj	The CustomEvent's scope object
		* @param {Boolean}	bOverride	Whether or not to apply scope correction
		*/
		var sub = function(fn, obj, bOverride) {
			for (var p=0;p<me.pages.length;++p) {
				var cal = me.pages[p];
				cal[this.type + strEvent].subscribe(fn, obj, bOverride);
			}
		};

		/**
		* Proxy unsubscriber to unsubscribe from the CalendarGroup's child Calendars' CustomEvents
		* @method unsub
		* @private
		* @param {Function} fn	The function to subscribe to this CustomEvent
		* @param {Object}	obj	The CustomEvent's scope object
		*/
		var unsub = function(fn, obj) {
			for (var p=0;p<me.pages.length;++p) {
				var cal = me.pages[p];
				cal[this.type + strEvent].unsubscribe(fn, obj);
			}
		};
		
		var defEvents = YAHOO.widget.Calendar._EVENT_TYPES;
	
		/**
		* Fired before a selection is made
		* @event beforeSelectEvent
		*/
		this.beforeSelectEvent = new YAHOO.util.CustomEvent(defEvents.BEFORE_SELECT);
		this.beforeSelectEvent.subscribe = sub; this.beforeSelectEvent.unsubscribe = unsub;
	
		/**
		* Fired when a selection is made
		* @event selectEvent
		* @param {Array}	Array of Date field arrays in the format [YYYY, MM, DD].
		*/
		this.selectEvent = new YAHOO.util.CustomEvent(defEvents.SELECT); 
		this.selectEvent.subscribe = sub; this.selectEvent.unsubscribe = unsub;
	
		/**
		* Fired before a selection is made
		* @event beforeDeselectEvent
		*/
		this.beforeDeselectEvent = new YAHOO.util.CustomEvent(defEvents.BEFORE_DESELECT); 
		this.beforeDeselectEvent.subscribe = sub; this.beforeDeselectEvent.unsubscribe = unsub;
	
		/**
		* Fired when a selection is made
		* @event deselectEvent
		* @param {Array}	Array of Date field arrays in the format [YYYY, MM, DD].
		*/
		this.deselectEvent = new YAHOO.util.CustomEvent(defEvents.DESELECT); 
		this.deselectEvent.subscribe = sub; this.deselectEvent.unsubscribe = unsub;
		
		/**
		* Fired when the Calendar page is changed
		* @event changePageEvent
		*/
		this.changePageEvent = new YAHOO.util.CustomEvent(defEvents.CHANGE_PAGE); 
		this.changePageEvent.subscribe = sub; this.changePageEvent.unsubscribe = unsub;
	
		/**
		* Fired before the Calendar is rendered
		* @event beforeRenderEvent
		*/
		this.beforeRenderEvent = new YAHOO.util.CustomEvent(defEvents.BEFORE_RENDER);
		this.beforeRenderEvent.subscribe = sub; this.beforeRenderEvent.unsubscribe = unsub;
	
		/**
		* Fired when the Calendar is rendered
		* @event renderEvent
		*/
		this.renderEvent = new YAHOO.util.CustomEvent(defEvents.RENDER);
		this.renderEvent.subscribe = sub; this.renderEvent.unsubscribe = unsub;
	
		/**
		* Fired when the Calendar is reset
		* @event resetEvent
		*/
		this.resetEvent = new YAHOO.util.CustomEvent(defEvents.RESET); 
		this.resetEvent.subscribe = sub; this.resetEvent.unsubscribe = unsub;
	
		/**
		* Fired when the Calendar is cleared
		* @event clearEvent
		*/
		this.clearEvent = new YAHOO.util.CustomEvent(defEvents.CLEAR);
		this.clearEvent.subscribe = sub; this.clearEvent.unsubscribe = unsub;
	
		/**
		* Fired just before the CalendarGroup is to be shown
		* @event beforeShowEvent
		*/
		this.beforeShowEvent = new YAHOO.util.CustomEvent(defEvents.BEFORE_SHOW);
	
		/**
		* Fired after the CalendarGroup is shown
		* @event showEvent
		*/
		this.showEvent = new YAHOO.util.CustomEvent(defEvents.SHOW);
	
		/**
		* Fired just before the CalendarGroup is to be hidden
		* @event beforeHideEvent
		*/
		this.beforeHideEvent = new YAHOO.util.CustomEvent(defEvents.BEFORE_HIDE);
	
		/**
		* Fired after the CalendarGroup is hidden
		* @event hideEvent
		*/
		this.hideEvent = new YAHOO.util.CustomEvent(defEvents.HIDE);

		/**
		* Fired just before the CalendarNavigator is to be shown
		* @event beforeShowNavEvent
		*/
		this.beforeShowNavEvent = new YAHOO.util.CustomEvent(defEvents.BEFORE_SHOW_NAV);
	
		/**
		* Fired after the CalendarNavigator is shown
		* @event showNavEvent
		*/
		this.showNavEvent = new YAHOO.util.CustomEvent(defEvents.SHOW_NAV);
	
		/**
		* Fired just before the CalendarNavigator is to be hidden
		* @event beforeHideNavEvent
		*/
		this.beforeHideNavEvent = new YAHOO.util.CustomEvent(defEvents.BEFORE_HIDE_NAV);
	
		/**
		* Fired after the CalendarNavigator is hidden
		* @event hideNavEvent
		*/
		this.hideNavEvent = new YAHOO.util.CustomEvent(defEvents.HIDE_NAV);

		/**
		* Fired just before the CalendarNavigator is to be rendered
		* @event beforeRenderNavEvent
		*/
		this.beforeRenderNavEvent = new YAHOO.util.CustomEvent(defEvents.BEFORE_RENDER_NAV);

		/**
		* Fired after the CalendarNavigator is rendered
		* @event renderNavEvent
		*/
		this.renderNavEvent = new YAHOO.util.CustomEvent(defEvents.RENDER_NAV);
	},
	
	/**
	* The default Config handler for the "pages" property
	* @method configPages
	* @param {String} type	The CustomEvent type (usually the property name)
	* @param {Object[]}	args	The CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
	* @param {Object} obj	The scope object. For configuration handlers, this will usually equal the owner.
	*/
	configPages : function(type, args, obj) {
		var pageCount = args[0];
	
		var cfgPageDate = YAHOO.widget.CalendarGroup._DEFAULT_CONFIG.PAGEDATE.key;
	
		// Define literals outside loop	
		var sep = "_";
		var groupCalClass = "groupcal";
	
		var firstClass = "first-of-type";
		var lastClass = "last-of-type";
	
		for (var p=0;p<pageCount;++p) {
			var calId = this.id + sep + p;
			var calContainerId = this.containerId + sep + p;
	
			var childConfig = this.cfg.getConfig();
			childConfig.close = false;
			childConfig.title = false;
			childConfig.navigator = null;

			var cal = this.constructChild(calId, calContainerId, childConfig);
			var caldate = cal.cfg.getProperty(cfgPageDate);
			this._setMonthOnDate(caldate, caldate.getMonth() + p);
			cal.cfg.setProperty(cfgPageDate, caldate);
	
			YAHOO.util.Dom.removeClass(cal.oDomContainer, this.Style.CSS_SINGLE);
			YAHOO.util.Dom.addClass(cal.oDomContainer, groupCalClass);

			if (p===0) {
				YAHOO.util.Dom.addClass(cal.oDomContainer, firstClass);
			}
	
			if (p==(pageCount-1)) {
				YAHOO.util.Dom.addClass(cal.oDomContainer, lastClass);
			}
	
			cal.parent = this;
			cal.index = p; 
	
			this.pages[this.pages.length] = cal;
		}
	},
	
	/**
	* The default Config handler for the "pagedate" property
	* @method configPageDate
	* @param {String} type	The CustomEvent type (usually the property name)
	* @param {Object[]}	args	The CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
	* @param {Object} obj	The scope object. For configuration handlers, this will usually equal the owner.
	*/
	configPageDate : function(type, args, obj) {
		var val = args[0];
		var firstPageDate;
		
		var cfgPageDate = YAHOO.widget.CalendarGroup._DEFAULT_CONFIG.PAGEDATE.key;
		
		for (var p=0;p<this.pages.length;++p) {
			var cal = this.pages[p];
			if (p === 0) {
				firstPageDate = cal._parsePageDate(val);
				cal.cfg.setProperty(cfgPageDate, firstPageDate);
			} else {
				var pageDate = new Date(firstPageDate);
				this._setMonthOnDate(pageDate, pageDate.getMonth() + p);
				cal.cfg.setProperty(cfgPageDate, pageDate);
			}
		}
	},
	
	/**
	* The default Config handler for the CalendarGroup "selected" property
	* @method configSelected
	* @param {String} type	The CustomEvent type (usually the property name)
	* @param {Object[]}	args	The CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
	* @param {Object} obj	The scope object. For configuration handlers, this will usually equal the owner.
	*/
	configSelected : function(type, args, obj) {
		var cfgSelected = YAHOO.widget.CalendarGroup._DEFAULT_CONFIG.SELECTED.key;
		this.delegateConfig(type, args, obj);
		var selected = (this.pages.length > 0) ? this.pages[0].cfg.getProperty(cfgSelected) : []; 
		this.cfg.setProperty(cfgSelected, selected, true);
	},

	
	/**
	* Delegates a configuration property to the CustomEvents associated with the CalendarGroup's children
	* @method delegateConfig
	* @param {String} type	The CustomEvent type (usually the property name)
	* @param {Object[]}	args	The CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
	* @param {Object} obj	The scope object. For configuration handlers, this will usually equal the owner.
	*/
	delegateConfig : function(type, args, obj) {
		var val = args[0];
		var cal;
	
		for (var p=0;p<this.pages.length;p++) {
			cal = this.pages[p];
			cal.cfg.setProperty(type, val);
		}
	},

	/**
	* Adds a function to all child Calendars within this CalendarGroup.
	* @method setChildFunction
	* @param {String}		fnName		The name of the function
	* @param {Function}		fn			The function to apply to each Calendar page object
	*/
	setChildFunction : function(fnName, fn) {
		var pageCount = this.cfg.getProperty(YAHOO.widget.CalendarGroup._DEFAULT_CONFIG.PAGES.key);
	
		for (var p=0;p<pageCount;++p) {
			this.pages[p][fnName] = fn;
		}
	},

	/**
	* Calls a function within all child Calendars within this CalendarGroup.
	* @method callChildFunction
	* @param {String}		fnName		The name of the function
	* @param {Array}		args		The arguments to pass to the function
	*/
	callChildFunction : function(fnName, args) {
		var pageCount = this.cfg.getProperty(YAHOO.widget.CalendarGroup._DEFAULT_CONFIG.PAGES.key);
	
		for (var p=0;p<pageCount;++p) {
			var page = this.pages[p];
			if (page[fnName]) {
				var fn = page[fnName];
				fn.call(page, args);
			}
		}	
	},

	/**
	* Constructs a child calendar. This method can be overridden if a subclassed version of the default
	* calendar is to be used.
	* @method constructChild
	* @param {String}	id			The id of the table element that will represent the calendar widget
	* @param {String}	containerId	The id of the container div element that will wrap the calendar table
	* @param {Object}	config		The configuration object containing the Calendar's arguments
	* @return {YAHOO.widget.Calendar}	The YAHOO.widget.Calendar instance that is constructed
	*/
	constructChild : function(id,containerId,config) {
		var container = document.getElementById(containerId);
		if (! container) {
			container = document.createElement("div");
			container.id = containerId;
			this.oDomContainer.appendChild(container);
		}
		return new YAHOO.widget.Calendar(id,containerId,config);
	},
	
	/**
	* Sets the calendar group's month explicitly. This month will be set into the first
	* page of the multi-page calendar, and all other months will be iterated appropriately.
	* @method setMonth
	* @param {Number}	month		The numeric month, from 0 (January) to 11 (December)
	*/
	setMonth : function(month) {
		month = parseInt(month, 10);
		var currYear;

		var cfgPageDate = YAHOO.widget.CalendarGroup._DEFAULT_CONFIG.PAGEDATE.key;

		for (var p=0; p<this.pages.length; ++p) {
			var cal = this.pages[p];
			var pageDate = cal.cfg.getProperty(cfgPageDate);
			if (p === 0) {
				currYear = pageDate.getFullYear();
			} else {
				pageDate.setFullYear(currYear);
			}
			this._setMonthOnDate(pageDate, month+p); 
			cal.cfg.setProperty(cfgPageDate, pageDate);
		}
	},

	/**
	* Sets the calendar group's year explicitly. This year will be set into the first
	* page of the multi-page calendar, and all other months will be iterated appropriately.
	* @method setYear
	* @param {Number}	year		The numeric 4-digit year
	*/
	setYear : function(year) {
	
		var cfgPageDate = YAHOO.widget.CalendarGroup._DEFAULT_CONFIG.PAGEDATE.key;
	
		year = parseInt(year, 10);
		for (var p=0;p<this.pages.length;++p) {
			var cal = this.pages[p];
			var pageDate = cal.cfg.getProperty(cfgPageDate);
	
			if ((pageDate.getMonth()+1) == 1 && p>0) {
				year+=1;
			}
			cal.setYear(year);
		}
	},

	/**
	* Calls the render function of all child calendars within the group.
	* @method render
	*/
	render : function() {
		this.renderHeader();
		for (var p=0;p<this.pages.length;++p) {
			var cal = this.pages[p];
			cal.render();
		}
		this.renderFooter();
	},

	/**
	* Selects a date or a collection of dates on the current calendar. This method, by default,
	* does not call the render method explicitly. Once selection has completed, render must be 
	* called for the changes to be reflected visually.
	* @method select
	* @param	{String/Date/Date[]}	date	The date string of dates to select in the current calendar. Valid formats are
	*								individual date(s) (12/24/2005,12/26/2005) or date range(s) (12/24/2005-1/1/2006).
	*								Multiple comma-delimited dates can also be passed to this method (12/24/2005,12/11/2005-12/13/2005).
	*								This method can also take a JavaScript Date object or an array of Date objects.
	* @return	{Date[]}			Array of JavaScript Date objects representing all individual dates that are currently selected.
	*/
	select : function(date) {
		for (var p=0;p<this.pages.length;++p) {
			var cal = this.pages[p];
			cal.select(date);
		}
		return this.getSelectedDates();
	},

	/**
	* Selects dates in the CalendarGroup based on the cell index provided. This method is used to select cells without having to do a full render. The selected style is applied to the cells directly.
	* The value of the MULTI_SELECT Configuration attribute will determine the set of dates which get selected. 
	* <ul>
	*    <li>If MULTI_SELECT is false, selectCell will select the cell at the specified index for only the last displayed Calendar page.</li>
	*    <li>If MULTI_SELECT is true, selectCell will select the cell at the specified index, on each displayed Calendar page.</li>
	* </ul>
	* @method selectCell
	* @param	{Number}	cellIndex	The index of the cell to be selected. 
	* @return	{Date[]}	Array of JavaScript Date objects representing all individual dates that are currently selected.
	*/
	selectCell : function(cellIndex) {
		for (var p=0;p<this.pages.length;++p) {
			var cal = this.pages[p];
			cal.selectCell(cellIndex);
		}
		return this.getSelectedDates();
	},
	
	/**
	* Deselects a date or a collection of dates on the current calendar. This method, by default,
	* does not call the render method explicitly. Once deselection has completed, render must be 
	* called for the changes to be reflected visually.
	* @method deselect
	* @param	{String/Date/Date[]}	date	The date string of dates to deselect in the current calendar. Valid formats are
	*								individual date(s) (12/24/2005,12/26/2005) or date range(s) (12/24/2005-1/1/2006).
	*								Multiple comma-delimited dates can also be passed to this method (12/24/2005,12/11/2005-12/13/2005).
	*								This method can also take a JavaScript Date object or an array of Date objects.	
	* @return	{Date[]}			Array of JavaScript Date objects representing all individual dates that are currently selected.
	*/
	deselect : function(date) {
		for (var p=0;p<this.pages.length;++p) {
			var cal = this.pages[p];
			cal.deselect(date);
		}
		return this.getSelectedDates();
	},
	
	/**
	* Deselects all dates on the current calendar.
	* @method deselectAll
	* @return {Date[]}		Array of JavaScript Date objects representing all individual dates that are currently selected.
	*						Assuming that this function executes properly, the return value should be an empty array.
	*						However, the empty array is returned for the sake of being able to check the selection status
	*						of the calendar.
	*/
	deselectAll : function() {
		for (var p=0;p<this.pages.length;++p) {
			var cal = this.pages[p];
			cal.deselectAll();
		}
		return this.getSelectedDates();
	},
	
	/**
	* Deselects dates in the CalendarGroup based on the cell index provided. This method is used to select cells without having to do a full render. The selected style is applied to the cells directly.
	* deselectCell will deselect the cell at the specified index on each displayed Calendar page.
	*
	* @method deselectCell
	* @param	{Number}	cellIndex	The index of the cell to deselect. 
	* @return	{Date[]}	Array of JavaScript Date objects representing all individual dates that are currently selected.
	*/
	deselectCell : function(cellIndex) {
		for (var p=0;p<this.pages.length;++p) {
			var cal = this.pages[p];
			cal.deselectCell(cellIndex);
		}
		return this.getSelectedDates();
	},
	
	/**
	* Resets the calendar widget to the originally selected month and year, and 
	* sets the calendar to the initial selection(s).
	* @method reset
	*/
	reset : function() {
		for (var p=0;p<this.pages.length;++p) {
			var cal = this.pages[p];
			cal.reset();
		}
	},
	
	/**
	* Clears the selected dates in the current calendar widget and sets the calendar
	* to the current month and year.
	* @method clear
	*/
	clear : function() {
		for (var p=0;p<this.pages.length;++p) {
			var cal = this.pages[p];
			cal.clear();
		}
	},
	
	/**
	* Navigates to the next month page in the calendar widget.
	* @method nextMonth
	*/
	nextMonth : function() {
		for (var p=0;p<this.pages.length;++p) {
			var cal = this.pages[p];
			cal.nextMonth();
		}
	},
	
	/**
	* Navigates to the previous month page in the calendar widget.
	* @method previousMonth
	*/
	previousMonth : function() {
		for (var p=this.pages.length-1;p>=0;--p) {
			var cal = this.pages[p];
			cal.previousMonth();
		}
	},
	
	/**
	* Navigates to the next year in the currently selected month in the calendar widget.
	* @method nextYear
	*/
	nextYear : function() {
		for (var p=0;p<this.pages.length;++p) {
			var cal = this.pages[p];
			cal.nextYear();
		}
	},

	/**
	* Navigates to the previous year in the currently selected month in the calendar widget.
	* @method previousYear
	*/
	previousYear : function() {
		for (var p=0;p<this.pages.length;++p) {
			var cal = this.pages[p];
			cal.previousYear();
		}
	},

	/**
	* Gets the list of currently selected dates from the calendar.
	* @return			An array of currently selected JavaScript Date objects.
	* @type Date[]
	*/
	getSelectedDates : function() { 
		var returnDates = [];
		var selected = this.cfg.getProperty(YAHOO.widget.CalendarGroup._DEFAULT_CONFIG.SELECTED.key);
		for (var d=0;d<selected.length;++d) {
			var dateArray = selected[d];

			var date = YAHOO.widget.DateMath.getDate(dateArray[0],dateArray[1]-1,dateArray[2]);
			returnDates.push(date);
		}

		returnDates.sort( function(a,b) { return a-b; } );
		return returnDates;
	},

	/**
	* Adds a renderer to the render stack. The function reference passed to this method will be executed
	* when a date cell matches the conditions specified in the date string for this renderer.
	* @method addRenderer
	* @param	{String}	sDates		A date string to associate with the specified renderer. Valid formats
	*									include date (12/24/2005), month/day (12/24), and range (12/1/2004-1/1/2005)
	* @param	{Function}	fnRender	The function executed to render cells that match the render rules for this renderer.
	*/
	addRenderer : function(sDates, fnRender) {
		for (var p=0;p<this.pages.length;++p) {
			var cal = this.pages[p];
			cal.addRenderer(sDates, fnRender);
		}
	},

	/**
	* Adds a month to the render stack. The function reference passed to this method will be executed
	* when a date cell matches the month passed to this method.
	* @method addMonthRenderer
	* @param	{Number}	month		The month (1-12) to associate with this renderer
	* @param	{Function}	fnRender	The function executed to render cells that match the render rules for this renderer.
	*/
	addMonthRenderer : function(month, fnRender) {
		for (var p=0;p<this.pages.length;++p) {
			var cal = this.pages[p];
			cal.addMonthRenderer(month, fnRender);
		}
	},

	/**
	* Adds a weekday to the render stack. The function reference passed to this method will be executed
	* when a date cell matches the weekday passed to this method.
	* @method addWeekdayRenderer
	* @param	{Number}	weekday		The weekday (1-7) to associate with this renderer. 1=Sunday, 2=Monday etc.
	* @param	{Function}	fnRender	The function executed to render cells that match the render rules for this renderer.
	*/
	addWeekdayRenderer : function(weekday, fnRender) {
		for (var p=0;p<this.pages.length;++p) {
			var cal = this.pages[p];
			cal.addWeekdayRenderer(weekday, fnRender);
		}
	},

	/**
	 * Removes all custom renderers added to the CalendarGroup through the addRenderer, addMonthRenderer and 
	 * addWeekRenderer methods. CalendarGroup's render method needs to be called to after removing renderers 
	 * to see the changes applied.
	 * 
	 * @method removeRenderers
	 */
	removeRenderers : function() {
		this.callChildFunction("removeRenderers");
	},

	/**
	* Renders the header for the CalendarGroup.
	* @method renderHeader
	*/
	renderHeader : function() {
		// EMPTY DEFAULT IMPL
	},

	/**
	* Renders a footer for the 2-up calendar container. By default, this method is
	* unimplemented.
	* @method renderFooter
	*/
	renderFooter : function() {
		// EMPTY DEFAULT IMPL
	},

	/**
	* Adds the designated number of months to the current calendar month, and sets the current
	* calendar page date to the new month.
	* @method addMonths
	* @param {Number}	count	The number of months to add to the current calendar
	*/
	addMonths : function(count) {
		this.callChildFunction("addMonths", count);
	},
	
	/**
	* Subtracts the designated number of months from the current calendar month, and sets the current
	* calendar page date to the new month.
	* @method subtractMonths
	* @param {Number}	count	The number of months to subtract from the current calendar
	*/
	subtractMonths : function(count) {
		this.callChildFunction("subtractMonths", count);
	},

	/**
	* Adds the designated number of years to the current calendar, and sets the current
	* calendar page date to the new month.
	* @method addYears
	* @param {Number}	count	The number of years to add to the current calendar
	*/
	addYears : function(count) {
		this.callChildFunction("addYears", count);
	},

	/**
	* Subtcats the designated number of years from the current calendar, and sets the current
	* calendar page date to the new month.
	* @method subtractYears
	* @param {Number}	count	The number of years to subtract from the current calendar
	*/
	subtractYears : function(count) {
		this.callChildFunction("subtractYears", count);
	},

	/**
	 * Returns the Calendar page instance which has a pagedate (month/year) matching the given date. 
	 * Returns null if no match is found.
	 * 
	 * @method getCalendarPage
	 * @param {Date} date The JavaScript Date object for which a Calendar page is to be found.
	 * @return {Calendar} The Calendar page instance representing the month to which the date 
	 * belongs.
	 */
	getCalendarPage : function(date) {
		var cal = null;
		if (date) {
			var y = date.getFullYear(),
				m = date.getMonth();

			var pages = this.pages;
			for (var i = 0; i < pages.length; ++i) {
				var pageDate = pages[i].cfg.getProperty("pagedate");
				if (pageDate.getFullYear() === y && pageDate.getMonth() === m) {
					cal = pages[i];
					break;
				}
			}
		}
		return cal;
	},

	/**
	* Sets the month on a Date object, taking into account year rollover if the month is less than 0 or greater than 11.
	* The Date object passed in is modified. It should be cloned before passing it into this method if the original value needs to be maintained
	* @method	_setMonthOnDate
	* @private
	* @param	{Date}	date	The Date object on which to set the month index
	* @param	{Number}	iMonth	The month index to set
	*/
	_setMonthOnDate : function(date, iMonth) {
		// Bug in Safari 1.3, 2.0 (WebKit build < 420), Date.setMonth does not work consistently if iMonth is not 0-11
		if (YAHOO.env.ua.webkit && YAHOO.env.ua.webkit < 420 && (iMonth < 0 || iMonth > 11)) {
			var DM = YAHOO.widget.DateMath;
			var newDate = DM.add(date, DM.MONTH, iMonth-date.getMonth());
			date.setTime(newDate.getTime());
		} else {
			date.setMonth(iMonth);
		}
	},
	
	/**
	 * Fixes the width of the CalendarGroup container element, to account for miswrapped floats
	 * @method _fixWidth
	 * @private
	 */
	_fixWidth : function() {
		var w = 0;
		for (var p=0;p<this.pages.length;++p) {
			var cal = this.pages[p];
			w += cal.oDomContainer.offsetWidth;
		}
		if (w > 0) {
			this.oDomContainer.style.width = w + "px";
		}
	},
	
	/**
	* Returns a string representation of the object.
	* @method toString
	* @return {String}	A string representation of the CalendarGroup object.
	*/
	toString : function() {
		return "CalendarGroup " + this.id;
	}
};

/**
* CSS class representing the container for the calendar
* @property YAHOO.widget.CalendarGroup.CSS_CONTAINER
* @static
* @final
* @type String
*/
YAHOO.widget.CalendarGroup.CSS_CONTAINER = "yui-calcontainer";

/**
* CSS class representing the container for the calendar
* @property YAHOO.widget.CalendarGroup.CSS_MULTI_UP
* @static
* @final
* @type String
*/
YAHOO.widget.CalendarGroup.CSS_MULTI_UP = "multi";

/**
* CSS class representing the title for the 2-up calendar
* @property YAHOO.widget.CalendarGroup.CSS_2UPTITLE
* @static
* @final
* @type String
*/
YAHOO.widget.CalendarGroup.CSS_2UPTITLE = "title";

/**
* CSS class representing the close icon for the 2-up calendar
* @property YAHOO.widget.CalendarGroup.CSS_2UPCLOSE
* @static
* @final
* @deprecated	Along with Calendar.IMG_ROOT and NAV_ARROW_LEFT, NAV_ARROW_RIGHT configuration properties.
*					Calendar's <a href="YAHOO.widget.Calendar.html#Style.CSS_CLOSE">Style.CSS_CLOSE</a> property now represents the CSS class used to render the close icon
* @type String
*/
YAHOO.widget.CalendarGroup.CSS_2UPCLOSE = "close-icon";

YAHOO.lang.augmentProto(YAHOO.widget.CalendarGroup, YAHOO.widget.Calendar, "buildDayLabel",
																 "buildMonthLabel",
																 "renderOutOfBoundsDate",
																 "renderRowHeader",
																 "renderRowFooter",
																 "renderCellDefault",
																 "styleCellDefault",
																 "renderCellStyleHighlight1",
																 "renderCellStyleHighlight2",
																 "renderCellStyleHighlight3",
																 "renderCellStyleHighlight4",
																 "renderCellStyleToday",
																 "renderCellStyleSelected",
																 "renderCellNotThisMonth",
																 "renderBodyCellRestricted",
																 "initStyles",
																 "configTitle",
																 "configClose",
																 "configIframe",
																 "configNavigator",
																 "createTitleBar",
																 "createCloseButton",
																 "removeTitleBar",
																 "removeCloseButton",
																 "hide",
																 "show",
																 "toDate",
																 "_parseArgs",
																 "browser");

/**
* The set of default Config property keys and values for the CalendarGroup
* @property YAHOO.widget.CalendarGroup._DEFAULT_CONFIG
* @final
* @static
* @private
* @type Object
*/
YAHOO.widget.CalendarGroup._DEFAULT_CONFIG = YAHOO.widget.Calendar._DEFAULT_CONFIG;
YAHOO.widget.CalendarGroup._DEFAULT_CONFIG.PAGES = {key:"pages", value:2};

YAHOO.widget.CalGrp = YAHOO.widget.CalendarGroup;

/**
* @class YAHOO.widget.Calendar2up
* @extends YAHOO.widget.CalendarGroup
* @deprecated The old Calendar2up class is no longer necessary, since CalendarGroup renders in a 2up view by default.
*/
YAHOO.widget.Calendar2up = function(id, containerId, config) {
	this.init(id, containerId, config);
};

YAHOO.extend(YAHOO.widget.Calendar2up, YAHOO.widget.CalendarGroup);

/**
* @deprecated The old Calendar2up class is no longer necessary, since CalendarGroup renders in a 2up view by default.
*/
YAHOO.widget.Cal2up = YAHOO.widget.Calendar2up;

/**
 * The CalendarNavigator is used along with a Calendar/CalendarGroup to 
 * provide a Month/Year popup navigation control, allowing the user to navigate 
 * to a specific month/year in the Calendar/CalendarGroup without having to 
 * scroll through months sequentially
 *
 * @namespace YAHOO.widget
 * @class CalendarNavigator
 * @constructor
 * @param {Calendar|CalendarGroup} cal The instance of the Calendar or CalendarGroup to which this CalendarNavigator should be attached.
 */
YAHOO.widget.CalendarNavigator = function(cal) {
	this.init(cal);
};

(function() {
	// Setup static properties (inside anon fn, so that we can use shortcuts)
	var CN = YAHOO.widget.CalendarNavigator;

	/**
	 * YAHOO.widget.CalendarNavigator.CLASSES contains constants
	 * for the class values applied to the CalendarNaviatgator's 
	 * DOM elements
	 * @property YAHOO.widget.CalendarNavigator.CLASSES
	 * @type Object
	 * @static
	 */
	CN.CLASSES = {
		/**
		 * Class applied to the Calendar Navigator's bounding box
		 * @property YAHOO.widget.CalendarNavigator.CLASSES.NAV
		 * @type String
		 * @static
		 */
		NAV :"yui-cal-nav",
		/**
		 * Class applied to the Calendar/CalendarGroup's bounding box to indicate
		 * the Navigator is currently visible
		 * @property YAHOO.widget.CalendarNavigator.CLASSES.NAV_VISIBLE
		 * @type String
		 * @static
		 */
		NAV_VISIBLE: "yui-cal-nav-visible",
		/**
		 * Class applied to the Navigator mask's bounding box
		 * @property YAHOO.widget.CalendarNavigator.CLASSES.MASK
		 * @type String
		 * @static
		 */
		MASK : "yui-cal-nav-mask",
		/**
		 * Class applied to the year label/control bounding box
		 * @property YAHOO.widget.CalendarNavigator.CLASSES.YEAR
		 * @type String
		 * @static
		 */
		YEAR : "yui-cal-nav-y",
		/**
		 * Class applied to the month label/control bounding box
		 * @property YAHOO.widget.CalendarNavigator.CLASSES.MONTH
		 * @type String
		 * @static
		 */
		MONTH : "yui-cal-nav-m",
		/**
		 * Class applied to the submit/cancel button's bounding box
		 * @property YAHOO.widget.CalendarNavigator.CLASSES.BUTTONS
		 * @type String
		 * @static
		 */
		BUTTONS : "yui-cal-nav-b",
		/**
		 * Class applied to buttons wrapping element
		 * @property YAHOO.widget.CalendarNavigator.CLASSES.BUTTON
		 * @type String
		 * @static
		 */
		BUTTON : "yui-cal-nav-btn",
		/**
		 * Class applied to the validation error area's bounding box
		 * @property YAHOO.widget.CalendarNavigator.CLASSES.ERROR
		 * @type String
		 * @static
		 */
		ERROR : "yui-cal-nav-e",
		/**
		 * Class applied to the year input control
		 * @property YAHOO.widget.CalendarNavigator.CLASSES.YEAR_CTRL
		 * @type String
		 * @static
		 */
		YEAR_CTRL : "yui-cal-nav-yc",
		/**
		 * Class applied to the month input control
		 * @property YAHOO.widget.CalendarNavigator.CLASSES.MONTH_CTRL
		 * @type String
		 * @static
		 */
		MONTH_CTRL : "yui-cal-nav-mc",
		/**
		 * Class applied to controls with invalid data (e.g. a year input field with invalid an year)
		 * @property YAHOO.widget.CalendarNavigator.CLASSES.INVALID
		 * @type String
		 * @static
		 */
		INVALID : "yui-invalid",
		/**
		 * Class applied to default controls
		 * @property YAHOO.widget.CalendarNavigator.CLASSES.DEFAULT
		 * @type String
		 * @static
		 */
		DEFAULT : "yui-default"
	};

	/**
	 * Object literal containing the default configuration values for the CalendarNavigator
	 * The configuration object is expected to follow the format below, with the properties being
	 * case sensitive.
	 * <dl>
	 * <dt>strings</dt>
	 * <dd><em>Object</em> :  An object with the properties shown below, defining the string labels to use in the Navigator's UI
	 *     <dl>
	 *         <dt>month</dt><dd><em>String</em> : The string to use for the month label. Defaults to "Month".</dd>
	 *         <dt>year</dt><dd><em>String</em> : The string to use for the year label. Defaults to "Year".</dd>
	 *         <dt>submit</dt><dd><em>String</em> : The string to use for the submit button label. Defaults to "Okay".</dd>
	 *         <dt>cancel</dt><dd><em>String</em> : The string to use for the cancel button label. Defaults to "Cancel".</dd>
	 *         <dt>invalidYear</dt><dd><em>String</em> : The string to use for invalid year values. Defaults to "Year needs to be a number".</dd>
	 *     </dl>
	 * </dd>
	 * <dt>monthFormat</dt><dd><em>String</em> : The month format to use. Either YAHOO.widget.Calendar.LONG, or YAHOO.widget.Calendar.SHORT. Defaults to YAHOO.widget.Calendar.LONG</dd>
	 * <dt>initialFocus</dt><dd><em>String</em> : Either "year" or "month" specifying which input control should get initial focus. Defaults to "year"</dd>
	 * </dl>
	 * @property _DEFAULT_CFG
	 * @protected
	 * @type Object
	 * @static
	 */
	CN._DEFAULT_CFG = {
		strings : {
			month: "Month",
			year: "Year",
			submit: "Okay",
			cancel: "Cancel",
			invalidYear : "Year needs to be a number"
		},
		monthFormat: YAHOO.widget.Calendar.LONG,
		initialFocus: "year"
	};

	/**
	 * The suffix added to the Calendar/CalendarGroup's ID, to generate
	 * a unique ID for the Navigator and it's bounding box.
	 * @property YAHOO.widget.CalendarNavigator.ID_SUFFIX
	 * @static
	 * @type String
	 * @final
	 */
	CN.ID_SUFFIX = "_nav";
	/**
	 * The suffix added to the Navigator's ID, to generate
	 * a unique ID for the month control.
	 * @property YAHOO.widget.CalendarNavigator.MONTH_SUFFIX
	 * @static
	 * @type String 
	 * @final
	 */
	CN.MONTH_SUFFIX = "_month";
	/**
	 * The suffix added to the Navigator's ID, to generate
	 * a unique ID for the year control.
	 * @property YAHOO.widget.CalendarNavigator.YEAR_SUFFIX
	 * @static
	 * @type String
	 * @final
	 */
	CN.YEAR_SUFFIX = "_year";
	/**
	 * The suffix added to the Navigator's ID, to generate
	 * a unique ID for the error bounding box.
	 * @property YAHOO.widget.CalendarNavigator.ERROR_SUFFIX
	 * @static
	 * @type String
	 * @final
	 */
	CN.ERROR_SUFFIX = "_error";
	/**
	 * The suffix added to the Navigator's ID, to generate
	 * a unique ID for the "Cancel" button.
	 * @property YAHOO.widget.CalendarNavigator.CANCEL_SUFFIX
	 * @static
	 * @type String
	 * @final
	 */
	CN.CANCEL_SUFFIX = "_cancel";
	/**
	 * The suffix added to the Navigator's ID, to generate
	 * a unique ID for the "Submit" button.
	 * @property YAHOO.widget.CalendarNavigator.SUBMIT_SUFFIX
	 * @static
	 * @type String
	 * @final
	 */
	CN.SUBMIT_SUFFIX = "_submit";

	/**
	 * The number of digits to which the year input control is to be limited.
	 * @property YAHOO.widget.CalendarNavigator.YR_MAX_DIGITS
	 * @static
	 * @type Number
	 */
	CN.YR_MAX_DIGITS = 4;

	/**
	 * The amount by which to increment the current year value,
	 * when the arrow up/down key is pressed on the year control
	 * @property YAHOO.widget.CalendarNavigator.YR_MINOR_INC
	 * @static
	 * @type Number
	 */
	CN.YR_MINOR_INC = 1;

	/**
	 * The amount by which to increment the current year value,
	 * when the page up/down key is pressed on the year control
	 * @property YAHOO.widget.CalendarNavigator.YR_MAJOR_INC
	 * @static
	 * @type Number
	 */
	CN.YR_MAJOR_INC = 10;

	/**
	 * Artificial delay (in ms) between the time the Navigator is hidden
	 * and the Calendar/CalendarGroup state is updated. Allows the user
	 * the see the Calendar/CalendarGroup page changing. If set to 0
	 * the Calendar/CalendarGroup page will be updated instantly
	 * @property YAHOO.widget.CalendarNavigator.UPDATE_DELAY
	 * @static
	 * @type Number
	 */
	CN.UPDATE_DELAY = 50;

	/**
	 * Regular expression used to validate the year input
	 * @property YAHOO.widget.CalendarNavigator.YR_PATTERN
	 * @static
	 * @type RegExp
	 */
	CN.YR_PATTERN = /^\d+$/;
	/**
	 * Regular expression used to trim strings
	 * @property YAHOO.widget.CalendarNavigator.TRIM
	 * @static
	 * @type RegExp
	 */
	CN.TRIM = /^\s*(.*?)\s*$/;
})();

YAHOO.widget.CalendarNavigator.prototype = {

	/**
	 * The unique ID for this CalendarNavigator instance
	 * @property id
	 * @type String
	 */
	id : null,

	/**
	 * The Calendar/CalendarGroup instance to which the navigator belongs
	 * @property cal
	 * @type {Calendar|CalendarGroup}
	 */
	cal : null,

	/**
	 * Reference to the HTMLElement used to render the navigator's bounding box
	 * @property navEl
	 * @type HTMLElement
	 */
	navEl : null,

	/**
	 * Reference to the HTMLElement used to render the navigator's mask
	 * @property maskEl
	 * @type HTMLElement
	 */
	maskEl : null,

	/**
	 * Reference to the HTMLElement used to input the year
	 * @property yearEl
	 * @type HTMLElement
	 */
	yearEl : null,

	/**
	 * Reference to the HTMLElement used to input the month
	 * @property monthEl
	 * @type HTMLElement
	 */
	monthEl : null,

	/**
	 * Reference to the HTMLElement used to display validation errors
	 * @property errorEl
	 * @type HTMLElement
	 */
	errorEl : null,

	/**
	 * Reference to the HTMLElement used to update the Calendar/Calendar group
	 * with the month/year values
	 * @property submitEl
	 * @type HTMLElement
	 */
	submitEl : null,
	
	/**
	 * Reference to the HTMLElement used to hide the navigator without updating the 
	 * Calendar/Calendar group
	 * @property cancelEl
	 * @type HTMLElement
	 */
	cancelEl : null,

	/** 
	 * Reference to the first focusable control in the navigator (by default monthEl)
	 * @property firstCtrl
	 * @type HTMLElement
	 */
	firstCtrl : null,
	
	/** 
	 * Reference to the last focusable control in the navigator (by default cancelEl)
	 * @property lastCtrl
	 * @type HTMLElement
	 */
	lastCtrl : null,

	/**
	 * The document containing the Calendar/Calendar group instance
	 * @protected
	 * @property _doc
	 * @type HTMLDocument
	 */
	_doc : null,

	/**
	 * Internal state property for the current year displayed in the navigator
	 * @protected
	 * @property _year
	 * @type Number
	 */
	_year: null,
	
	/**
	 * Internal state property for the current month index displayed in the navigator
	 * @protected
	 * @property _month
	 * @type Number
	 */
	_month: 0,

	/**
	 * Private internal state property which indicates whether or not the 
	 * Navigator has been rendered.
	 * @private
	 * @property __rendered
	 * @type Boolean
	 */
	__rendered: false,

	/**
	 * Init lifecycle method called as part of construction
	 * 
	 * @method init
	 * @param {Calendar} cal The instance of the Calendar or CalendarGroup to which this CalendarNavigator should be attached
	 */
	init : function(cal) {
		var calBox = cal.oDomContainer;

		this.cal = cal;
		this.id = calBox.id + YAHOO.widget.CalendarNavigator.ID_SUFFIX;
		this._doc = calBox.ownerDocument;

		/**
		 * Private flag, to identify IE6/IE7 Quirks
		 * @private
		 * @property __isIEQuirks
		 */
		var ie = YAHOO.env.ua.ie;
		this.__isIEQuirks = (ie && ((ie <= 6) || (ie === 7 && this._doc.compatMode == "BackCompat")));
	},

	/**
	 * Displays the navigator and mask, updating the input controls to reflect the 
	 * currently set month and year. The show method will invoke the render method
	 * if the navigator has not been renderered already, allowing for lazy rendering
	 * of the control.
	 * 
	 * The show method will fire the Calendar/CalendarGroup's beforeShowNav and showNav events
	 * 
	 * @method show
	 */
	show : function() {
		var CLASSES = YAHOO.widget.CalendarNavigator.CLASSES;

		if (this.cal.beforeShowNavEvent.fire()) {
			if (!this.__rendered) {
				this.render();
			}
			this.clearErrors();

			this._updateMonthUI();
			this._updateYearUI();
			this._show(this.navEl, true);

			this.setInitialFocus();
			this.showMask();

			YAHOO.util.Dom.addClass(this.cal.oDomContainer, CLASSES.NAV_VISIBLE);
			this.cal.showNavEvent.fire();
		}
	},

	/**
	 * Hides the navigator and mask
	 * 
	 * The show method will fire the Calendar/CalendarGroup's beforeHideNav event and hideNav events
	 * @method hide
	 */
	hide : function() {
		var CLASSES = YAHOO.widget.CalendarNavigator.CLASSES;

		if (this.cal.beforeHideNavEvent.fire()) {
			this._show(this.navEl, false);
			this.hideMask();
			YAHOO.util.Dom.removeClass(this.cal.oDomContainer, CLASSES.NAV_VISIBLE);
			this.cal.hideNavEvent.fire();
		}
	},
	

	/**
	 * Displays the navigator's mask element
	 * 
	 * @method showMask
	 */
	showMask : function() {
		this._show(this.maskEl, true);
		if (this.__isIEQuirks) {
			this._syncMask();
		}
	},

	/**
	 * Hides the navigator's mask element
	 * 
	 * @method hideMask
	 */
	hideMask : function() {
		this._show(this.maskEl, false);
	},

	/**
	 * Returns the current month set on the navigator
	 * 
	 * Note: This may not be the month set in the UI, if 
	 * the UI contains an invalid value.
	 * 
	 * @method getMonth
	 * @return {Number} The Navigator's current month index
	 */
	getMonth: function() {
		return this._month;
	},

	/**
	 * Returns the current year set on the navigator
	 * 
	 * Note: This may not be the year set in the UI, if 
	 * the UI contains an invalid value.
	 * 
	 * @method getYear
	 * @return {Number} The Navigator's current year value
	 */
	getYear: function() {
		return this._year;
	},

	/**
	 * Sets the current month on the Navigator, and updates the UI
	 * 
	 * @method setMonth
	 * @param {Number} nMonth The month index, from 0 (Jan) through 11 (Dec).
	 */
	setMonth : function(nMonth) {
		if (nMonth >= 0 && nMonth < 12) {
			this._month = nMonth;
		}
		this._updateMonthUI();
	},

	/**
	 * Sets the current year on the Navigator, and updates the UI. If the 
	 * provided year is invalid, it will not be set.
	 * 
	 * @method setYear
	 * @param {Number} nYear The full year value to set the Navigator to.
	 */
	setYear : function(nYear) {
		var yrPattern = YAHOO.widget.CalendarNavigator.YR_PATTERN;
		if (YAHOO.lang.isNumber(nYear) && yrPattern.test(nYear+"")) {
			this._year = nYear;
		}
		this._updateYearUI();
	},

	/**
	 * Renders the HTML for the navigator, adding it to the 
	 * document and attaches event listeners if it has not 
	 * already been rendered.
	 * 
	 * @method render
	 */
	render: function() {
		this.cal.beforeRenderNavEvent.fire();
		if (!this.__rendered) {
			this.createNav();
			this.createMask();
			this.applyListeners();
			this.__rendered = true;
		}
		this.cal.renderNavEvent.fire();
	},

	/**
	 * Creates the navigator's containing HTMLElement, it's contents, and appends 
	 * the containg element to the Calendar/CalendarGroup's container.
	 * 
	 * @method createNav
	 */
	createNav : function() {
		var NAV = YAHOO.widget.CalendarNavigator;
		var doc = this._doc;

		var d = doc.createElement("div");
		d.className = NAV.CLASSES.NAV;

		var htmlBuf = this.renderNavContents([]);

		d.innerHTML = htmlBuf.join('');
		this.cal.oDomContainer.appendChild(d);

		this.navEl = d;

		this.yearEl = doc.getElementById(this.id + NAV.YEAR_SUFFIX);
		this.monthEl = doc.getElementById(this.id + NAV.MONTH_SUFFIX);
		this.errorEl = doc.getElementById(this.id + NAV.ERROR_SUFFIX);
		this.submitEl = doc.getElementById(this.id + NAV.SUBMIT_SUFFIX);
		this.cancelEl = doc.getElementById(this.id + NAV.CANCEL_SUFFIX);

		if (YAHOO.env.ua.gecko && this.yearEl && this.yearEl.type == "text") {
			// Avoid XUL error on focus, select [ https://bugzilla.mozilla.org/show_bug.cgi?id=236791, 
			// supposedly fixed in 1.8.1, but there are reports of it still being around for methods other than blur ]
			this.yearEl.setAttribute("autocomplete", "off");
		}

		this._setFirstLastElements();
	},

	/**
	 * Creates the Mask HTMLElement and appends it to the Calendar/CalendarGroups
	 * container.
	 * 
	 * @method createMask
	 */
	createMask : function() {
		var C = YAHOO.widget.CalendarNavigator.CLASSES;

		var d = this._doc.createElement("div");
		d.className = C.MASK;

		this.cal.oDomContainer.appendChild(d);
		this.maskEl = d;
	},

	/**
	 * Used to set the width/height of the mask in pixels to match the Calendar Container.
	 * Currently only used for IE6 and IE7 quirks mode. The other A-Grade browser are handled using CSS (width/height 100%).
	 * <p>
	 * The method is also registered as an HTMLElement resize listener on the Calendars container element.
	 * </p>
	 * @protected
	 * @method _syncMask
	 */
	_syncMask : function() {
		var c = this.cal.oDomContainer;
		if (c && this.maskEl) {
			var r = YAHOO.util.Dom.getRegion(c);
			YAHOO.util.Dom.setStyle(this.maskEl, "width", r.right - r.left + "px");
			YAHOO.util.Dom.setStyle(this.maskEl, "height", r.bottom - r.top + "px");
		}
	},

	/**
	 * Renders the contents of the navigator
	 * 
	 * @method renderNavContents
	 * 
	 * @param {Array} html The HTML buffer to append the HTML to.
	 * @return {Array} A reference to the buffer passed in.
	 */
	renderNavContents : function(html) {
		var NAV = YAHOO.widget.CalendarNavigator,
			C = NAV.CLASSES,
			h = html; // just to use a shorter name

		h[h.length] = '<div class="' + C.MONTH + '">';
		this.renderMonth(h);
		h[h.length] = '</div>';
		h[h.length] = '<div class="' + C.YEAR + '">';
		this.renderYear(h);
		h[h.length] = '</div>';
		h[h.length] = '<div class="' + C.BUTTONS + '">';
		this.renderButtons(h);
		h[h.length] = '</div>';
		h[h.length] = '<div class="' + C.ERROR + '" id="' + this.id + NAV.ERROR_SUFFIX + '"></div>';

		return h;
	},

	/**
	 * Renders the month label and control for the navigator
	 * 
	 * @method renderNavContents
	 * @param {Array} html The HTML buffer to append the HTML to.
	 * @return {Array} A reference to the buffer passed in.
	 */
	renderMonth : function(html) {
		var NAV = YAHOO.widget.CalendarNavigator,
			C = NAV.CLASSES;

		var id = this.id + NAV.MONTH_SUFFIX,
			mf = this.__getCfg("monthFormat"),
			months = this.cal.cfg.getProperty((mf == YAHOO.widget.Calendar.SHORT) ? "MONTHS_SHORT" : "MONTHS_LONG"),
			h = html;

		if (months && months.length > 0) {
			h[h.length] = '<label for="' + id + '">';
			h[h.length] = this.__getCfg("month", true);
			h[h.length] = '</label>';
			h[h.length] = '<select name="' + id + '" id="' + id + '" class="' + C.MONTH_CTRL + '">';
			for (var i = 0; i < months.length; i++) {
				h[h.length] = '<option value="' + i + '">';
				h[h.length] = months[i];
				h[h.length] = '</option>';
			}
			h[h.length] = '</select>';
		}
		return h;
	},

	/**
	 * Renders the year label and control for the navigator
	 * 
	 * @method renderYear
	 * @param {Array} html The HTML buffer to append the HTML to.
	 * @return {Array} A reference to the buffer passed in.
	 */
	renderYear : function(html) {
		var NAV = YAHOO.widget.CalendarNavigator,
			C = NAV.CLASSES;

		var id = this.id + NAV.YEAR_SUFFIX,
			size = NAV.YR_MAX_DIGITS,
			h = html;

		h[h.length] = '<label for="' + id + '">';
		h[h.length] = this.__getCfg("year", true);
		h[h.length] = '</label>';
		h[h.length] = '<input type="text" name="' + id + '" id="' + id + '" class="' + C.YEAR_CTRL + '" maxlength="' + size + '"/>';
		return h;
	},

	/**
	 * Renders the submit/cancel buttons for the navigator
	 * 
	 * @method renderButton
	 * @return {String} The HTML created for the Button UI
	 */
	renderButtons : function(html) {
		var C = YAHOO.widget.CalendarNavigator.CLASSES;
		var h = html;

		h[h.length] = '<span class="' + C.BUTTON + ' ' + C.DEFAULT + '">';
		h[h.length] = '<button type="button" id="' + this.id + '_submit' + '">';
		h[h.length] = this.__getCfg("submit", true);
		h[h.length] = '</button>';
		h[h.length] = '</span>';
		h[h.length] = '<span class="' + C.BUTTON +'">';
		h[h.length] = '<button type="button" id="' + this.id + '_cancel' + '">';
		h[h.length] = this.__getCfg("cancel", true);
		h[h.length] = '</button>';
		h[h.length] = '</span>';

		return h;
	},

	/**
	 * Attaches DOM event listeners to the rendered elements
	 * <p>
	 * The method will call applyKeyListeners, to setup keyboard specific 
	 * listeners
	 * </p>
	 * @method applyListeners
	 */
	applyListeners : function() {
		var E = YAHOO.util.Event;

		function yearUpdateHandler() {
			if (this.validate()) {
				this.setYear(this._getYearFromUI());
			}
		}

		function monthUpdateHandler() {
			this.setMonth(this._getMonthFromUI());
		}

		E.on(this.submitEl, "click", this.submit, this, true);
		E.on(this.cancelEl, "click", this.cancel, this, true);
		E.on(this.yearEl, "blur", yearUpdateHandler, this, true);
		E.on(this.monthEl, "change", monthUpdateHandler, this, true);

		if (this.__isIEQuirks) {
			YAHOO.util.Event.on(this.cal.oDomContainer, "resize", this._syncMask, this, true);
		}

		this.applyKeyListeners();
	},

	/**
	 * Removes/purges DOM event listeners from the rendered elements
	 * 
	 * @method purgeListeners
	 */
	purgeListeners : function() {
		var E = YAHOO.util.Event;
		E.removeListener(this.submitEl, "click", this.submit);
		E.removeListener(this.cancelEl, "click", this.cancel);
		E.removeListener(this.yearEl, "blur");
		E.removeListener(this.monthEl, "change");
		if (this.__isIEQuirks) {
			E.removeListener(this.cal.oDomContainer, "resize", this._syncMask);
		}

		this.purgeKeyListeners();
	},

	/**
	 * Attaches DOM listeners for keyboard support. 
	 * Tab/Shift-Tab looping, Enter Key Submit on Year element,
	 * Up/Down/PgUp/PgDown year increment on Year element
	 * <p>
	 * NOTE: MacOSX Safari 2.x doesn't let you tab to buttons and 
	 * MacOSX Gecko does not let you tab to buttons or select controls,
	 * so for these browsers, Tab/Shift-Tab looping is limited to the 
	 * elements which can be reached using the tab key.
	 * </p>
	 * @method applyKeyListeners
	 */
	applyKeyListeners : function() {
		var E = YAHOO.util.Event,
			ua = YAHOO.env.ua;

		// IE/Safari 3.1 doesn't fire keypress for arrow/pg keys (non-char keys)
		var arrowEvt = (ua.ie || ua.webkit) ? "keydown" : "keypress";

		// - IE/Safari 3.1 doesn't fire keypress for non-char keys
		// - Opera doesn't allow us to cancel keydown or keypress for tab, but 
		//   changes focus successfully on keydown (keypress is too late to change focus - opera's already moved on).
		var tabEvt = (ua.ie || ua.opera || ua.webkit) ? "keydown" : "keypress";

		// Everyone likes keypress for Enter (char keys) - whoo hoo!
		E.on(this.yearEl, "keypress", this._handleEnterKey, this, true);

		E.on(this.yearEl, arrowEvt, this._handleDirectionKeys, this, true);
		E.on(this.lastCtrl, tabEvt, this._handleTabKey, this, true);
		E.on(this.firstCtrl, tabEvt, this._handleShiftTabKey, this, true);
	},

	/**
	 * Removes/purges DOM listeners for keyboard support
	 *
	 * @method purgeKeyListeners
	 */
	purgeKeyListeners : function() {
		var E = YAHOO.util.Event,
			ua = YAHOO.env.ua;

		var arrowEvt = (ua.ie || ua.webkit) ? "keydown" : "keypress";
		var tabEvt = (ua.ie || ua.opera || ua.webkit) ? "keydown" : "keypress";

		E.removeListener(this.yearEl, "keypress", this._handleEnterKey);
		E.removeListener(this.yearEl, arrowEvt, this._handleDirectionKeys);
		E.removeListener(this.lastCtrl, tabEvt, this._handleTabKey);
		E.removeListener(this.firstCtrl, tabEvt, this._handleShiftTabKey);
	},

	/**
	 * Updates the Calendar/CalendarGroup's pagedate with the currently set month and year if valid.
	 * <p>
	 * If the currently set month/year is invalid, a validation error will be displayed and the 
	 * Calendar/CalendarGroup's pagedate will not be updated.
	 * </p>
	 * @method submit
	 */
	submit : function() {
		if (this.validate()) {
			this.hide();

			this.setMonth(this._getMonthFromUI());
			this.setYear(this._getYearFromUI());

			var cal = this.cal;
			var nav = this;
			
			function update() {
				cal.setYear(nav.getYear());
				cal.setMonth(nav.getMonth());
				cal.render();
			}
			// Artificial delay, just to help the user see something changed
			var delay = YAHOO.widget.CalendarNavigator.UPDATE_DELAY;
			if (delay > 0) {
				window.setTimeout(update, delay);
			} else {
				update();
			}
		}
	},

	/**
	 * Hides the navigator and mask, without updating the Calendar/CalendarGroup's state
	 * 
	 * @method cancel
	 */
	cancel : function() {
		this.hide();
	},

	/**
	 * Validates the current state of the UI controls
	 * 
	 * @method validate
	 * @return {Boolean} true, if the current UI state contains valid values, false if not
	 */
	validate : function() {
		if (this._getYearFromUI() !== null) {
			this.clearErrors();
			return true;
		} else {
			this.setYearError();
			this.setError(this.__getCfg("invalidYear", true));
			return false;
		}
	},

	/**
	 * Displays an error message in the Navigator's error panel
	 * @method setError
	 * @param {String} msg The error message to display
	 */
	setError : function(msg) {
		if (this.errorEl) {
			this.errorEl.innerHTML = msg;
			this._show(this.errorEl, true);
		}
	},

	/**
	 * Clears the navigator's error message and hides the error panel
	 * @method clearError 
	 */
	clearError : function() {
		if (this.errorEl) {
			this.errorEl.innerHTML = "";
			this._show(this.errorEl, false);
		}
	},

	/**
	 * Displays the validation error UI for the year control
	 * @method setYearError
	 */
	setYearError : function() {
		YAHOO.util.Dom.addClass(this.yearEl, YAHOO.widget.CalendarNavigator.CLASSES.INVALID);
	},

	/**
	 * Removes the validation error UI for the year control
	 * @method clearYearError
	 */
	clearYearError : function() {
		YAHOO.util.Dom.removeClass(this.yearEl, YAHOO.widget.CalendarNavigator.CLASSES.INVALID);
	},

	/**
	 * Clears all validation and error messages in the UI
	 * @method clearErrors
	 */
	clearErrors : function() {
		this.clearError();
		this.clearYearError();
	},

	/**
	 * Sets the initial focus, based on the configured value
	 * @method setInitialFocus
	 */
	setInitialFocus : function() {
		var el = this.submitEl;
		var f = this.__getCfg("initialFocus");

		if (f && f.toLowerCase) {
			f = f.toLowerCase();
			if (f == "year") {
				el = this.yearEl;
				try {
					this.yearEl.select();
				} catch (e) {
					// Ignore;
				}
			} else if (f == "month") {
				el = this.monthEl;
			}
		}

		if (el && YAHOO.lang.isFunction(el.focus)) {
			try {
				el.focus();
			} catch (e) {
				// TODO: Fall back if focus fails?
			}
		}
	},

	/**
	 * Removes all renderered HTML elements for the Navigator from
	 * the DOM, purges event listeners and clears (nulls) any property
	 * references to HTML references
	 * @method erase
	 */
	erase : function() {
		if (this.__rendered) {
			this.purgeListeners();

			// Clear out innerHTML references
			this.yearEl = null;
			this.monthEl = null;
			this.errorEl = null;
			this.submitEl = null;
			this.cancelEl = null;
			this.firstCtrl = null;
			this.lastCtrl = null;
			if (this.navEl) {
				this.navEl.innerHTML = "";
			}

			var p = this.navEl.parentNode;
			if (p) {
				p.removeChild(this.navEl);
			}
			this.navEl = null;

			var pm = this.maskEl.parentNode;
			if (pm) {
				pm.removeChild(this.maskEl);
			}
			this.maskEl = null;
			this.__rendered = false;
		}
	},

	/**
	 * Destroys the Navigator object and any HTML references
	 * @method destroy
	 */
	destroy : function() {
		this.erase();
		this._doc = null;
		this.cal = null;
		this.id = null;
	},

	/**
	 * Protected implementation to handle how UI elements are 
	 * hidden/shown.
	 *
	 * @method _show
	 * @protected
	 */
	_show : function(el, bShow) {
		if (el) {
			YAHOO.util.Dom.setStyle(el, "display", (bShow) ? "block" : "none");
		}
	},

	/**
	 * Returns the month value (index), from the month UI element
	 * @protected
	 * @method _getMonthFromUI
	 * @return {Number} The month index, or 0 if a UI element for the month
	 * is not found
	 */
	_getMonthFromUI : function() {
		if (this.monthEl) {
			return this.monthEl.selectedIndex;
		} else {
			return 0; // Default to Jan
		}
	},

	/**
	 * Returns the year value, from the Navitator's year UI element
	 * @protected
	 * @method _getYearFromUI
	 * @return {Number} The year value set in the UI, if valid. null is returned if 
	 * the UI does not contain a valid year value.
	 */
	_getYearFromUI : function() {
		var NAV = YAHOO.widget.CalendarNavigator;

		var yr = null;
		if (this.yearEl) {
			var value = this.yearEl.value;
			value = value.replace(NAV.TRIM, "$1");

			if (NAV.YR_PATTERN.test(value)) {
				yr = parseInt(value, 10);
			}
		}
		return yr;
	},

	/**
	 * Updates the Navigator's year UI, based on the year value set on the Navigator object
	 * @protected
	 * @method _updateYearUI
	 */
	_updateYearUI : function() {
		if (this.yearEl && this._year !== null) {
			this.yearEl.value = this._year;
		}
	},

	/**
	 * Updates the Navigator's month UI, based on the month value set on the Navigator object
	 * @protected
	 * @method _updateMonthUI
	 */
	_updateMonthUI : function() {
		if (this.monthEl) {
			this.monthEl.selectedIndex = this._month;
		}
	},

	/**
	 * Sets up references to the first and last focusable element in the Navigator's UI
	 * in terms of tab order (Naviagator's firstEl and lastEl properties). The references
	 * are used to control modality by looping around from the first to the last control
	 * and visa versa for tab/shift-tab navigation.
	 * <p>
	 * See <a href="#applyKeyListeners">applyKeyListeners</a>
	 * </p>
	 * @protected
	 * @method _setFirstLastElements
	 */
	_setFirstLastElements : function() {
		this.firstCtrl = this.monthEl;
		this.lastCtrl = this.cancelEl;

		// Special handling for MacOSX.
		// - Safari 2.x can't focus on buttons
		// - Gecko can't focus on select boxes or buttons
		if (this.__isMac) {
			if (YAHOO.env.ua.webkit && YAHOO.env.ua.webkit < 420){
				this.firstCtrl = this.monthEl;
				this.lastCtrl = this.yearEl;
			}
			if (YAHOO.env.ua.gecko) {
				this.firstCtrl = this.yearEl;
				this.lastCtrl = this.yearEl;
			}
		}
	},

	/**
	 * Default Keyboard event handler to capture Enter 
	 * on the Navigator's year control (yearEl)
	 * 
	 * @method _handleEnterKey
	 * @protected
	 * @param {Event} e The DOM event being handled
	 */
	_handleEnterKey : function(e) {
		var KEYS = YAHOO.util.KeyListener.KEY;

		if (YAHOO.util.Event.getCharCode(e) == KEYS.ENTER) {
			YAHOO.util.Event.preventDefault(e);
			this.submit();
		}
	},

	/**
	 * Default Keyboard event handler to capture up/down/pgup/pgdown
	 * on the Navigator's year control (yearEl).
	 * 
	 * @method _handleDirectionKeys
	 * @protected
	 * @param {Event} e The DOM event being handled
	 */
	_handleDirectionKeys : function(e) {
		var E = YAHOO.util.Event;
		var KEYS = YAHOO.util.KeyListener.KEY;
		var NAV = YAHOO.widget.CalendarNavigator;

		var value = (this.yearEl.value) ? parseInt(this.yearEl.value, 10) : null;
		if (isFinite(value)) {
			var dir = false;
			switch(E.getCharCode(e)) {
				case KEYS.UP:
					this.yearEl.value = value + NAV.YR_MINOR_INC;
					dir = true;
					break;
				case KEYS.DOWN:
					this.yearEl.value = Math.max(value - NAV.YR_MINOR_INC, 0);
					dir = true;
					break;
				case KEYS.PAGE_UP:
					this.yearEl.value = value + NAV.YR_MAJOR_INC;
					dir = true;
					break;
				case KEYS.PAGE_DOWN:
					this.yearEl.value = Math.max(value - NAV.YR_MAJOR_INC, 0);
					dir = true;
					break;
				default:
					break;
			}
			if (dir) {
				E.preventDefault(e);
				try {
					this.yearEl.select();
				} catch(e) {
					// Ignore
				}
			}
		}
	},

	/**
	 * Default Keyboard event handler to capture Tab 
	 * on the last control (lastCtrl) in the Navigator.
	 * 
	 * @method _handleTabKey
	 * @protected
	 * @param {Event} e The DOM event being handled
	 */
	_handleTabKey : function(e) {
		var E = YAHOO.util.Event;
		var KEYS = YAHOO.util.KeyListener.KEY;

		if (E.getCharCode(e) == KEYS.TAB && !e.shiftKey) {
			try {
				E.preventDefault(e);
				this.firstCtrl.focus();
			} catch (e) {
				// Ignore - mainly for focus edge cases
			}
		}
	},

	/**
	 * Default Keyboard event handler to capture Shift-Tab 
	 * on the first control (firstCtrl) in the Navigator.
	 * 
	 * @method _handleShiftTabKey
	 * @protected
	 * @param {Event} e The DOM event being handled
	 */
	_handleShiftTabKey : function(e) {
		var E = YAHOO.util.Event;
		var KEYS = YAHOO.util.KeyListener.KEY;

		if (e.shiftKey && E.getCharCode(e) == KEYS.TAB) {
			try {
				E.preventDefault(e);
				this.lastCtrl.focus();
			} catch (e) {
				// Ignore - mainly for focus edge cases
			}
		}
	},

	/**
	 * Retrieve Navigator configuration values from 
	 * the parent Calendar/CalendarGroup's config value.
	 * <p>
	 * If it has not been set in the user provided configuration, the method will 
	 * return the default value of the configuration property, as set in _DEFAULT_CFG
	 * </p>
	 * @private
	 * @method __getCfg
	 * @param {String} Case sensitive property name.
	 * @param {Boolean} true, if the property is a string property, false if not.
	 * @return The value of the configuration property
	 */
	__getCfg : function(prop, bIsStr) {
		var DEF_CFG = YAHOO.widget.CalendarNavigator._DEFAULT_CFG;
		var cfg = this.cal.cfg.getProperty("navigator");

		if (bIsStr) {
			return (cfg !== true && cfg.strings && cfg.strings[prop]) ? cfg.strings[prop] : DEF_CFG.strings[prop];
		} else {
			return (cfg !== true && cfg[prop]) ? cfg[prop] : DEF_CFG[prop];
		}
	},

	/**
	 * Private flag, to identify MacOS
	 * @private
	 * @property __isMac
	 */
	__isMac : (navigator.userAgent.toLowerCase().indexOf("macintosh") != -1)

};

YAHOO.register("calendar", YAHOO.widget.Calendar, {version: "2.5.1", build: "984"});



/***
@title:
Center

@version:
2.0

@author:
Andreas Lagerkvist

@date:
2008-09-17

@url:
http://andreaslagerkvist.com/jquery/center/

@license:
http://creativecommons.org/licenses/by/3.0/

@copyright:
2008 Andreas Lagerkvist (andreaslagerkvist.com)

@requires:
jquery

@does:
This little pluggy centers an element on the screen using either fixed or absolute positioning. Can be used to display messages, pop up images etc.

@howto:
jQuery('#my-element').center(true); would center the element with ID 'my-element' using absolute position (leave empty for fixed).

@exampleHTML:
<p>I should be fixed centered</p>

<p>The paragraph above and the paragraph beneath this one are centered. They should be in the middle of the viewport.</p>

<p>I should be absolutely centered</p>

@exampleJS:
jQuery('#jquery-center-example p:first-child').center();
jQuery('#jquery-center-example p:last-child').center(true);
***/
jQuery.fn.center = function (absolute) {
	return this.each(function () {
		var t = jQuery(this);
		t.css({
			position:	absolute ? 'absolute' : 'fixed', 
			left:		'50%', 
			top:		'50%', 
			zIndex:		'99'
		}).css({
			marginLeft:	'-' + (t.outerWidth() / 2) + 'px', 
			marginTop:	'-' + (t.outerHeight() / 2) + 'px'
		});

		if (absolute) {
			t.css({
				marginTop:	parseInt(t.css('marginTop'), 10) + jQuery(window).scrollTop(), 
				marginLeft:	parseInt(t.css('marginLeft'), 10) + jQuery(window).scrollLeft()
			});
		}
	});
};



YAHOO.namespace("webtitan.calendrier");
YAHOO.webtitan.calendrier.maxYear=0;
YAHOO.webtitan.calendrier.maxMonth=0;
YAHOO.webtitan.calendrier.minYear=0;
YAHOO.webtitan.calendrier.minMonth=0;
YAHOO.webtitan.calendrier.filtre_cato=null;
YAHOO.webtitan.calendrier.filtre_categorie=null;

YAHOO.webtitan.calendrier.setPrevNextBtnState= function(prev, next){
var calendrier= $w(YAHOO.webtitan.calendrier.instance.id );
var div= calendrier.getElementsByTagName("div")[0];
var aprev= div.getElementsByTagName("a")[0];
var anext= div.getElementsByTagName("a")[1];
if(prev){} else{
div.removeChild(aprev);}
if(next){} else{
div.removeChild(anext);}}
YAHOO.webtitan.calendrier.updatePrevNextBtnState= function(){
if(YAHOO.webtitan.calendrier.maxYear>0){
var date= YAHOO.webtitan.calendrier.getCurPage();
var month= date[1];
var year= date[0];
var prev=(!((year==YAHOO.webtitan.calendrier.minYear)&&(month==YAHOO.webtitan.calendrier.minMonth)));
var next=(!((year==YAHOO.webtitan.calendrier.maxYear)&&(month==YAHOO.webtitan.calendrier.maxMonth)));
YAHOO.webtitan.calendrier.setPrevNextBtnState(prev, next);}}
var changePageHandler= function(type, args, obj){
if(YAHOO.webtitan.calendrier.maxYear>0){
var date= YAHOO.webtitan.calendrier.getCurPage();
var month= date[1];
var year= date[0];
if((year==YAHOO.webtitan.calendrier.maxYear)&&(month>YAHOO.webtitan.calendrier.maxMonth)){
YAHOO.webtitan.calendrier.instance.previousMonth();
return;} else if((year==YAHOO.webtitan.calendrier.minYear)&&(month<YAHOO.webtitan.calendrier.minMonth)){
YAHOO.webtitan.calendrier.instance.nextMonth();
return;} else if(year<YAHOO.webtitan.calendrier.minYear){
YAHOO.webtitan.calendrier.instance.nextMonth();
return;} else if(year>YAHOO.webtitan.calendrier.maxYear){
YAHOO.webtitan.calendrier.instance.previousMonth();
return;}
YAHOO.webtitan.calendrier.updatePrevNextBtnState();}
YAHOO.webtitan.calendrier.validerQueAJour();}
function echecAction(){}

function calendrierEvenementRender(workingDate, cell){
var annee= YAHOO.webtitan.calendrier.pageData[workingDate.getFullYear()];
if(annee){
var mois= annee[workingDate.getMonth()+1];
if(mois){
if((mois[workingDate.getDate()-1])&&(mois[workingDate.getDate()-1]==1)){
YAHOO.util.Dom.addClass(cell,"cal_event" );} else{
YAHOO.util.Dom.addClass(cell,"cal_no_event" );}}}}
YAHOO.webtitan.calendrier.pageData= new Array();

YAHOO.webtitan.calendrier.getCurPage= function(){
var date= YAHOO.webtitan.calendrier.instance.cellDates[7];
return date;}

function calendrierMonthReceived(o){
if(o.responseXML){
YAHOO.webtitan.calendrier.working=false;
var xml= o.responseXML.documentElement;
var year= xml.getAttribute("year");
var month= xml.getAttribute("month");
var jours= new Array();
for(var i=0; i< xml.childNodes.length; i++){
var jour= xml.childNodes[i];
jours[i]= jour.getAttribute("hasEvent");}
YAHOO.webtitan.calendrier.pageData[year][month]= jours;
YAHOO.webtitan.calendrier.instance.render();
YAHOO.webtitan.calendrier.updatePrevNextBtnState();
YAHOO.webtitan.calendrier.validerQueAJour();} else{
alert(o.responseText);
YAHOO.webtitan.calendrier.working=false;}}

YAHOO.webtitan.calendrier.getChargerMoisData= function(year, month){
alert(_TR("mot.adm_js_calendrier_erreur_implantation" ,"Vous devez implémenter une version spécifique au site de chargerMois..."));
return"";}

YAHOO.webtitan.calendrier.chargerMois= function(year, month){
if(YAHOO.webtitan.calendrier.working){} else{
YAHOO.webtitan.calendrier.working= true;
var sUrl= YAHOO.webtitan.calendrier.chargerMoisUrl;
var callback={
success: calendrierMonthReceived,
failure: echecAction,
argument:[]};
var postData= this.getChargerMoisData(year, month);
YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData);}}

YAHOO.webtitan.calendrier.validerQueAJour= function(){
if(YAHOO.webtitan.calendrier.working){} else{
var date= YAHOO.webtitan.calendrier.getCurPage();
var month= date[1];
var year= date[0];
if(YAHOO.webtitan.calendrier.pageData[year]){} else{
YAHOO.webtitan.calendrier.pageData[year]= new Array();}
if((YAHOO.webtitan.calendrier.pageData[year][month])&&(YAHOO.webtitan.calendrier.pageData[year][month]!=null)){} else{
YAHOO.webtitan.calendrier.chargerMois(year, month);}}}

YAHOO.webtitan.calendrier.updateMonth= function(jour){
var year= jour.getFullYear();
var month= jour.getMonth()+1;
if(YAHOO.webtitan.calendrier.pageData[year]){
YAHOO.webtitan.calendrier.pageData[year][month]=null;}
this.validerQueAJour();}

YAHOO.webtitan.calendrier.updateAllMonth= function(){
YAHOO.webtitan.calendrier.pageData= new Array();
this.validerQueAJour();}

if(Langue.getId()== 1){
YAHOO.webtitan.calendrier.localize= function(cal1){
cal1.cfg.setProperty("DATE_FIELD_DELIMITER","-" );
cal1.cfg.setProperty("MDY_DAY_POSITION", 3);
cal1.cfg.setProperty("MDY_MONTH_POSITION", 2);
cal1.cfg.setProperty("MDY_YEAR_POSITION", 1);
cal1.cfg.setProperty("MD_DAY_POSITION", 2);
cal1.cfg.setProperty("MD_MONTH_POSITION", 1);
cal1.cfg.setProperty("MY_DAY_POSITION", 2);
cal1.cfg.setProperty("MY_MONTH_POSITION", 1);
cal1.cfg.setProperty("MONTHS_SHORT",["Ja","Fe" ,"Mr" ,"Al" ,"Ma" ,"Jn" ,"Jl" ,"Au" ,"Se" ,"Oc" ,"No" ,"De"]);
cal1.cfg.setProperty("MONTHS_LONG",["Janvier","Février" ,"Mars" ,"Avril" ,"Mai" ,"Juin" ,"Juillet" ,"Août" ,"Septembre" ,"Octobre" ,"Novembre" ,"Décembre"]);
cal1.cfg.setProperty("WEEKDAYS_1CHAR",["Di","Lu" ,"Ma" ,"Me" ,"Je" ,"Ve" ,"Sa"]);
cal1.cfg.setProperty("WEEKDAYS_SHORT",["Di","Lu" ,"Ma" ,"Me" ,"Je" ,"Ve" ,"Sa"]);
cal1.cfg.setProperty("WEEKDAYS_MEDIUM",["Dim","Lun" ,"Mar" ,"Mer" ,"Jeu" ,"Ven" ,"Sam"]);
cal1.cfg.setProperty("WEEKDAYS_LONG",["Dimanche","Lundi" ,"Mardi" ,"Mercredi" ,"Jeudi" ,"Vendredi" ,"Samedi"]);}}
if(Langue.getId()== 2){
YAHOO.webtitan.calendrier.localize= function(cal1){
cal1.cfg.setProperty("DATE_FIELD_DELIMITER","-" );
cal1.cfg.setProperty("MDY_DAY_POSITION", 3);
cal1.cfg.setProperty("MDY_MONTH_POSITION", 2);
cal1.cfg.setProperty("MDY_YEAR_POSITION", 1);
cal1.cfg.setProperty("MD_DAY_POSITION", 2);
cal1.cfg.setProperty("MD_MONTH_POSITION", 1);
cal1.cfg.setProperty("MY_DAY_POSITION", 2);
cal1.cfg.setProperty("MY_MONTH_POSITION", 1);
cal1.cfg.setProperty("MONTHS_SHORT",["Ja","Fe" ,"Mr" ,"Al" ,"Ma" ,"Jn" ,"Jl" ,"Au" ,"Se" ,"Oc" ,"No" ,"De"]);
cal1.cfg.setProperty("MONTHS_LONG",["January","February" ,"March" ,"April" ,"May" ,"June" ,"July" ,"August" ,"September" ,"October" ,"November" ,"December"]);
cal1.cfg.setProperty("WEEKDAYS_1CHAR",["Su","Mo" ,"Tu" ,"We" ,"Th" ,"Fr" ,"Sa"]);
cal1.cfg.setProperty("WEEKDAYS_SHORT",["Su","Mo" ,"Tu" ,"We" ,"Th" ,"Fr" ,"Sa"]);
cal1.cfg.setProperty("WEEKDAYS_MEDIUM",["Sun","Mon" ,"Tue" ,"Wed" ,"Thu" ,"Fri" ,"Sat"]);
cal1.cfg.setProperty("WEEKDAYS_LONG",["Sunday","Monday" ,"Tuesday" ,"Wednesday" ,"Thursday" ,"Friday" ,"Saturday"]);}}

YAHOO.webtitan.calendrier.commonInit= function(){
YAHOO.webtitan.calendrier.localize(YAHOO.webtitan.calendrier.instance);
YAHOO.webtitan.calendrier.instance.changePageEvent.subscribe(changePageHandler, YAHOO.webtitan.calendrier.instance, true);
for(var i=1; i<= 12; i++){
YAHOO.webtitan.calendrier.instance.addMonthRenderer(i, calendrierEvenementRender);}}



YAHOO.namespace("webtitan.calendrier");
YAHOO.webtitan.calendrier.CalendrierInput= function(tableId, callContainerId, inputId, onChange){
this.deltaX= 0;
this.deltaY= 20;
this.call= null;
this.over_cal= false;
this.inputId= inputId;
this.callContainerId= callContainerId;
this.tableId= tableId;
this.onChange= onChange;
YAHOO.webtitan.calendrier.calendrierInput= this;
this.init();}
YAHOO.webtitan.calendrier.CalendrierInput.prototype.init= function(){
this.cal1= new YAHOO.widget.Calendar(this.tableId,this.callContainerId);
YAHOO.webtitan.calendrier.localize(this.cal1);
this.cal1.selectEvent.subscribe(this.readDate, this, true);
this.cal1.renderEvent.subscribe(this.setupListeners, this, true);
YAHOO.util.Event.addListener(this.inputId,'focus' , this.showCal, this, true);
YAHOO.util.Event.addListener(this.inputId,'blur' , this.hideCal, this, true);
this.cal1.render();
this.hideCal();}
YAHOO.webtitan.calendrier.CalendrierInput.prototype.setupListeners= function(){
var ci= this;
YAHOO.util.Event.addListener(ci.callContainerId,'mouseover' , ci.overCal, this, true);
YAHOO.util.Event.addListener(ci.callContainerId,'mouseout' , ci.outCal, this, true);}
YAHOO.webtitan.calendrier.CalendrierInput.prototype.readDate= function(){
var ci= this;
var calDate= ci.cal1.getSelectedDates()[0];
var m= calDate.getMonth()+1;
var d= calDate.getDate();
m= m.toString();
d= d.toString();
if(m.length==1){
m="0"+m;}
if(d.length==1){
d="0"+d;}
calDate= calDate.getFullYear()+"-"+ m+"-"+ d;
YAHOO.util.Dom.get(ci.inputId).value= calDate;
ci.over_cal= false;
ci.hideCal();
if(ci.onChange){
ci.onChange();}}

YAHOO.webtitan.calendrier.parseDate= function(str){
var s1= str.indexOf("-");
if(s1>0){
var s2= str.indexOf("-", s1+1);
if(s2>s1){
var y= str.substr(0, s1);
var m= str.substr(s1+1, s2-s1-1);
var d= str.substr(s2+1);

var jour= new Date(y, m-1, d);
if((jour!=null)&&(! isNaN(jour.getDate()) ) ){
return jour;}}}
return null;}
YAHOO.webtitan.calendrier.CalendrierInput.prototype.showCal= function(){
var ci= this;
var xy= YAHOO.util.Dom.getXY(ci.inputId);
var dateStr= YAHOO.util.Dom.get(ci.inputId).value;
var date= YAHOO.webtitan.calendrier.parseDate(dateStr);
if(date!=null){
ci.cal1.setYear( date.getFullYear());
ci.cal1.setMonth( date.getMonth() );
ci.cal1.select(date);
ci.cal1.render();}
YAHOO.util.Dom.setStyle(ci.callContainerId,'display' ,'block' );
xy[0]+= ci.deltaX;
xy[1]+= ci.deltaY;
YAHOO.util.Dom.setXY(ci.callContainerId, xy);}
YAHOO.webtitan.calendrier.CalendrierInput.prototype.hideCal= function(){
var ci= this;
if(!ci.over_cal){
YAHOO.util.Dom.setStyle(ci.callContainerId,'display' ,'none' );} else{
setTimeout(function(){
YAHOO.util.Dom.setStyle(ci.callContainerId,'display' ,'none' );}, 1000)}}
YAHOO.webtitan.calendrier.CalendrierInput.prototype.overCal= function(){
var ci= this;
ci.over_cal= true;}
YAHOO.webtitan.calendrier.CalendrierInput.prototype.outCal= function(){
var ci= this;
ci.over_cal= false;}


var etapesWorkings= false;
var formCom1, formCom2, formCom3, formCom3a, formCom3b, formCom4, formCom5;
var etapesCompletes=[false, false, false, false, false, false, false], etapeCourante;
var adrGoogleMats=[], pays=[];
var ETA_ACCUEIL= 0,
ETA_QUOI= 1,
ETA_OU= 2, ETA_OU_2= 3,
ETA_QUAND= 4,
ETA_COMBIEN= 5,
ETA_CONTACT= 6,
ETA_ENVOIE= 7,
ETA_REUSSI= 8
function initFormulaires(){
var cf_data=[["nom-evenement", _TR("bab.nom_evenement_message" ,"Inscrivez le nom officiel de l’événement."), true],["image", _TR("bab.image_message" ,"Joignez une image représentative de l’événement."), false],["internet", _TR("bab.intranet_message","Entrez l’adresse Internet de l’événement, s’il y a lieu."), false],["genre", _TR("bab.intranet_genre" ,"Sélectionnez un genre correspondant à l’événement soumis."), true],["resume-evenement", _TR("bab.resume_evenement_message" ,"Fournissez une brève description de l’événement."), true]];
formCom1= new FormulaireHelper(cf_data,"ajouter_evenement" , null, null);
var cf_data=[["pays",_TR("bab.pays_message" ,"Veuillez sélectionner un pays."), true],["zone",_TR("bab.zone_message" ,"Veuillez sélectionner une zone."), false],["ville",_TR("bab.ville_message" ,"Entrez le nom de la ville qui accueillera l’événement."), true],["adresse",_TR("bab.adresse_message_1" ,"Écrivez l’adresse ou indiquez l’endroit où se déroulera l’événement."), true, _TR("bab.adresse_message_2","Écrivez l’adresse ou indiquez l’endroit où se déroulera l’événement.")]];
formCom2= new FormulaireHelper(cf_data,"ajouter_evenement" , null, null);
var cf_data=[["occev1","" , false, _TR("bab.occev1" ,"Sélectionnez l\'occurrence de l\'événement")],["dateUnique", _TR("bab.dateUnique_message_1" ,"Sélectionnez la date de l’événement à l’aide du petit calendrier."), false, _TR("cal.dateUnique.message_2" ,"Sélectionnez la fréquence de l'évènement.")],["heure-de", _TR("bab.heure_de_message_1" ,"Saisissez une heure valide pour le début de l\'événement (ex : 9:00)."), false, _TR("cal.heure_de_message_2" ,"De préférence, spécifiez une heure sous le format 24 heures. Ex.: de 11h00 à 18h00")],["heure-a", _TR("bab.heure_a_message" ,"Saisissez une heure valide pour la fin de l\'événement (ex : 13:00)."), false]];
formCom3a= new FormulaireHelper(cf_data,"ajouter_evenement" , null, null);
var cf_data=[["date-du", _TR("bab.date_du_message" ,"Sélectionnez les dates de l’événement à l’aide du petit calendrier. Vous pouvez indiquer plusieurs dates séparées ou un intervalle de temps continu."), false],["date-au","" , false],["lun-de","" , false],["lun-a","" , false],["mar-de","" , false],["mar-a","" , false],["mer-de","" , false],["mer-a","" , false],["jeu-de","" , false],["jeu-a","" , false],["ven-de","" , false],["ven-a","" , false],["sam-de","" , false],["sam-a","" , false],["dim-de","" , false],["dim-a","" , false],["tous-les-jours","" , false]];
formCom3b= new FormulaireHelper(cf_data,"ajouter_evenement" , null, null);
var cf_data=[["typecout1","" , false, _TR("bab.typecout1_message" ,"Indiquez si l’événement est gratuit. Sinon, sélectionnez « Autre ».")],["personnes-agees","" , false, _TR("bab.personnes_agess_message" ,"Inscrivez le prix d’entrée pour une personne âgée.")],["adultes","" , false, _TR("bab.adultes_message" ,"Inscrivez le prix d’entrée pour un adulte.")],["etudiants","" , false, _TR("bab.etudiants_message" ,"Inscrivez le prix d’entrée pour un étudiant.")],["enfant-ans","" , false, _TR("bab.enfants_ans_message" ,"Inscrivez le prix d’entrée pour un enfant et spécifiez quelle est la limite d’âge pour bénéficier de ce tarif.")],["enfants","" , false]];
formCom4= new FormulaireHelper(cf_data,"ajouter_evenement" , null, null);
var cf_data=[["nom", _TR("bab.nom_message" ,"Inscrivez le nom de la personne ou de l\'organisme responsable de l’événement."), true],["telephone", _TR("bab.telephone_message" ,"Inscrivez le numéro de téléphone de la personne ou l\'organisme à joindre pour plus d\'information."), false],["courriel", _TR("bab.courriel_message" ,"Indiquez l’adresse courriel de la personne responsable de l’événement."), true],["rendre_visible", _TR("bab.rendre_visible_message" ,"Cochez cette case pour que vos informations (courriel et numéro de téléphone) soient affichées sur le babillard."), false]];
formCom6= new FormulaireHelper(cf_data,"ajouter_evenement" , null, null);
$w("occev1").checked== true;
choixOccurenceUnique();
$w("typecout1").checked= true;
rendreGratuit(true);}
setInterval(function(){
if(!$j.browser.msie || $j.browser.version>= 7){
if(!etapesWorkings && etapeCourante){
var $ac= $j("#anim-cache");
var $cur= $j("#etape"+ etapeCourante);
var h= $ac.height();
var c;
c= $cur.height()+ 30;
if(h != c){
etapesWorkings= true;
$ac.animate({height: c}, 200,"swing" , function(){
etapesWorkings= false;});}}} else{
$j("#divsuivantprecedent").hide().show();}}, 300);
function initSoumissionCalendrier(){
initFormulaires();
etapesCompletes=[false, false, false, false, false, false, false];
switchToEtape(0);}
function switchToEtape(numEtape){
if(!etapesWorkings){
etapesWorkings= true;
$j("#b-soumettre-autre-evenement, #btn_prec, #btn_suiv, #b-soumettre").hide();
function afterAnim(){
etapesWorkings= false;
etapeCourante= numEtape;
for(var i=0; i<9; i++){
var divname="etape"+ i;
if(i != etapeCourante){
toggleVisibilite(divname, false);} else{
toggleVisibilite(divname, true);}}
updateFleches();}
if(typeof etapeCourante !="undefined" &&(!$j.browser.msie || $j.browser.version>= 7) ){
var dir=(numEtape> etapeCourante) ? 1 :-1;
var $cur= $j("#etape"+ etapeCourante);
var $next= $j("#etape"+ numEtape);
var bmarg= $next.css("margin-left");
var cmarg= $cur.css("margin-left");
var $ac= $j("#anim-cache");
$cur.animate({"margin-left":-dir * 300}, 400,"swing" , function(){
$cur.css("margin-left", cmarg);});
$next.show().css({position:"absolute" ,"margin-left" : dir * 300}).animate({"margin-left": bmarg}, 400,"swing" , function(){
$next.css({position:"static" , top: 0, left: 0});
afterAnim();});
var p= $cur.position();$next.css({top: p.top, left: p.left});
$ac.css("height", $ac.height());
$ac.animate({height: $next.height()+ 30}, 400,"swing" );} else{
afterAnim();}
if(numEtape== ETA_OU_2){
checkAddrGoogle();} else if(numEtape== ETA_QUAND){
initEtape4();} else if(numEtape== ETA_COMBIEN){
updateStringOccurences();}
bfTracker._trackPageview("http://www.onesttousdesartistes.tv/evenements/form/"+etapeCourante);}}
function lancerFormulaire(){
switchToEtape(ETA_QUOI);}
function envoiTerminer(){
bfTracker._trackPageview("http://www.onesttousdesartistes.tv/form/evenement/confirm/");
switchToEtape(ETA_REUSSI);
window.frames["form_evenement_iframe"].location.replace("javascript:;");}
function naviguerEtapes(inc){
if(inc> 0){
switch(etapeCourante){
case ETA_ACCUEIL:
case ETA_ENVOIE:
case ETA_REUSSI:
return false;
break;
case ETA_CONTACT:
var success= validerEtapeFormulaire();
if(success){
switchToEtape(etapeCourante+ inc);
$w("ajouter_evenement").submit();}
break;
default:
var success= validerEtapeFormulaire();
if(success){
switchToEtape(etapeCourante+ inc);}
break;}} else{
switch(etapeCourante){
case ETA_ACCUEIL:
case ETA_QUOI:
case ETA_ENVOIE:
case ETA_REUSSI:
return false;
break;
default:
var success= true;
if(success){
switchToEtape(etapeCourante+ inc);}
break;}}}
function validerEtapeFormulaire(){
$j.clearMessages();
var resultatValidationPrimaire= true;
if(eval("formCom"+etapeCourante)) resultatValidationPrimaire= eval("formCom"+etapeCourante).vCham();
if(resultatValidationPrimaire){
switch(etapeCourante){
case ETA_QUOI:
var addr= $w("internet").value;
if(addr !="" ){
var debutValide=(addr.indexOf("http://") !=-1 || addr.indexOf("www.") !=-1);
var finValide=(addr.indexOf(".net") !=-1 || addr.indexOf(".com") !=-1 || addr.indexOf(".ca") !=-1 || addr.indexOf(".fr") !=-1 || addr.indexOf(".us") !=-1 || addr.indexOf(".org") !=-1);;
if(debutValide && finValide){
if(addr.indexOf("http://")==-1) $w("internet").value="http://"+ addr;
etapesCompletes[1]= true;
return true;} else{
$j("#internet").message(_TR("bab.erreur_adresse_internet" ,"L\'adresse Internet que vous avez inscrite ne semble pas valide."));
$w("internet").focus();
return false;}} else{
var i_image= $w("image");
var image= i_image.file;
if(image){
var pti= image.lastIndexOf(".");
var ext= image.substr(pti).toLowerCase();
if(ext !=".jpg" ){
$j("#image").focus().message(_TR("all.img_pas_jpeg","Vous devez envoyer une image au format JPEG. Convertissez votre image à l\'aide d\'un logiciel approprié." ));
return false;}}
etapesCompletes[1]= true;
return true;}
break;
case ETA_OU:
etapesCompletes[2]= true;
return true;
break;
case ETA_OU_2:
var a= adrGoogleMats[selectionGoogleCourante];
try{
var c= a.AddressDetails.Country;
var sp= $w("pays");
for(var k= 0; k< sp.options.length; k++){
var o= sp.options[k];
if(o.iso== c.CountryNameCode){
sp.selectedIndex= k;}}
if(c.AdministrativeArea){
if(c.AdministrativeArea.AdministrativeAreaName){
var zn= c.AdministrativeArea.AdministrativeAreaName;
var sp= $w("zone");
for(var k= 0; k< sp.options.length; k++){
var o= sp.options[k];
if(o.nom== zn || o.code== zn){
sp.selectedIndex= k;}}}
if(c.AdministrativeArea.SubAdministrativeArea && c.AdministrativeArea.SubAdministrativeArea.Locality){
var l= c.AdministrativeArea.SubAdministrativeArea.Locality;
$w("ville").value= l.LocalityName;
$w("adresse").value= l.Thoroughfare.ThoroughfareName;}}} catch(e){}
etapesCompletes[3]= true;
return true;
case ETA_QUAND:
if($w("occev1").checked== false && $w("occev2").checked== false){
$j("#dateUnique").message(_TR("bab.erreur_frequence_evenement" ,"Sélectionnez les dates de l’événement à l’aide du petit calendrier. S’il se déroule pendant plusieurs jours, sélectionnez les dates de début et de fin pour indiquer l’intervalle."));} else{
if($w("occev1").checked== true){
if($w("dateUnique").value=="" ){
$j("#dateUnique").message(_TR("bab.erreur_selection_date_evenement" ,"Sélectionnez la date de l’événement à l’aide du petit calendrier."));
$w("dateUnique").focus();
return false;}
if(getRealDate($w("dateUnique").value).getTime()< new Date().getTime()- 1000 * 60 * 60 * 24){
$w("dateUnique").focus();
$j("#dateUnique").message(_TR("bab.erreur_passe" ,"Vous ne pouvez pas inscrire un événement qui est terminé. Inscrivez au minimum une date qui n\'est pas passée."));
return false;}
etapesCompletes[ETA_QUAND]= true;
return true;} else{
if(arrayOccurenceMultiple.length> 1 ||($w("date-du").value !="" && $w("date-au").value !="" )){
if(checkSerieConflits()){
etapesCompletes[ETA_QUAND]= true;
return true;}} else{
var $i= $j("#date-au");
if($w("date-du").value=="" ){
$i= $j("#date-du");}
$i.focus();
$i.message(_TR("bab.erreur_serie_dates","Vous devez entrer au moins une série de dates."));}}}
break;
case ETA_COMBIEN:
if($w("typecout1").checked== true){
etapesCompletes[ETA_COMBIEN]= true;
return true;} else{
if($w("enfant-ans").value !="" ){
if(parseInt($w("enfant-ans").value, 10)> 0){} else{
$j("#enfant-ans").message(_TR("bab.erreur_enfant-ans_pas_chif" ,"Vous devez inscrire un chiffre dans la la case age des enfants."));
return false;}}
var tousChampsVide=($w("personnes-agees").value=="" && $w("adultes").value=="" && $w("etudiants").value=="" && $w("enfants").value=="" );
var enfantMalRempli=(($w("enfant-ans").value=="" && $w("enfants").value !="" ) ||($w("enfant-ans").value !="" && $w("enfants").value=="" ));
if(!tousChampsVide && !enfantMalRempli){
etapesCompletes[ETA_COMBIEN]= true;
return true;} else{
if(tousChampsVide){
$j("#btn_suiv").message(_TR("bab.erreur_selection_cout_evenement" ,"Indiquez si l’événement est gratuit. Sinon, sélectionnez « Autre »."));
return false;} else if(enfantMalRempli){
if($w("enfant-ans").value=="" ){
$j("#enfant-ans").message(_TR("bab.erreur_age_maximal_enfant" ,"Inscrivez l\'âge maximum pour bénéficier du tarif pour enfant."));
$w("enfant-ans").focus();
return false;} else{
$j("#enfants").message(_TR("bab.erreur_cout_enfant" ,"Vous devez déterminer quel est le prix d\'entrée pour un enfant."));
$w("enfants").focus();
return false;}}}}
break;
case ETA_CONTACT:
etapesCompletes[ETA_CONTACT]= true;
return true;
break;}} else{
etapesCompletes[etapeCourante]= false;
return false;}}
function updateFleches(){
switch(etapeCourante){
case ETA_ACCUEIL:
case ETA_ENVOIE:
case ETA_REUSSI:
changeClass("btn_prec","prec disabled" );
changeClass("btn_suiv","suiv disabled" );
$j("#btn_suiv").text(_TR("all.suivant" ,"Suivant"));
break;
case ETA_QUOI:
changeClass("btn_prec","prec disabled" );
changeClass("btn_suiv","suiv" );
$j("#btn_suiv").text(_TR("all.suivant" ,"Suivant"));
break;
case ETA_CONTACT:
changeClass("btn_prec","prec" );
changeClass("btn_suiv","suiv_soumettre" );
$j("#btn_suiv").text(_TR("con.soummettre" ,"Soumettre"));
break;
default:
changeClass("btn_prec","prec" );
changeClass("btn_suiv","suiv" );
$j("#btn_suiv").text(_TR("all.suivant" ,"Suivant"));
break;}
if(etapeCourante== ETA_ACCUEIL){
$j("#b-soumettre-autre-evenement, #btn_prec, #btn_suiv").hide();
$j("#b-soumettre").show();} else if(etapeCourante== ETA_REUSSI){
$j("#btn_prec, #btn_suiv, #b-soumettre").hide();
$j("#b-soumettre-autre-evenement").show();} else{
$j("#b-soumettre-autre-evenement, #b-soumettre").hide();
$j("#btn_prec, #btn_suiv").show();}}
function toggleVisibilite(nomDiv, makeVisible){
if(document.getElementById){
var displayValue='none';
if(makeVisible== true) displayValue='block';
changeStyle(nomDiv,'display' , displayValue);}}
function nouvelEvenement(){
$w("ajouter_evenement").reset();
arrayOccurenceUniqueSelected= false;
arrayOccurenceMultipleSelected= false;
arrayOccurenceMultiple=[];
currentEditing= 0;
etapesCompletes=[false, false, false, false, false, false];
switchToEtape(1);}
function rendreGratuit(vraiOuFaux){
$j.clearMessages();
toggleVisibilite("details-couts", !vraiOuFaux);}
function changeStyle(nomDiv, propriete, valeur){
document.getElementById(nomDiv).style[propriete]= valeur;}
function changeClass(elementId, nouvelleClasse){
document.getElementById(elementId).className= nouvelleClasse;}
function erreurPHPside(erreurEncodee, etapeErreur){
switchToEtape(etapeErreur);
$j("#ajouter_evenement").message(decodeURIComponent(erreurEncodee));}
var map= null;

function checkAddrGoogle(){
if(!$j.browser.msie ||( parseFloat($j.browser.version)>= 7 )){
if(map== null){
map= new GMap2($w("googleMap"));}
var geocoder= new GClientGeocoder();
var adress= $w("adresse").value+", "+ $w("ville").value;
var z= $w("zone");
if(z.selectedIndex> 0){
z= z.options[z.selectedIndex];
adress+=", "+ z.text;}
var z= $w("pays");
if(z.selectedIndex> 0){
z= z.options[z.selectedIndex];
adress+=", "+ z.text;}
var matchs= geocoder.getLocations(adress, googleAddrResult);} else{
noGoogleAddr();}}
var selectionGoogleCourante=-1;
function choisirGAdrr(i){
selectionGoogleCourante= i;
if(i>= 0){
var a= adrGoogleMats[i];
var cords= a.Point.coordinates;
$w("googlemap").value=""+ cords[0]+", "+ cords[1]+", "+ cords[2];
var pt= new GLatLng(cords[1], cords[0]);
map.clearOverlays();
map.setCenter(pt, 13);
var m= new GMarker(pt);
map.addOverlay(m);
map.setUIToDefault();} else{
map.setCenter(new GLatLng(0, 0), 0);
$w("googlemap").value="";}
var p= $j("#googleMatch p");
p.removeClass("selected");
$j(p[i+1]).addClass("selected");}
function googleAddrResult(response){
var html;
var sel=-1;
var i= 0;
adrGoogleMats=[];
if(!response || response.Status.code != 200 || response.Placemark.length== 0){
html="<p class='infos'>"+_TR("bab.adresse_introuvable","Nous n\'avons pas trouvé cette adresse." )+"</p>";} else{
adrGoogleMats= response.Placemark;
html='<p class="infos" id="grChoix'+i+'">'+_TR("bab.x_results","{0} résultats" , response.Placemark.length)+"</p>";
for(var i= 0; i< response.Placemark.length; i++){
var p= response.Placemark[i];
html+='<p class="adresse"><a href="javascript: choisirGAdrr('+i+')">'+p.address+'</a></p>';}
if(response.Placemark.length> 0){
sel= 0;}
i++;}
html+='<p id="grChoix'+i+'"><a href="javascript: choisirGAdrr(-1)">'+_TR("bab.pas_google_map","Ne pas utiliser l\'adresse validée par Google Map." )+'</a></p>';
$w("googleMatch").innerHTML= html;
choisirGAdrr(sel);}
function noGoogleAddr(){
var html;
html="<p class='infos'>"+_TR("bab.adresse_not_implemented","Désolé, la validation de votre adresse par Google n\'est pas disponible sur votre navigateur. Nous vous suggérons de le mettre à jour." )+"</p>";
$w("googleMatch").innerHTML= html;
$j("#googleMap").hide();
$j(".desc").css("visibility","hidden" );}
function safeXMLExtract(node, sub){
var r= node.getElementsByTagName(sub);
if(r.length== 1 && r[0].firstChild){
return r[0].firstChild.nodeValue;}
return"";}
function updateZones(){
fillCbWithDb("pays","zone" , function(){
var zw= $w("zone");
var td= $j(zw).parent().parent();
if(zw.options.length> 1){
td.show();} else{
td.hide();}});}


var arrayOccurenceUniqueSelected;
var arrayOccurenceMultipleSelected;
var timeoutFC2;
var lesMois=[_TR("bab.mois_janvier","janvier"), _TR("bab.mois_fevrier","février"), _TR("bab.mois_mars" ,"mars"), _TR("bab.mois_avril" ,"avril"), _TR("bab.mois_mai" ,"mai"), _TR("bab.mois_juin" ,"juin"), _TR("bab.mois_juillet" ,"juillet"), _TR("bab.mois_août" ,"août"), _TR("bab.mois_septembre" ,"septembre"), _TR("bab.mois_octobre" ,"octobre"), _TR("bab.mois_novembre" ,"novembre"), _TR("bab.mois_decembre" ,"décembre")];
var lesJours=[_TR("bab.jour_dimanche" ,"dimanche"), _TR("bab.jour_lundi" ,"lundi"), _TR("bab.jour_mardi" ,"mardi"), _TR("bab.jour_mercredi" ,"mercredi"), _TR("bab.jour_jeudi" ,"jeudi"), _TR("bab.jour_vendredi" ,"vendredi"), _TR("bab.jour_samedi" ,"samedi")];
var lesJoursChamps=["dimanche","lundi" ,"mardi" ,"mercredi" ,"jeudi" ,"vendredi" ,"samedi"];
var dateUnique_sel= false;
var dateMultipleDe_sel= false;
var dateMultipleA_sel= false;
var arrayOccurenceMultiple=[];
var currentEditing= 0;
function initEtape4(){
if(arrayOccurenceUniqueSelected != true && arrayOccurenceMultipleSelected != true){
$w("occev1").checked= false;
$w("occev2").checked= false;
toggleVisibilite("occurenceunique", false);
toggleVisibilite("occurencemultiple", false);} else if(arrayOccurenceUniqueSelected== true){
$w("occev1").checked= true;
toggleVisibilite("occurenceunique", true);
toggleVisibilite("occurencemultiple", false);} else{
$w("occev2").checked= true;
toggleVisibilite("occurenceunique", false);
toggleVisibilite("occurencemultiple", true);}}
function choixOccurenceUnique(){
arrayOccurenceMultipleSelected= false;
arrayOccurenceUniqueSelected= true;
toggleVisibilite("occurencemultiple", false);
toggleVisibilite("occurenceunique", true);
if(dateUnique_sel== false) dateUnique_sel= new YAHOO.webtitan.calendrier.CalendrierInput("g_calDateUnique","calDateUnique" ,"dateUnique" );}
function choixOccurenceMultiple(){
arrayOccurenceUniqueSelected= false;
arrayOccurenceMultipleSelected= true;
if(dateMultipleDe_sel== false) dateMultipleDe_sel= new YAHOO.webtitan.calendrier.CalendrierInput("g_dateMultipleDe","calDateMultiple-de" ,"date-du" , fc);
if(dateMultipleA_sel== false) dateMultipleA_sel= new YAHOO.webtitan.calendrier.CalendrierInput("g_dateMultipleA","calDateMultiple-a" ,"date-au" , fc);
dateMultipleA_sel.deltaX=-90;
if(arrayOccurenceMultiple.length< 1){
viderChamps();
currentEditing= 0;
arrayOccurenceMultiple[0]= editObjetDate();} else{
currentEditing= arrayOccurenceMultiple.length- 1;}
toggleVisibilite("occurenceunique", false);
toggleVisibilite("occurencemultiple", true);}
function editObjetDate(){
var obO= new Object();
obO.dateDu= $w("date-du").value;
obO.dateAu= $w("date-au").value;
obO.lundi= new Object();
obO.lundi.checked= $w("lundi").checked;
obO.lundi.de= $w("lun-de").value;
obO.lundi.a= $w("lun-a").value;
obO.mardi= new Object();
obO.mardi.checked= $w("mardi").checked;
obO.mardi.de= $w("mar-de").value;
obO.mardi.a= $w("mar-a").value;
obO.mercredi= new Object();
obO.mercredi.checked= $w("mercredi").checked;
obO.mercredi.de= $w("mer-de").value;
obO.mercredi.a= $w("mer-a").value;
obO.jeudi= new Object();
obO.jeudi.checked= $w("jeudi").checked;
obO.jeudi.de= $w("jeu-de").value;
obO.jeudi.a= $w("jeu-a").value;
obO.vendredi= new Object();
obO.vendredi.checked= $w("vendredi").checked;
obO.vendredi.de= $w("ven-de").value;
obO.vendredi.a= $w("ven-a").value;
obO.samedi= new Object();
obO.samedi.checked= $w("samedi").checked;
obO.samedi.de= $w("sam-de").value;
obO.samedi.a= $w("sam-a").value;
obO.dimanche= new Object();
obO.dimanche.checked= $w("dimanche").checked;
obO.dimanche.de= $w("dim-de").value;
obO.dimanche.a= $w("dim-a").value;
obO.tousLesJours= new Object();
obO.tousLesJours.checked= $w("tous-les-jours").checked;
obO.tousLesJours.de= $w("tous-de").value;
obO.tousLesJours.a= $w("tous-a").value;
return obO;}
function chargerContenuDansChamps(){
var objData= arrayOccurenceMultiple[currentEditing];
$w("date-du").value= objData.dateDu;
$w("date-au").value= objData.dateAu;
for(var j=0; j<lesJours.length; j++){
$w(lesJoursChamps[j]).checked= objData[lesJoursChamps[j]].checked;
$w(lesJoursChamps[j].substr(0, 3)+"-de").value= objData[lesJoursChamps[j]].de;
$w(lesJoursChamps[j].substr(0, 3)+"-a").value= objData[lesJoursChamps[j]].a;}
}
function fc(){
clearTimeout(timeoutFC2);
timeoutFC2= setTimeout(fc2, 100);}
function fc2(){
clearTimeout(timeoutFC2);
arrayOccurenceMultiple[currentEditing]= editObjetDate();
return updateVisuelSeries();}

function isConflict(dateDu, dateAu, passe){
for(var i=0; i<arrayOccurenceMultiple.length; i++){
if(i != passe){
var obO= arrayOccurenceMultiple[i];
if(obO.dateDu !="" && obO.dateAu !="" ){
var dateDu2= getRealDate(obO.dateDu);
var dateAu2= getRealDate(obO.dateAu);
if((dateDu2>= dateDu && dateDu2<= dateAu) ||(dateAu2>= dateDu && dateAu2<= dateAu) ||(dateDu2< dateDu && dateAu2> dateAu) ){
return true;}}}}
return false;}
function checkSerieConflits(){
var haveFutur= false;
for(var i=0; i<arrayOccurenceMultiple.length; i++){
var obO= arrayOccurenceMultiple[i];
if(obO.dateDu !="" && obO.dateAu !="" ){
var dateDu= getRealDate(obO.dateDu);
var dateAu= getRealDate(obO.dateAu);
if(dateAu>= new Date()- 1000 * 60 * 60 * 24){
haveFutur= true;}
if(isConflict(dateDu, dateAu, i)){
$w("date-du").focus();
$j("#date-du").message(_TR("bab.erreur_conflit" ,"Les dates entrées entrent en conflit avec d\'autres dates."));
return false;}}}
if(!haveFutur){
$w("date-du").focus();
$j("#date-du").message(_TR("bab.erreur_passe" ,"Vous ne pouvez pas inscrire un événement qui est terminé. Inscrivez au minimum une date qui n\'est pas passée."));
return false;}
return true;}
function updateVisuelSeries(){
$w("seriesDeDates").innerHTML="";
var foundOne= false;
var elementErrone= false;
var newInnerHtml="<ul>";
for(var i=0; i<arrayOccurenceMultiple.length; i++){
var obO= arrayOccurenceMultiple[i];
if(obO.dateDu !="" && obO.dateAu !="" ){
var dateDu= getRealDate(obO.dateDu);
var dateAu= getRealDate(obO.dateAu);
if(dateDu<= dateAu){
foundOne= true;
var lienModifier="";
var classLi="";
var classFermer="";
if(i != currentEditing){
classLi=" class=\"serie-modifiable\"";
classFermer=" class=\"fermer-modifiable\"";
lienModifier="<br />[ <a href=\"#\" onclick=\"modifier("+i+"); return false;\">"+ _TR("all.modifier" ,"Modifier")+"</a> ]";}
var strDateDebut= getStringDate(obO.dateDu);
var strDateAu= getStringDate(obO.dateAu);
if(strDateDebut== strDateAu){
newInnerHtml+="<li"+classLi+">"+ strDateDebut.charAt(0).toUpperCase()+ strDateDebut.substring(1).toLowerCase()+"<a onclick=\"effacer("+i+"); return false;\" class=\"effacer\" href=\"#\">"+ _TR("bab.js_effacer" ,"Effacer")+"</a>"+lienModifier+"</li>";} else{
newInnerHtml+="<li"+classLi+">Du "+getStringDate(obO.dateDu)+" au<br /> "+ getStringDate(obO.dateAu)+"<a onclick=\"effacer("+i+"); return false;\" class=\"effacer\" href=\"#\">"+ _TR("bab.js_effacer" ,"Effacer")+"</a>"+lienModifier+"</li>";}
if(i== currentEditing) enableOrDisableWeekDays(getRealDate(obO.dateDu), getRealDate(obO.dateAu));} else{
$w("date-du").value="";
$j("#date-du").message(_TR("bab.erreur_date_debut_evenement" ,"La date du début de l\'événement doit être antérieure à la date de fin."));
$w("date-du").focus();
elementErrone= true;}} else{
elementErrone= true;}}
if(foundOne== true){
newInnerHtml+="</ul>";
$w("seriesDeDates").innerHTML= newInnerHtml;}
if(elementErrone== true) return false;}
function modifier(num){
if(fc2() != false){
currentEditing= num;
viderChamps();
var autocheck= chargerContenuDansChamps();
fc();} else{
arrayOccurenceMultiple.splice(currentEditing, 1);
currentEditing= num;
viderChamps();
var autocheck= chargerContenuDansChamps();
fc();}}
function effacer(idSerieDate){
arrayOccurenceMultiple.splice(idSerieDate, 1);
if(idSerieDate== currentEditing){
currentEditing= arrayOccurenceMultiple.length;
viderChamps();} else if(currentEditing> idSerieDate){
currentEditing--;} else{}
fc();}
function ajouterSerieDate(){
$j.clearMessages();
if(fc2() != false){
if(checkSerieConflits()){
arrayOccurenceMultiple[currentEditing]= editObjetDate();
viderChamps();
currentEditing= arrayOccurenceMultiple.length;
updateVisuelSeries();
viderChamps();}} else{
$j("#b-ajouter-serie-date").message(_TR("bab.erreur_saisie_date_courante" ,"Il vous faut d\'abord saisir correctement la série de date courante avant d\'en ajouter une autre."));}}
function getRealDate(stringDate){
var arrayD= stringDate.split("-");
var annee= parseInt(arrayD[0], 10);
var mois= parseInt(arrayD[1], 10)-1;
var jour= parseInt(arrayD[2], 10);
var retDate= new Date(annee, mois, jour);
return retDate;}
function getStringDate(stringDate){
var objDate= getRealDate(stringDate);
var retStr="";
retStr+= lesJours[objDate.getDay()]+" "+ objDate.getDate()+" "+ lesMois[objDate.getMonth()]+" "+ objDate.getFullYear();
return retStr;}
function enableOrDisableWeekDays(debut, fin){
var difference=(fin- debut) /(60*60*24*1000);
if(difference<= 6){
var jourDebut= debut.getDay();
var jourFin= fin.getDay();
var dateOperator="&&";
if(jourDebut> jourFin) dateOperator="||";
for(var j=0; j<lesJours.length; j++){
var vDis= true;
if(eval("j >= jourDebut "+ dateOperator+" j <= jourFin" )) vDis= false;
$w(lesJoursChamps[j]).disabled= vDis;
$w(lesJoursChamps[j].substr(0, 3)+"-de").disabled= vDis;
$w(lesJoursChamps[j].substr(0, 3)+"-a").disabled= vDis;
if(vDis== true){
$w(lesJoursChamps[j]).checked= false;
$w(lesJoursChamps[j].substr(0, 3)+"-de").value="";
$w(lesJoursChamps[j].substr(0, 3)+"-a").value="";}}} else{
for(var j=0; j<lesJours.length; j++){
$w(lesJoursChamps[j]).disabled= false;
$w(lesJoursChamps[j].substr(0, 3)+"-de").disabled= false;
$w(lesJoursChamps[j].substr(0, 3)+"-a").disabled= false;}}
var allActivated= true;
var valeurDE="";
var valeurA="";
var premiereValeurTrouvee= false;
for(var j=0; j<lesJours.length; j++){
if($w(lesJoursChamps[j]).disabled== false && $w(lesJoursChamps[j]).checked== false){
allActivated= false;}
if($w(lesJoursChamps[j]).checked== true && $w(lesJoursChamps[j]).disabled== false && premiereValeurTrouvee== false){
premiereValeurTrouvee= true;
valeurDE= $w(lesJoursChamps[j].substr(0, 3)+"-de").value;
valeurA= $w(lesJoursChamps[j].substr(0, 3)+"-a").value;}
if(premiereValeurTrouvee== true && $w(lesJoursChamps[j]).checked== true && $w(lesJoursChamps[j]).disabled== false){
if(valeurDE=="" || valeurA=="" || valeurDE != $w(lesJoursChamps[j].substr(0, 3)+"-de").value || valeurA != $w(lesJoursChamps[j].substr(0, 3)+"-a").value ) allActivated= false;}}
if(allActivated== true){
$w("tous-de").value= valeurDE;
$w("tous-a").value= valeurA;
$w("tous-les-jours").checked= false;
$w("tous-les-jours").click();} else{
$w("tous-les-jours").checked= false;}}
function autoCheckDays(){
for(var j=0; j<lesJours.length; j++){
if($w(lesJoursChamps[j]).disabled== false ||($w(lesJoursChamps[j]).disabled== true && $w(lesJoursChamps[j]).checked== true)){
$w(lesJoursChamps[j]).checked= $w("tous-les-jours").checked;
$w(lesJoursChamps[j]).disabled= $w("tous-les-jours").checked;
$w(lesJoursChamps[j].substr(0, 3)+"-de").disabled= $w("tous-les-jours").checked;
$w(lesJoursChamps[j].substr(0, 3)+"-a").disabled= $w("tous-les-jours").checked;
if($w("tous-les-jours").checked== true){
$w(lesJoursChamps[j].substr(0, 3)+"-de").value= $w("tous-de").value;
$w(lesJoursChamps[j].substr(0, 3)+"-a").value= $w("tous-a").value;}}}
editObjetDate();}
function viderChamps(){
for(var j=0; j<lesJours.length; j++){
$w(lesJoursChamps[j]).checked= false;
$w(lesJoursChamps[j]).disabled= false;
$w(lesJoursChamps[j].substr(0, 3)+"-de").disabled= false;
$w(lesJoursChamps[j].substr(0, 3)+"-a").disabled= false;
$w(lesJoursChamps[j].substr(0, 3)+"-de").value="";
$w(lesJoursChamps[j].substr(0, 3)+"-a").value="";}
$w("tous-les-jours").checked= false;
$w("tous-de").value="";
$w("tous-a").value="";
$w("date-du").value="";
$w("date-au").value="";
dateMultipleDe_sel.cal1.clear();
dateMultipleA_sel.cal1.clear();}
function updateToutesHeures(){
for(var j=0; j<lesJours.length; j++){
if($w(lesJoursChamps[j]).disabled== true && $w(lesJoursChamps[j]).checked== true){
$w(lesJoursChamps[j].substr(0, 3)+"-de").value= $w("tous-de").value;
$w(lesJoursChamps[j].substr(0, 3)+"-a").value= $w("tous-a").value;}}
arrayOccurenceMultiple[currentEditing]= editObjetDate();}
function updateStringOccurences(){
var stringOccurences="";
if($w("occev1").checked== true){
stringOccurences+="date-de="+$w("dateUnique").value+";a="+$w("dateUnique").value;
var heure="";
if($w("heure-de").value !="" || $w("heure-a").value !="" ){
heure=";tljc=1;tljd="+$w("heure-de").value+";tljf="+$w("heure-a").value;}
stringOccurences+= heure;} else{
var nbOccurencesDansString= 0;
var ar= arrayOccurenceMultiple;
for(var i=0; i<ar.length; i++){
if(ar[i].dateDu !="" && ar[i].dateAu !="" ){
if(nbOccurencesDansString> 0) stringOccurences+=",";
stringOccurences+="date-de="+ar[i].dateDu+";a="+ar[i].dateAu;
if(ar[i].tousLesJours.checked== true){
stringOccurences+=";tljc=1";
stringOccurences+=";tljd="+ar[i].tousLesJours.de;
stringOccurences+=";tljf="+ar[i].tousLesJours.a;} else{
for(var j=0; j<lesJours.length; j++){
if(ar[i][lesJoursChamps[j]].checked== true){
stringOccurences+=";j"+(j+1)+"c=1";
stringOccurences+=";j"+(j+1)+"d="+ar[i][lesJoursChamps[j]].de;
stringOccurences+=";j"+(j+1)+"f="+ar[i][lesJoursChamps[j]].a;}}}
nbOccurencesDansString++;}}}
$w("string-occurences").value= stringOccurences;}



var Sync={

paral: function(){
a= arguments;
var len= a.length-1;
var c= len;
var k;
function complete(d){
c--;
if(d){
k= d;}
if(c==0){
a[len](k);}}
for(var i=0; i< len; i++){
a[i](complete);}}}


var calendrierActivites;
var genreCourant= 0;
var paysCourant= 0;
var provinceCourante= 0;
var activiteCourante= 0;
var motRechCourant="";
var noPage= 1;
var itemsParPage= 5;
var babillardXml= null;
var popUpCell= null;
var celFrmHelper= null;
var autoOpen= false;
function updateRecherche(){
noPage= 1;
babillardXml=null;
var params={
plugin:"activite",
action:"recherche",
fullmode:1,
xmlmode:1};
if(activiteCourante> 0){
params.activite= activiteCourante;
activiteCourante=0;} else{
if(genreCourant> 0){
params.genres= genreCourant;}
if(paysCourant> 0){
params.pays= paysCourant;}
if(provinceCourante> 0){
params.province= provinceCourante;}
if(motRechCourant!=""){
params.rech= motRechCourant;}}
var $r= $j("#resultats");
Sync.paral(
function(f){
$r.fadeOut(500, function(){
$r.show().css("visibility","hidden" );
f();});}, function(f){
$j.post("/plugin.php", params, f,"xml" );},
babillardReceived
);}

function getImgItBabillard(it){
var enclosure= it.getElementsByTagName("enclosure");
var imgurl= null;
if(enclosure.length==1){
enclosure=enclosure[0];
imgurl= enclosure.getAttribute("url");
var pm= imgurl.indexOf("/medias/");
if(pm>0){
imgurl= imgurl.substr(pm+8);}} else{
enclosure=null;}
var baliseImage="";
if(imgurl!=null){
baliseImage="<img alt=\"\" src=\""+ _URL_IMAGE(imgurl, 115, 115, 2)+"\" />";} else{
baliseImage="<img alt='' src='/images/default_cal_img.jpg' />";}
return baliseImage;}

function getDetailCtItBabillard(it){
var prix_p_aggee= safeXmlExtract(it,"prix_p_aggee" );
var prix_adulte= safeXmlExtract(it,"prix_adulte" );
var prix_etudiant= safeXmlExtract(it,"prix_etudiant" );
var prix_enfant= safeXmlExtract(it,"prix_enfant" );
var age_enfant= safeXmlExtract(it,"age_enfant" );
infosCouts="";
if(( prix_p_aggee=="" || prix_p_aggee=="0" ) &&( prix_adulte=="" || prix_adulte=="0" ) &&( prix_etudiant=="" || prix_etudiant=="0" ) &&( prix_enfant=="" || prix_enfant=="0" ) ){
infosCouts+= _TR("bab.prix_activite","Cette activité est gratuite pour tous.");} else{
infosCouts+="<div class=\"couts-activite\"><p>";
if(prix_p_aggee !="" ){ infosCouts+= _TR("bab.prix_personne_ages","Personne âgée :")+" "+ prix_p_aggee+"<br />";}
if(prix_adulte !="" ){ infosCouts+= _TR("bab.prix_adultes","Adulte :")+" "+ prix_adulte+"<br />";}
if(prix_etudiant !="" ){ infosCouts+= _TR("bab.prix_etudiant","Étudiant :")+" "+ prix_etudiant+"<br />";}
if(prix_enfant !="" ){ infosCouts+= _TR("bab.prix_enfant","Enfant de moins de {0} ans :", age_enfant)+" "+ prix_enfant+"<br />";}
infosCouts+="</p></div>";}
return infosCouts;}

function babillardReceived(o){
$j("#resultats").css("visibility","visible" ).fadeIn(500);
if(o){
babillardXml= o;
updateHtml();
updateEnteteRech();
bfTracker._trackPageview("http://www.onesttousdesartistes.tv/evenements/filtrer/"+genreCourant+"/"+paysCourant+"/"+provinceCourante+"?ga_search="+ motRechCourant);
if(autoOpen){
autoOpen= false;
$j(".b-details.moins").click();}} else{
$w("resultats").innerHTML="<h3>"+ _TR("bab.erreur_reception_donnees","Le serveur n\'a retourné aucune donnée valide.")+"</h3>";}}

function updateEnteteRech(){
var html="";
if(babillardXml!=null){
var root= babillardXml.documentElement;
var items= root.getElementsByTagName("item");
document.getElementById("recherche_titre_info").className="date-activites";
var z= $w("filtrer-zones");
var o= z.options[z.selectedIndex];
z=o.text;
var g= $w("filtrer-genres");
o= g.options[g.selectedIndex];
g=o.text;
var pays= $w("filtrer-pays");
pays= pays.options[pays.selectedIndex];
pays= pays.text;
if(motRechCourant!=""){
if(genreCourant> 0){
if(provinceCourante> 0){
html+='<h4>'+_TR("his.resulSearch","Résultat")+' : </h4><p class="nb-activites">'+ _TR("bab.nombre_activites_genre_region_rech","{3}{0}{4} événement(s) de type {3}«{1}»{4} dans la région {3}«{2}»{4} correspond(ent) à {3}«{5}»{4}." , items.length, g, z,'<strong>' ,'</strong>' , motRechCourant)+'</p>';} else if(paysCourant> 0){
html+='<h4>'+_TR("his.resulSearch","Résultat")+' : </h4><p class="nb-activites">'+ _TR("bab.nombre_activites_genre_pays_rech","{3}{0}{4} événement(s) de type {3}«{1}»{4} dans le pays {3}«{2}»{4} correspond(ent) à {3}«{5}»{4}." , items.length, g, pays,'<strong>' ,'</strong>' , motRechCourant)+'</p>';} else{
html+='<h4>'+_TR("his.resulSearch","Résultat")+' : </h4><p class="nb-activites">'+ _TR("bab.nombre_activites_genre_rech","{2}{0}{3} événement(s) de type {2}«{1}»{3} correspond(ent) à {2}«{4}»{3}." , items.length, g,'<strong>' ,'</strong>' , motRechCourant)+'</p>';}} else if(provinceCourante> 0){
html+='<h4>'+_TR("his.resulSearch","Résultat")+' : </h4><p class="nb-activites">'+ _TR("bab.nombre_activites_region_rech","{2}{0}{3} événement(s) dans la région {2}«{1}»{3} correspond(ent) à {2}«{4}»{3}." , items.length, z,'<strong>' ,'</strong>' , motRechCourant)+'</p>';} else if(paysCourant> 0){
html+='<h4>'+_TR("his.resulSearch","Résultat")+' : </h4><p class="nb-activites">'+ _TR("bab.nombre_activites_pays_rech","{2}{0}{3} événement(s) dans le pays {2}«{1}»{3} correspond(ent) à {2}«{4}»{3}." , items.length, pays,'<strong>' ,'</strong>' , motRechCourant)+'</p>';} else{
html+='<h4>'+_TR("his.resulSearch","Résultat")+' : </h4><p class="nb-activites">'+ _TR("bab.nombre_activites_rech","{1}{0}{2} événement(s) classé(s) dans {1} tous les types{2} et {1}toutes les régions{2} correspond(ent) à {1}«{3}»{2}." , items.length,'<strong>' ,'</strong>' , motRechCourant)+'</p>';}} else{
if(genreCourant> 0){
if(provinceCourante> 0){
html+='<h4>'+_TR("his.resulSearch","Résultat")+' : </h4><p class="nb-activites">'+ _TR("bab.nombre_activites_genre_region","{3}{0}{4} événement(s) de type {3}«{1}»{4} dans la région {3}«{2}»{4}." , items.length, g, z,'<strong>' ,'</strong>' )+'</p>';} else if(paysCourant> 0){
html+='<h4>'+_TR("his.resulSearch","Résultat")+' : </h4><p class="nb-activites">'+ _TR("bab.nombre_activites_genre_pays","{3}{0}{4} événement(s) de type {3}«{1}»{4} dans le pays {3}«{2}»{4}." , items.length, g, z,'<strong>' ,'</strong>' )+'</p>';} else{
html+='<h4>'+_TR("his.resulSearch","Résultat")+' : </h4><p class="nb-activites">'+ _TR("bab.nombre_activites_genre","{2}{0}{3} événement(s) de type {2}«{1}»{3}." , items.length, g,'<strong>' ,'</strong>' )+'</p>';}} else if(provinceCourante> 0){
html+='<h4>'+_TR("his.resulSearch","Résultat")+' : </h4><p class="nb-activites">'+ _TR("bab.nombre_activites_region","{2}{0}{3} événement(s) dans la région {2}«{1}»{3}." , items.length, z,'<strong>' ,'</strong>' )+'</p>';} else if(paysCourant> 0){
html+='<h4>'+_TR("his.resulSearch","Résultat")+' : </h4><p class="nb-activites">'+ _TR("bab.nombre_activites_pays","{2}{0}{3} événement(s) dans le pays {2}«{1}»{3}." , items.length, pays,'<strong>' ,'</strong>' )+'</p>';} else{
html+='<h4>'+_TR("his.resulSearch","Résultat")+' : </h4><p class="nb-activites">'+ _TR("bab.nombre_activites","{1}{0}{2} événement(s) classé(s) dans {1} tous les types{2} et {1}toutes les régions{2}." , items.length,'<strong>' ,'</strong>' )+'</p>';}}}
$w("recherche_titre_info").innerHTML= html;}

function getCelRapItBabillard(i, zebra){
var html="";
html+='<a id="btnCelRap_'+i+'" class="sms_'+zebra+'" href="javascript: btnCelRap('+i+')" >'+_TR("bab.mavertir","Notification par message texte" )+'</a>';
return html;}

function updateHtml(){
if(babillardXml!=null){
var root= babillardXml.documentElement;
var items= root.getElementsByTagName("item");
var nbResultat= items.length;
var nbPage= Math.ceil( nbResultat / itemsParPage );
if(noPage> nbPage){
noPage= nbPage;}
if(noPage< 1){
noPage= 1;}
var rendu=(noPage-1)*itemsParPage;
var max= rendu+itemsParPage;
if(nbResultat<max){
max=nbResultat;}
html='<div id="accordion">';
var zebra= 1;
for(var i=rendu; i< max; i++){
var it= items[i];
var nom= safeXmlExtract(it,"title" );
var ville= safeXmlExtract(it,"ville" );
var lieu= safeXmlExtract(it,"lieu" );
var dateResume= safeXmlExtract(it,"dateResume" );
var genreId= safeXmlExtract(it,"genre" );
var paysNom= safeXmlExtract(it,"paysNom" );
var zoneNom= safeXmlExtract(it,"zoneNom" );
var genreNom= safeXmlExtract(it,"genreNom" );
var regionNom= safeXmlExtract(it,"regionNom" );
var description= safeXmlExtract(it,"description" );
var horaire= safeXmlExtract(it,"horaire" );
var siteWeb= safeXmlExtract(it,"internet" );
var contact_visible= safeXmlExtract(it,"contact_visible" );
var nom_responsable= safeXmlExtract(it,"nom_responsable" );
var telephone_responsable= safeXmlExtract(it,"telephone_responsable" );
var courriel_responsable= safeXmlExtract(it,"courriel_responsable" );
var futur= safeXmlExtract(it,"futur" );
var gdata= safeXmlExtract(it,"googlemap" );
if(i== rendu){
var positionBab="first";
var sep="";}else if(i== max-1){
var positionBab="last";
var sep="<div class='sepEven'></div>";}else{
var positionBab="";
var sep="<div class='sepEven'></div>";}
html+= sep;
html+="<div class='evenement ev"+ zebra+" "+ positionBab+"'>";
html+="<div class='wrapper'>";
html+="<div class='image-details'>";
html+="<p>"+ getImgItBabillard(it)+"</p>";
html+="</div>";
html+="<div class='infos'>";
html+="<h5>"+ nom+"</h5>";
html+="<p><strong>"+ genreNom+"</strong></p>";
html+="<p><strong>"+ paysNom+" / "+ zoneNom+" / "+ ville+"</strong></p>";
html+="<p>"+ dateResume+"</p>";
html+="<p class='p-details'>[<a id='b-details"+ i+"' class='b-details moins' href='#' onclick='return false;'>"+ _TR("bab.activite_details" ,"Détails")+" + </a>]</p>";
html+="</div>";
html+="<div class='clear'></div>";
html+="<div  id='plus-details"+ i+"' class='plus-details'>";
html+='<div id="dgmap'+i+'" class="g-map">';
if(gdata !="" ){
gdatas= gdata.split(",", 4);
if(gdatas.length== 3){
html+='<a class="btnMap" href="javascript: popupGMap('+i+');">'+_TR("oetda.itinéraire","Voir l'itinéraire")+'</a>';}}
html+='</div>';
html+='<div class="contenu">';
if(horaire != dateResume){
html+="<p><strong>"+_TR("cal.horraire","Horaire" )+"</strong></p><p class='date'>"+ horaire+"</p>";}
html+="<p><strong>"+ lieu+"</strong></p><br />";
html+="<p>"+ description+" </p><br />";
html+="<p><strong>"+ _TR("bab.activite_cout" ,"Coûts")+"</strong></p><p>"+ getDetailCtItBabillard(it)+"</p><br />";
if(contact_visible=="1" ){
if(telephone_responsable !="" || courriel_responsable !="" ){
html+="<p><strong>"+_TR("bab.info_contact","Informations" )+"</strong></p>";
if(courriel_responsable !="" ) html+="<p>"+nom_responsable+"</p>";
if(telephone_responsable !="" ) html+="<p>"+telephone_responsable+"</p>";
if(courriel_responsable !="" ) html+="<p><a href=\"mailto:"+courriel_responsable+"\">"+courriel_responsable+"</a></p>";}}
if(siteWeb !="" ){
html+="<br />";
html+="<p><strong><a class='site_internet"+zebra+"' href='"+ siteWeb+"' target='_blank' title='"+ siteWeb+"'>"+ _TR("bab.voirEvent_site_web" ,"Voir le site Web de l\'événement")+"</a></strong></p>";}
if(futur){
html+= getCelRapItBabillard(i, zebra);}
html+='</div>';
html+='<div class="clear"></div>';
html+="</div>";
html+="</div>";
html+="<div class='bottom'></div>";
html+="</div>";
zebra++;
if(zebra== 3){
zebra= 1;}}
html+='</div>';
var r= document.getElementById("resultats");
r.innerHTML= html;
initSlide(items.length);
updateBtnPrecedentSuivant(noPage, nbPage);} else{
$w("resultats").innerHTML="<h3>"+ _TR("bab.erreur_resultat_serveur" ,"Le serveur n\'a retourné aucune donnée valide.")+"</h3>";}}
function popupGMap(index){
if( $j.browser.msie &&( parseFloat($j.browser.version)< 7 ) ){
$j(".filtre").hide();}
if( typeof( window.innerWidth )=='number' ){
var width= window.innerWidth-200;
var height= window.innerHeight-200;}else if( document.documentElement &&( document.documentElement.clientWidth || document.documentElement.clientHeight ) ){
var width= document.documentElement.clientWidth-200;
var height= document.documentElement.clientHeight-200;}
var html='<div id="envoyer-ami" style="width: '+width+'px; height: '+height+'px; border: 10px #dea850 solid">';
html+='<a class="fermer" >Fermer</a>';
html+='<div style="width: '+width+'px; height: '+height+'px" id="gmappopup'+index+'"></div>';
html+='</div>';
$j('body').append('<div id="overlay"></div>');
$j('#overlay').css({'opacity'
:'0' ,'width'
: $j(document).width()+'px','height'
: $j(document).height()+'px','background-color'
:'#000' ,'position'
:'absolute' ,'top'
:'0' ,'left'
:'0' ,'z-index'
:'2' }).fadeTo(100, 0.75, function(){
var popup= new PopUpHtml(html,0,0,width,height);
$j(".fermer:first").css({
position:"absolute",
left:width-5+"px",
top:"-20px"	});
var data= babillardXml.documentElement.getElementsByTagName("item");
data= data[index];
var gdata= safeXmlExtract(data,"googlemap" );
gdata= gdata.split(",", 4);
var map= new GMap2($w("gmappopup"+index));
var pt= new GLatLng(gdata[1], gdata[0]);
map.setCenter(pt, 15);
var m= new GMarker(pt);
map.addOverlay(m);
map.setUIToDefault();
if( $j.browser.msie &&( parseFloat($j.browser.version)< 7 ) ){
$j('.ajaxpopup').center(true);}else{$j('.ajaxpopup').center();}
$j(".fermer:first").click(popup.close);
$j(".fermer:first").click(function(){
if( $j.browser.msie &&( parseFloat($j.browser.version)< 7 ) ){
$j(".filtre").show();}
$j('#overlay').fadeOut(800, function(){
$j(this).remove();});});
bfTracker._trackPageview('/maps/'+safeXmlExtract(data,"link" ));});}
function babillardSuivant(){
noPage++;
updateHtml();}
function babillardPrecedent(){
noPage--;
updateHtml();}

function updateBtnPrecedentSuivant(noPage, nbPage){
var bp= $w("btnPrecedent");
var bs= $w("btnSuivant");
var working= false;
if((noPage>1)&&(!working)){
bp.style.cursor="pointer";
bp.onclick=babillardPrecedent;
bp.className="prec";} else{
bp.style.cursor="default";
bp.onclick=null;
bp.className="prec disabled";}
if((noPage< nbPage)&&(!working)){
bs.style.cursor="pointer";
bs.onclick=babillardSuivant;
bs.className="suiv";} else{
bs.style.cursor="default";
bs.onclick=null;
bs.className="suiv disabled";}
if(nbPage>0){
$w("pageNo").innerHTML="PAGE<br />"+noPage+" "+_TR("all.de","de" )+" "+nbPage;} else{
$w("pageNo").innerHTML="";}}

function babillardEchecAction(o){
$w("resultats").innerHTML="<h3>"+ _TR("bab.echec_action_babillard" ,"Une erreur est survenue lors de la communication avec le serveur.")+"</h3>";}
function changeDate(type, args, obj){
var dates= args[0];
var date= dates[0];
var year= date[0], month= date[1], day= date[2];
dateCourante= year+"-"+ month+"-"+ day;
updateRecherche();}

function btnFiltrerLesActivites(){
var g= $w("filtrer-genres");
var p= $w("filtrer-pays");
var z= $w("filtrer-zones");
var gc=0;
var pc=0;
var zc=0;
if(g.selectedIndex>0){
var o= g.options[g.selectedIndex];
gc=o.value;}
if(p.selectedIndex>0){
var o= p.options[p.selectedIndex];
pc=o.value;}
if(z.selectedIndex>0){
var o= z.options[z.selectedIndex];
zc=o.value;}
genreCourant= gc;
paysCourant= pc;
provinceCourante= zc;
motRechCourant= $w("filtrer-keywords").value;
updateRecherche();}
function setUpItem(it, target){
target.hide();
it.click(
function(){
if(it.hasClass("moins")){
target.slideDown(500,"easeOutQuint" );
it.removeClass("moins").addClass("plus").text(_TR("bab.activite_details" ,"Détails")+" -");}else{
target.slideUp(500,"easeOutQuint" );
it.removeClass("plus").addClass("moins").text(_TR("bab.activite_details" ,"Détails")+" +");}}
);}
function initSlide(nbItem){
var rendu=(noPage-1)*itemsParPage;
var max= rendu+itemsParPage;
if(nbItem<max){
max=nbItem;}
for(var i=rendu; i<max; i++){
setUpItem($j('#b-details'+i), $j("#plus-details"+i));}}


function addOptions(select, options){
for(var i=0; i< options.length; i++){
var o= options[i];
var opt= document.createElement('option');
var nom= o.nom;
if(nom.length> 35){
nom= nom.substr(0, 30)+"[...]";}
opt.text= nom;
opt.nom= o.nom;
opt.value= o.id;
opt.iso= o.isoCode2;
opt.code= o.code;
try{
select.add(opt, null);} catch(ex){
select.add(opt, select.options.length);}}}
function fillCbWithDb(source, dest, after){
function fillCbWithDbR(o){
var z= $w(dest);
while(z.options.length> 1){
z.remove(1);}
if(o){
var x= o.documentElement.getElementsByTagName("i");
var zo=[];
for(i= 0; i< x.length; i++){
var a= x[i];
zo.push({id: safeXMLExtract(a,"id" ), nom: safeXMLExtract(a,"nom" ), code: safeXMLExtract(a,"code" )});}
addOptions(z, zo);
if(after){
after();}}}
var pays= parseInt($w(source).value);
if(pays> 0){
$j.get("/plugin.php?plugin=geo&action=Provinces&format=xml&pays="+ pays,{}, fillCbWithDbR,"xml" );} else{
fillCbWithDbR();}}
function updateZF(){
fillCbWithDb("filtrer-pays","filtrer-zones" );}
function initBab(jList){

$j(function(){
addOptions($w("filtrer-pays"), pays);
addOptions($w("pays"), pays);
$w("pays").onchange= updateZones;
$w("filtrer-pays").onchange= updateZF;
updateRecherche();
if(jList){} else{
autoOpen= true;
}
initSoumissionCalendrier();});}
