]> ToastFreeware Gitweb - philipp/winterrodeln/wradmin.git/blobdiff - wradmin/static/yui/calendar/calendar-debug.js
Rename public directory to static.
[philipp/winterrodeln/wradmin.git] / wradmin / static / yui / calendar / calendar-debug.js
diff --git a/wradmin/static/yui/calendar/calendar-debug.js b/wradmin/static/yui/calendar/calendar-debug.js
new file mode 100644 (file)
index 0000000..25646a2
--- /dev/null
@@ -0,0 +1,7178 @@
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 2.7.0
+*/
+(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);
+        }
+
+        if (!owner) {  YAHOO.log("No owner specified for Config object", "error", "Config"); }
+
+    };
+
+
+    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 ) {
+            YAHOO.log("Firing Config event: " + key + "=" + value, "info", "Config");
+            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();
+            YAHOO.log("Added property: " + key, "info", "Config");
+        
+            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 = {},
+                currCfg = this.config,
+                prop,
+                property;
+                
+            for (prop in currCfg) {
+                if (Lang.hasOwnProperty(currCfg, prop)) {
+                    property = currCfg[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();
+            YAHOO.log("setProperty: " + key + "=" + value, "info", "Config");
+        
+            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();
+            YAHOO.log("queueProperty: " + key + "=" + value, "info", "Config");
+        
+            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;
+
+                                }
+                            }
+                        }
+                    }
+                }
+
+                YAHOO.log("Config event queue: " + this.outputEventQueue(), "info", "Config");
+
+                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) {
+                if (Lang.hasOwnProperty(this.config, prop)) {
+                    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;
+
+                    // Clear out queue entry, to avoid it being 
+                    // re-added to the queue by any queueProperty/supercedes
+                    // calls which are invoked during fireEvent
+                    this.eventQueue[i] = null;
+
+                    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
+*/
+(function(){
+
+       var Dom = YAHOO.util.Dom,
+               Event = YAHOO.util.Event,
+               Lang = YAHOO.lang,
+               DateMath = YAHOO.widget.DateMath;
+
+/**
+* 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.
+*/
+function Calendar(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
+*/
+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
+*/
+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
+*/
+Calendar.MONTH_DAY = "MD";
+
+/**
+* Type constant used for renderers to represent a weekday
+* @property YAHOO.widget.Calendar.WEEKDAY
+* @static
+* @final
+* @type String
+*/
+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
+*/
+Calendar.RANGE = "R";
+
+/**
+* Type constant used for renderers to represent a month across any year
+* @property YAHOO.widget.Calendar.MONTH
+* @static
+* @final
+* @type String
+*/
+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
+*/
+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
+*/
+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
+*/
+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
+*/
+Calendar.LONG = "long";
+
+/**
+* Constant used to represent medium date field string formats (e.g. Mon)
+* @property YAHOO.widget.Calendar.MEDIUM
+* @static
+* @final
+* @type String
+*/
+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
+*/
+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
+*/
+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},
+       STRINGS : { 
+               key:"strings",
+               value: {
+                       previousMonth : "Previous Month",
+                       nextMonth : "Next Month",
+                       close: "Close"
+               },
+               supercedes : ["close", "title"]
+       }
+};
+
+var DEF_CFG = Calendar._DEFAULT_CONFIG;
+
+/**
+* The set of Custom Event types supported by the Calendar
+* @property YAHOO.widget.Calendar._EVENT_TYPES
+* @final
+* @static
+* @private
+* @type Object
+*/
+Calendar._EVENT_TYPES = {
+       BEFORE_SELECT : "beforeSelect", 
+       SELECT : "select",
+       BEFORE_DESELECT : "beforeDeselect",
+       DESELECT : "deselect",
+       CHANGE_PAGE : "changePage",
+       BEFORE_RENDER : "beforeRender",
+       RENDER : "render",
+       BEFORE_DESTROY : "beforeDestroy",
+       DESTROY : "destroy",
+       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
+*/
+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"
+};
+
+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 (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 {
+                       this.logger.log("Invalid constructor/init arguments", "error");
+               }
+               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 = Dom.get(container);
+               if (!this.oDomContainer) { this.logger.log("Container not found in document.", "error"); }
+
+               if (!this.oDomContainer.id) {
+                       this.oDomContainer.id = Dom.generateId();
+               }
+               if (!id) {
+                       id = this.oDomContainer.id + "_t";
+               }
+
+               this.id = id;
+               this.containerId = this.oDomContainer.id;
+
+               this.logger = new YAHOO.widget.LogWriter("Calendar " + this.id);
+               this.initEvents();
+
+               this.today = new Date();
+               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();
+
+               Dom.addClass(this.oDomContainer, this.Style.CSS_CONTAINER);
+               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 (Dom.inDocument(this.oDomContainer)) {
+                               if (useIframe) {
+                                       var pos = Dom.getStyle(this.oDomContainer, "position");
+                                       
+                                       if (pos == "absolute" || pos == "relative") {
+                                               
+                                               if (!Dom.inDocument(this.iframe)) {
+                                                       this.iframe = document.createElement("iframe");
+                                                       this.iframe.src = "javascript:false;";
+       
+                                                       Dom.setStyle(this.iframe, "opacity", "0");
+       
+                                                       if (YAHOO.env.ua.ie && YAHOO.env.ua.ie <= 6) {
+                                                               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(DEF_CFG.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(DEF_CFG.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 = Calendar._EVENT_TYPES,
+                       CE = YAHOO.util.CustomEvent,
+                       cal = this; // To help with minification
+
+               /**
+               * Fired before a date selection is made
+               * @event beforeSelectEvent
+               */
+               cal.beforeSelectEvent = new CE(defEvents.BEFORE_SELECT); 
+
+               /**
+               * Fired when a date selection is made
+               * @event selectEvent
+               * @param {Array}        Array of Date field arrays in the format [YYYY, MM, DD].
+               */
+               cal.selectEvent = new CE(defEvents.SELECT);
+
+               /**
+               * Fired before a date or set of dates is deselected
+               * @event beforeDeselectEvent
+               */
+               cal.beforeDeselectEvent = new CE(defEvents.BEFORE_DESELECT);
+
+               /**
+               * Fired when a date or set of dates is deselected
+               * @event deselectEvent
+               * @param {Array}        Array of Date field arrays in the format [YYYY, MM, DD].
+               */
+               cal.deselectEvent = new CE(defEvents.DESELECT);
+       
+               /**
+               * Fired when the Calendar page is changed
+               * @event changePageEvent
+               */
+               cal.changePageEvent = new CE(defEvents.CHANGE_PAGE);
+       
+               /**
+               * Fired before the Calendar is rendered
+               * @event beforeRenderEvent
+               */
+               cal.beforeRenderEvent = new CE(defEvents.BEFORE_RENDER);
+       
+               /**
+               * Fired when the Calendar is rendered
+               * @event renderEvent
+               */
+               cal.renderEvent = new CE(defEvents.RENDER);
+
+               /**
+               * Fired just before the Calendar is to be destroyed
+               * @event beforeDestroyEvent
+               */
+               cal.beforeDestroyEvent = new CE(defEvents.BEFORE_DESTROY);
+
+               /**
+               * Fired after the Calendar is destroyed. This event should be used
+               * for notification only. When this event is fired, important Calendar instance
+               * properties, dom references and event listeners have already been 
+               * removed/dereferenced, and hence the Calendar instance is not in a usable 
+               * state.
+               *
+               * @event destroyEvent
+               */
+               cal.destroyEvent = new CE(defEvents.DESTROY);
+
+               /**
+               * Fired when the Calendar is reset
+               * @event resetEvent
+               */
+               cal.resetEvent = new CE(defEvents.RESET);
+
+               /**
+               * Fired when the Calendar is cleared
+               * @event clearEvent
+               */
+               cal.clearEvent = new CE(defEvents.CLEAR);
+
+               /**
+               * Fired just before the Calendar is to be shown
+               * @event beforeShowEvent
+               */
+               cal.beforeShowEvent = new CE(defEvents.BEFORE_SHOW);
+
+               /**
+               * Fired after the Calendar is shown
+               * @event showEvent
+               */
+               cal.showEvent = new CE(defEvents.SHOW);
+
+               /**
+               * Fired just before the Calendar is to be hidden
+               * @event beforeHideEvent
+               */
+               cal.beforeHideEvent = new CE(defEvents.BEFORE_HIDE);
+
+               /**
+               * Fired after the Calendar is hidden
+               * @event hideEvent
+               */
+               cal.hideEvent = new CE(defEvents.HIDE);
+
+               /**
+               * Fired just before the CalendarNavigator is to be shown
+               * @event beforeShowNavEvent
+               */
+               cal.beforeShowNavEvent = new CE(defEvents.BEFORE_SHOW_NAV);
+       
+               /**
+               * Fired after the CalendarNavigator is shown
+               * @event showNavEvent
+               */
+               cal.showNavEvent = new CE(defEvents.SHOW_NAV);
+       
+               /**
+               * Fired just before the CalendarNavigator is to be hidden
+               * @event beforeHideNavEvent
+               */
+               cal.beforeHideNavEvent = new CE(defEvents.BEFORE_HIDE_NAV);
+       
+               /**
+               * Fired after the CalendarNavigator is hidden
+               * @event hideNavEvent
+               */
+               cal.hideNavEvent = new CE(defEvents.HIDE_NAV);
+
+               /**
+               * Fired just before the CalendarNavigator is to be rendered
+               * @event beforeRenderNavEvent
+               */
+               cal.beforeRenderNavEvent = new CE(defEvents.BEFORE_RENDER_NAV);
+
+               /**
+               * Fired after the CalendarNavigator is rendered
+               * @event renderNavEvent
+               */
+               cal.renderNavEvent = new CE(defEvents.RENDER_NAV);
+
+               cal.beforeSelectEvent.subscribe(cal.onBeforeSelect, this, true);
+               cal.selectEvent.subscribe(cal.onSelect, this, true);
+               cal.beforeDeselectEvent.subscribe(cal.onBeforeDeselect, this, true);
+               cal.deselectEvent.subscribe(cal.onDeselect, this, true);
+               cal.changePageEvent.subscribe(cal.onChangePage, this, true);
+               cal.renderEvent.subscribe(cal.onRender, this, true);
+               cal.resetEvent.subscribe(cal.onReset, this, true);
+               cal.clearEvent.subscribe(cal.onClear, this, true);
+       },
+
+       /**
+       * The default event handler for clicks on the "Previous Month" navigation UI
+       *
+       * @method doPreviousMonthNav
+       * @param {DOMEvent} e   The DOM event
+       * @param {Calendar} cal A reference to the calendar
+       */
+       doPreviousMonthNav : function(e, cal) {
+               Event.preventDefault(e);
+               // previousMonth invoked in a timeout, to allow
+               // event to bubble up, with correct target. Calling
+               // previousMonth, will call render which will remove 
+               // HTML which generated the event, resulting in an 
+               // invalid event target in certain browsers.
+               setTimeout(function() {
+                       cal.previousMonth();
+                       var navs = Dom.getElementsByClassName(cal.Style.CSS_NAV_LEFT, "a", cal.oDomContainer);
+                       if (navs && navs[0]) {
+                               try {
+                                       navs[0].focus();
+                               } catch (e) {
+                                       // ignore
+                               }
+                       }
+               }, 0);
+       },
+
+       /**
+        * The default event handler for clicks on the "Next Month" navigation UI
+        *
+        * @method doNextMonthNav
+        * @param {DOMEvent} e  The DOM event
+        * @param {Calendar} cal        A reference to the calendar
+        */
+       doNextMonthNav : function(e, cal) {
+               Event.preventDefault(e);
+               setTimeout(function() {
+                       cal.nextMonth();
+                       var navs = Dom.getElementsByClassName(cal.Style.CSS_NAV_RIGHT, "a", cal.oDomContainer);
+                       if (navs && navs[0]) {
+                               try {
+                                       navs[0].focus();
+                               } catch (e) {
+                                       // ignore
+                               }
+                       }
+               }, 0);
+       },
+
+       /**
+       * The default event handler for date cell selection. Currently attached to 
+       * the Calendar's bounding box, referenced by it's <a href="#property_oDomContainer">oDomContainer</a> property.
+       *
+       * @method doSelectCell
+       * @param {DOMEvent} e   The DOM event
+       * @param {Calendar} cal A reference to the calendar
+       */
+       doSelectCell : function(e, cal) {
+               var cell, d, date, index;
+
+               var target = Event.getTarget(e),
+                       tagName = target.tagName.toLowerCase(),
+                       defSelector = false;
+
+               while (tagName != "td" && !Dom.hasClass(target, cal.Style.CSS_CELL_SELECTABLE)) {
+
+                       if (!defSelector && tagName == "a" && Dom.hasClass(target, cal.Style.CSS_CELL_SELECTOR)) {
+                               defSelector = true;
+                       }
+
+                       target = target.parentNode;
+                       tagName = target.tagName.toLowerCase();
+
+                       if (target == this.oDomContainer || tagName == "html") {
+                               return;
+                       }
+               }
+
+               if (defSelector) {
+                       // Stop link href navigation for default renderer
+                       Event.preventDefault(e);
+               }
+       
+               cell = target;
+
+               if (Dom.hasClass(cell, cal.Style.CSS_CELL_SELECTABLE)) {
+                       index = cal.getIndexFromId(cell.id);
+                       if (index > -1) {
+                               d = cal.cellDates[index];
+                               if (d) {
+                                       date = DateMath.getDate(d[0],d[1]-1,d[2]);
+                               
+                                       var link;
+
+                                       cal.logger.log("Selecting cell " + index + " via click", "info");
+                                       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 = 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 (Dom.hasClass(target, cal.Style.CSS_CELL_SELECTABLE)) {
+                       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 = 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 (Dom.hasClass(target, cal.Style.CSS_CELL_SELECTABLE)) {
+                       Dom.removeClass(target, cal.Style.CSS_CELL_HOVER);
+               }
+       },
+
+       setupConfig : function() {
+               var cfg = this.cfg;
+
+               /**
+               * The month/year representing the current visible Calendar date (mm/yyyy)
+               * @config pagedate
+               * @type String | Date
+               * @default today's date
+               */
+               cfg.addProperty(DEF_CFG.PAGEDATE.key, { value:new Date(), handler:this.configPageDate } );
+
+               /**
+               * The date or range of dates representing the current Calendar selection
+               * @config selected
+               * @type String
+               * @default []
+               */
+               cfg.addProperty(DEF_CFG.SELECTED.key, { value:[], handler:this.configSelected } );
+
+               /**
+               * The title to display above the Calendar's month header
+               * @config title
+               * @type String
+               * @default ""
+               */
+               cfg.addProperty(DEF_CFG.TITLE.key, { value:DEF_CFG.TITLE.value, handler:this.configTitle } );
+
+               /**
+               * Whether or not a close button should be displayed for this Calendar
+               * @config close
+               * @type Boolean
+               * @default false
+               */
+               cfg.addProperty(DEF_CFG.CLOSE.key, { value:DEF_CFG.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
+               */
+               cfg.addProperty(DEF_CFG.IFRAME.key, { value:DEF_CFG.IFRAME.value, handler:this.configIframe, validator:cfg.checkBoolean } );
+
+               /**
+               * The minimum selectable date in the current Calendar (mm/dd/yyyy)
+               * @config mindate
+               * @type String | Date
+               * @default null
+               */
+               cfg.addProperty(DEF_CFG.MINDATE.key, { value:DEF_CFG.MINDATE.value, handler:this.configMinDate } );
+
+               /**
+               * The maximum selectable date in the current Calendar (mm/dd/yyyy)
+               * @config maxdate
+               * @type String | Date
+               * @default null
+               */
+               cfg.addProperty(DEF_CFG.MAXDATE.key, { value:DEF_CFG.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
+               */
+               cfg.addProperty(DEF_CFG.MULTI_SELECT.key,       { value:DEF_CFG.MULTI_SELECT.value, handler:this.configOptions, validator:cfg.checkBoolean } );
+
+               /**
+               * The weekday the week begins on. Default is 0 (Sunday = 0, Monday = 1 ... Saturday = 6).
+               * @config START_WEEKDAY
+               * @type number
+               * @default 0
+               */
+               cfg.addProperty(DEF_CFG.START_WEEKDAY.key,      { value:DEF_CFG.START_WEEKDAY.value, handler:this.configOptions, validator:cfg.checkNumber  } );
+       
+               /**
+               * True if the Calendar should show weekday labels. True by default.
+               * @config SHOW_WEEKDAYS
+               * @type Boolean
+               * @default true
+               */
+               cfg.addProperty(DEF_CFG.SHOW_WEEKDAYS.key,      { value:DEF_CFG.SHOW_WEEKDAYS.value, handler:this.configOptions, validator:cfg.checkBoolean  } );
+       
+               /**
+               * True if the Calendar should show week row headers. False by default.
+               * @config SHOW_WEEK_HEADER
+               * @type Boolean
+               * @default false
+               */
+               cfg.addProperty(DEF_CFG.SHOW_WEEK_HEADER.key, { value:DEF_CFG.SHOW_WEEK_HEADER.value, handler:this.configOptions, validator:cfg.checkBoolean } );
+       
+               /**
+               * True if the Calendar should show week row footers. False by default.
+               * @config SHOW_WEEK_FOOTER
+               * @type Boolean
+               * @default false
+               */      
+               cfg.addProperty(DEF_CFG.SHOW_WEEK_FOOTER.key,{ value:DEF_CFG.SHOW_WEEK_FOOTER.value, handler:this.configOptions, validator: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
+               */      
+               cfg.addProperty(DEF_CFG.HIDE_BLANK_WEEKS.key, { value:DEF_CFG.HIDE_BLANK_WEEKS.value, handler:this.configOptions, validator: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
+               */      
+               cfg.addProperty(DEF_CFG.NAV_ARROW_LEFT.key,     { value:DEF_CFG.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
+               */      
+               cfg.addProperty(DEF_CFG.NAV_ARROW_RIGHT.key, { value:DEF_CFG.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"]
+               */
+               cfg.addProperty(DEF_CFG.MONTHS_SHORT.key,       { value:DEF_CFG.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"
+               */      
+               cfg.addProperty(DEF_CFG.MONTHS_LONG.key,                { value:DEF_CFG.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"]
+               */      
+               cfg.addProperty(DEF_CFG.WEEKDAYS_1CHAR.key,     { value:DEF_CFG.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"]
+               */      
+               cfg.addProperty(DEF_CFG.WEEKDAYS_SHORT.key,     { value:DEF_CFG.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"]
+               */      
+               cfg.addProperty(DEF_CFG.WEEKDAYS_MEDIUM.key,    { value:DEF_CFG.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"]
+               */      
+               cfg.addProperty(DEF_CFG.WEEKDAYS_LONG.key,      { value:DEF_CFG.WEEKDAYS_LONG.value, handler:this.configLocale } );
+       
+               /**
+               * Refreshes the locale values used to build the Calendar.
+               * @method refreshLocale
+               * @private
+               */
+               var refreshLocale = function() {
+                       cfg.refireEvent(DEF_CFG.LOCALE_MONTHS.key);
+                       cfg.refireEvent(DEF_CFG.LOCALE_WEEKDAYS.key);
+               };
+       
+               cfg.subscribeToConfigEvent(DEF_CFG.START_WEEKDAY.key, refreshLocale, this, true);
+               cfg.subscribeToConfigEvent(DEF_CFG.MONTHS_SHORT.key, refreshLocale, this, true);
+               cfg.subscribeToConfigEvent(DEF_CFG.MONTHS_LONG.key, refreshLocale, this, true);
+               cfg.subscribeToConfigEvent(DEF_CFG.WEEKDAYS_1CHAR.key, refreshLocale, this, true);
+               cfg.subscribeToConfigEvent(DEF_CFG.WEEKDAYS_SHORT.key, refreshLocale, this, true);
+               cfg.subscribeToConfigEvent(DEF_CFG.WEEKDAYS_MEDIUM.key, refreshLocale, this, true);
+               cfg.subscribeToConfigEvent(DEF_CFG.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"
+               */      
+               cfg.addProperty(DEF_CFG.LOCALE_MONTHS.key,      { value:DEF_CFG.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"
+               */      
+               cfg.addProperty(DEF_CFG.LOCALE_WEEKDAYS.key,    { value:DEF_CFG.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 ","
+               */      
+               cfg.addProperty(DEF_CFG.DATE_DELIMITER.key,             { value:DEF_CFG.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 "/"
+               */      
+               cfg.addProperty(DEF_CFG.DATE_FIELD_DELIMITER.key, { value:DEF_CFG.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 "-"
+               */
+               cfg.addProperty(DEF_CFG.DATE_RANGE_DELIMITER.key, { value:DEF_CFG.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
+               */
+               cfg.addProperty(DEF_CFG.MY_MONTH_POSITION.key,  { value:DEF_CFG.MY_MONTH_POSITION.value, handler:this.configLocale, validator:cfg.checkNumber } );
+       
+               /**
+               * The position of the year in a month/year date string
+               * @config MY_YEAR_POSITION
+               * @type Number
+               * @default 2
+               */
+               cfg.addProperty(DEF_CFG.MY_YEAR_POSITION.key,   { value:DEF_CFG.MY_YEAR_POSITION.value, handler:this.configLocale, validator:cfg.checkNumber } );
+       
+               /**
+               * The position of the month in a month/day date string
+               * @config MD_MONTH_POSITION
+               * @type Number
+               * @default 1
+               */
+               cfg.addProperty(DEF_CFG.MD_MONTH_POSITION.key,  { value:DEF_CFG.MD_MONTH_POSITION.value, handler:this.configLocale, validator:cfg.checkNumber } );
+       
+               /**
+               * The position of the day in a month/year date string
+               * @config MD_DAY_POSITION
+               * @type Number
+               * @default 2
+               */
+               cfg.addProperty(DEF_CFG.MD_DAY_POSITION.key,            { value:DEF_CFG.MD_DAY_POSITION.value, handler:this.configLocale, validator:cfg.checkNumber } );
+       
+               /**
+               * The position of the month in a month/day/year date string
+               * @config MDY_MONTH_POSITION
+               * @type Number
+               * @default 1
+               */
+               cfg.addProperty(DEF_CFG.MDY_MONTH_POSITION.key, { value:DEF_CFG.MDY_MONTH_POSITION.value, handler:this.configLocale, validator:cfg.checkNumber } );
+       
+               /**
+               * The position of the day in a month/day/year date string
+               * @config MDY_DAY_POSITION
+               * @type Number
+               * @default 2
+               */
+               cfg.addProperty(DEF_CFG.MDY_DAY_POSITION.key,   { value:DEF_CFG.MDY_DAY_POSITION.value, handler:this.configLocale, validator:cfg.checkNumber } );
+       
+               /**
+               * The position of the year in a month/day/year date string
+               * @config MDY_YEAR_POSITION
+               * @type Number
+               * @default 3
+               */
+               cfg.addProperty(DEF_CFG.MDY_YEAR_POSITION.key,  { value:DEF_CFG.MDY_YEAR_POSITION.value, handler:this.configLocale, validator: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
+               */
+               cfg.addProperty(DEF_CFG.MY_LABEL_MONTH_POSITION.key,    { value:DEF_CFG.MY_LABEL_MONTH_POSITION.value, handler:this.configLocale, validator: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
+               */
+               cfg.addProperty(DEF_CFG.MY_LABEL_YEAR_POSITION.key,     { value:DEF_CFG.MY_LABEL_YEAR_POSITION.value, handler:this.configLocale, validator:cfg.checkNumber } );
+               
+               /**
+               * The suffix used after the month when rendering the Calendar header
+               * @config MY_LABEL_MONTH_SUFFIX
+               * @type String
+               * @default " "
+               */
+               cfg.addProperty(DEF_CFG.MY_LABEL_MONTH_SUFFIX.key,      { value:DEF_CFG.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 ""
+               */
+               cfg.addProperty(DEF_CFG.MY_LABEL_YEAR_SUFFIX.key, { value:DEF_CFG.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
+               */
+               cfg.addProperty(DEF_CFG.NAV.key, { value:DEF_CFG.NAV.value, handler:this.configNavigator } );
+
+               /**
+                * The map of UI strings which the Calendar UI uses.
+                *
+                * @config strings
+                * @type {Object}
+                * @default An object with the properties shown below:
+                *     <dl>
+                *         <dt>previousMonth</dt><dd><em>String</em> : The string to use for the "Previous Month" navigation UI. Defaults to "Previous Month".</dd>
+                *         <dt>nextMonth</dt><dd><em>String</em> : The string to use for the "Next Month" navigation UI. Defaults to "Next Month".</dd>
+                *         <dt>close</dt><dd><em>String</em> : The string to use for the close button label. Defaults to "Close".</dd>
+                *     </dl>
+                */
+               cfg.addProperty(DEF_CFG.STRINGS.key, { 
+                       value:DEF_CFG.STRINGS.value,
+                       handler:this.configStrings,
+                       validator: function(val) {
+                               return Lang.isObject(val);
+                       },
+                       supercedes:DEF_CFG.STRINGS.supercedes
+               });
+       },
+
+       /**
+       * The default handler for the "strings" property
+       * @method configStrings
+       */
+       configStrings : function(type, args, obj) {
+               var val = Lang.merge(DEF_CFG.STRINGS.value, args[0]);
+               this.cfg.setProperty(DEF_CFG.STRINGS.key, val, true);
+       },
+
+       /**
+       * The default handler for the "pagedate" property
+       * @method configPageDate
+       */
+       configPageDate : function(type, args, obj) {
+               this.cfg.setProperty(DEF_CFG.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 (Lang.isString(val)) {
+                       val = this._parseDate(val);
+                       this.cfg.setProperty(DEF_CFG.MINDATE.key, 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 (Lang.isString(val)) {
+                       val = this._parseDate(val);
+                       this.cfg.setProperty(DEF_CFG.MAXDATE.key, 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],
+                       cfgSelected = DEF_CFG.SELECTED.key;
+               
+               if (selected) {
+                       if (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) {
+               this.Locale[type.toUpperCase()] = args[0];
+
+               this.cfg.refireEvent(DEF_CFG.LOCALE_MONTHS.key);
+               this.cfg.refireEvent(DEF_CFG.LOCALE_WEEKDAYS.key);
+       },
+       
+       /**
+       * The default handler for all configuration locale field length properties
+       * @method configLocaleValues
+       */
+       configLocaleValues : function(type, args, obj) {
+
+               type = type.toLowerCase();
+
+               var val = args[0],
+                       cfg = this.cfg,
+                       Locale = this.Locale;
+
+               switch (type) {
+                       case DEF_CFG.LOCALE_MONTHS.key:
+                               switch (val) {
+                                       case Calendar.SHORT:
+                                               Locale.LOCALE_MONTHS = cfg.getProperty(DEF_CFG.MONTHS_SHORT.key).concat();
+                                               break;
+                                       case Calendar.LONG:
+                                               Locale.LOCALE_MONTHS = cfg.getProperty(DEF_CFG.MONTHS_LONG.key).concat();
+                                               break;
+                               }
+                               break;
+                       case DEF_CFG.LOCALE_WEEKDAYS.key:
+                               switch (val) {
+                                       case Calendar.ONE_CHAR:
+                                               Locale.LOCALE_WEEKDAYS = cfg.getProperty(DEF_CFG.WEEKDAYS_1CHAR.key).concat();
+                                               break;
+                                       case Calendar.SHORT:
+                                               Locale.LOCALE_WEEKDAYS = cfg.getProperty(DEF_CFG.WEEKDAYS_SHORT.key).concat();
+                                               break;
+                                       case Calendar.MEDIUM:
+                                               Locale.LOCALE_WEEKDAYS = cfg.getProperty(DEF_CFG.WEEKDAYS_MEDIUM.key).concat();
+                                               break;
+                                       case Calendar.LONG:
+                                               Locale.LOCALE_WEEKDAYS = cfg.getProperty(DEF_CFG.WEEKDAYS_LONG.key).concat();
+                                               break;
+                               }
+                               
+                               var START_WEEKDAY = cfg.getProperty(DEF_CFG.START_WEEKDAY.key);
+       
+                               if (START_WEEKDAY > 0) {
+                                       for (var w=0; w < START_WEEKDAY; ++w) {
+                                               Locale.LOCALE_WEEKDAYS.push(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 || Lang.isObject(val))) {
+                       if (!this.oNavigator) {
+                               this.oNavigator = new YAHOO.widget.CalendarNavigator(this);
+                               // Cleanup DOM Refs/Events before innerHTML is removed.
+                               this.beforeRenderEvent.subscribe(function () {
+                                       if (!this.pages) {
+                                               this.oNavigator.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 = 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() {
+               return this._buildMonthLabel(this.cfg.getProperty(DEF_CFG.PAGEDATE.key));
+       },
+
+    /**
+     * Helper method, to format a Month Year string, given a JavaScript Date, based on the 
+     * Calendar localization settings
+     * 
+     * @method _buildMonthLabel
+     * @private
+     * @param {Date} date
+     * @return {String} Formated month, year string
+     */
+       _buildMonthLabel : function(date) {
+               var     monthLabel  = this.Locale.LOCALE_MONTHS[date.getMonth()] + this.Locale.MY_LABEL_MONTH_SUFFIX,
+                       yearLabel = date.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 = 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);
+       
+               Dom.addClass(this.oDomContainer, "withtitle");
+       
+               return tDiv;
+       },
+       
+       /**
+        * Removes the title bar element from the DOM
+        * 
+        * @method removeTitleBar
+        */
+       removeTitleBar : function() {
+               var tDiv = Dom.getElementsByClassName(YAHOO.widget.CalendarGroup.CSS_2UPTITLE, "div", this.oDomContainer)[0] || null;
+               if (tDiv) {
+                       Event.purgeElement(tDiv);
+                       this.oDomContainer.removeChild(tDiv);
+               }
+               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 cssClose = YAHOO.widget.CalendarGroup.CSS_2UPCLOSE,
+                       DEPR_CLOSE_PATH = "us/my/bn/x_d.gif",
+                       lnk = Dom.getElementsByClassName("link-close", "a", this.oDomContainer)[0],
+                       strings = this.cfg.getProperty(DEF_CFG.STRINGS.key),
+                       closeStr = (strings && strings.close) ? strings.close : "";
+
+               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 (Calendar.IMG_ROOT !== null) {
+                       var img = Dom.getElementsByClassName(cssClose, "img", lnk)[0] || document.createElement("img");
+                       img.src = Calendar.IMG_ROOT + DEPR_CLOSE_PATH;
+                       img.className = cssClose;
+                       lnk.appendChild(img);
+               } else {
+                       lnk.innerHTML = '<span class="' + cssClose + ' ' + this.Style.CSS_CLOSE + '">' + closeStr + '</span>';
+               }
+               this.oDomContainer.appendChild(lnk);
+
+               return lnk;
+       },
+       
+       /**
+        * Removes the close button HTML element from the DOM
+        * 
+        * @method removeCloseButton
+        */
+       removeCloseButton : function() {
+               var btn = Dom.getElementsByClassName("link-close", "a", this.oDomContainer)[0] || null;
+               if (btn) {
+                       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) {
+
+               this.logger.log("Rendering header", "render");
+
+               var colSpan = 7,
+                       DEPR_NAV_LEFT = "us/tr/callt.gif",
+                       DEPR_NAV_RIGHT = "us/tr/calrt.gif",
+                       cfg = this.cfg,
+                       pageDate = cfg.getProperty(DEF_CFG.PAGEDATE.key),
+                       strings= cfg.getProperty(DEF_CFG.STRINGS.key),
+                       prevStr = (strings && strings.previousMonth) ?  strings.previousMonth : "",
+                       nextStr = (strings && strings.nextMonth) ? strings.nextMonth : "",
+            monthLabel;
+
+               if (cfg.getProperty(DEF_CFG.SHOW_WEEK_HEADER.key)) {
+                       colSpan += 1;
+               }
+       
+               if (cfg.getProperty(DEF_CFG.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) {
+                       monthLabel  = this._buildMonthLabel(DateMath.subtract(pageDate, DateMath.MONTH, 1));
+
+                       var leftArrow = cfg.getProperty(DEF_CFG.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 && Calendar.IMG_ROOT !== null) {
+                               leftArrow = 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 + ' href="#">' + prevStr + ' (' + monthLabel + ')' + '</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) {
+                       monthLabel  = this._buildMonthLabel(DateMath.add(pageDate, DateMath.MONTH, 1));
+
+                       var rightArrow = cfg.getProperty(DEF_CFG.NAV_ARROW_RIGHT.key);
+                       if (rightArrow === null && Calendar.IMG_ROOT !== null) {
+                               rightArrow = 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 + ' href="#">' + nextStr + ' (' + monthLabel + ')' + '</a>';
+               }
+
+               html[html.length] =     '</div>\n</th>\n</tr>';
+
+               if (cfg.getProperty(DEF_CFG.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) {
+
+               html[html.length] = '<tr class="' + this.Style.CSS_WEEKDAY_ROW + '">';
+
+               if (this.cfg.getProperty(DEF_CFG.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(DEF_CFG.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) {
+               this.logger.log("Rendering body", "render");
+
+               var startDay = this.cfg.getProperty(DEF_CFG.START_WEEKDAY.key);
+
+               this.preMonthDays = workingDate.getDay();
+               if (startDay > 0) {
+                       this.preMonthDays -= startDay;
+               }
+               if (this.preMonthDays < 0) {
+                       this.preMonthDays += 7;
+               }
+
+               this.monthDays = DateMath.findMonthEnd(workingDate).getDate();
+               this.postMonthDays = Calendar.DISPLAY_DAYS-this.preMonthDays-this.monthDays;
+
+               this.logger.log(this.preMonthDays + " preciding out-of-month days", "render");
+               this.logger.log(this.monthDays + " month days", "render");
+               this.logger.log(this.postMonthDays + " post-month days", "render");
+
+               workingDate = DateMath.subtract(workingDate, DateMath.DAY, this.preMonthDays);
+               this.logger.log("Calendar page starts on " + workingDate, "render");
+       
+               var weekNum,
+                       weekClass,
+                       weekPrefix = "w",
+                       cellPrefix = "_cell",
+                       workingDayPrefix = "wd",
+                       dayPrefix = "d",
+                       cellRenderers,
+                       renderer,
+                       t = this.today,
+                       cfg = this.cfg,
+                       todayYear = t.getFullYear(),
+                       todayMonth = t.getMonth(),
+                       todayDate = t.getDate(),
+                       useDate = cfg.getProperty(DEF_CFG.PAGEDATE.key),
+                       hideBlankWeeks = cfg.getProperty(DEF_CFG.HIDE_BLANK_WEEKS.key),
+                       showWeekFooter = cfg.getProperty(DEF_CFG.SHOW_WEEK_FOOTER.key),
+                       showWeekHeader = cfg.getProperty(DEF_CFG.SHOW_WEEK_HEADER.key),
+                       mindate = cfg.getProperty(DEF_CFG.MINDATE.key),
+                       maxdate = cfg.getProperty(DEF_CFG.MAXDATE.key);
+
+               if (mindate) {
+                       mindate = DateMath.clearTime(mindate);
+               }
+               if (maxdate) {
+                       maxdate = DateMath.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 = DateMath.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;
+                                       this.logger.log("Rendering cell " + cell.id + " (" + workingDate.getFullYear() + "-" + (workingDate.getMonth()+1) + "-" + workingDate.getDate() + ")", "cellrender");
+
+                                       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 {
+                                               Dom.addClass(cell, workingDayPrefix + workingDate.getDay());
+                                               Dom.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 Calendar.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 Calendar.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 Calendar.RANGE:
+                                                                       var date1 = rArray[1][0],
+                                                                               date2 = rArray[1][1],
+                                                                               d1month = date1[1],
+                                                                               d1day = date1[2],
+                                                                               d1year = date1[0],
+                                                                               d1 = DateMath.getDate(d1year, d1month-1, d1day),
+                                                                               d2month = date2[1],
+                                                                               d2day = date2[2],
+                                                                               d2year = date2[0],
+                                                                               d2 = DateMath.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 Calendar.WEEKDAY:
+                                                                       var weekday = rArray[1][0];
+                                                                       if (workingDate.getDay()+1 == weekday) {
+                                                                               renderer = rArray[2];
+                                                                       }
+                                                                       break;
+                                                               case Calendar.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) {
+                                               this.logger.log("renderer[" + x + "] for (" + workingDate.getFullYear() + "-" + (workingDate.getMonth()+1) + "-" + workingDate.getDate() + ")", "cellrender");
+                                               if (cellRenderers[x].call(cal, workingDate, cell) == Calendar.STOP_RENDER) {
+                                                       break;
+                                               }
+                                       }
+
+                                       workingDate.setTime(workingDate.getTime() + DateMath.ONE_DAY_MS);
+                                       // Just in case we crossed DST/Summertime boundaries
+                                       workingDate = DateMath.clearTime(workingDate);
+
+                                       if (i >= 0 && i <= 6) {
+                                               Dom.addClass(cell, this.Style.CSS_CELL_TOP);
+                                       }
+                                       if ((i % 7) === 0) {
+                                               Dom.addClass(cell, this.Style.CSS_CELL_LEFT);
+                                       }
+                                       if (((i+1) % 7) === 0) {
+                                               Dom.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)) {
+                                               Dom.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();
+
+               // Find starting day of the current month
+               var workingDate = DateMath.findMonthStart(this.cfg.getProperty(DEF_CFG.PAGEDATE.key));
+
+               this.resetRenderers();
+               this.cellDates.length = 0;
+
+               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(DEF_CFG.TITLE.key);
+               this.cfg.refireEvent(DEF_CFG.CLOSE.key);
+               this.cfg.refireEvent(DEF_CFG.IFRAME.key);
+
+               this.renderEvent.fire();
+       },
+
+       /**
+       * Applies the Calendar's DOM listeners to applicable elements.
+       * @method applyListeners
+       */
+       applyListeners : function() {
+               var root = this.oDomContainer,
+                       cal = this.parent || this,
+                       anchor = "a",
+                       click = "click";
+
+               var linkLeft = Dom.getElementsByClassName(this.Style.CSS_NAV_LEFT, anchor, root),
+                       linkRight = Dom.getElementsByClassName(this.Style.CSS_NAV_RIGHT, anchor, root);
+
+               if (linkLeft && linkLeft.length > 0) {
+                       this.linkLeft = linkLeft[0];
+                       Event.addListener(this.linkLeft, click, this.doPreviousMonthNav, cal, true);
+               }
+
+               if (linkRight && linkRight.length > 0) {
+                       this.linkRight = linkRight[0];
+                       Event.addListener(this.linkRight, click, this.doNextMonthNav, cal, true);
+               }
+
+               if (cal.cfg.getProperty("navigator") !== null) {
+                       this.applyNavListeners();
+               }
+
+               if (this.domEventMap) {
+                       var el,elements;
+                       for (var cls in this.domEventMap) {     
+                               if (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 = Dom.getElementsByClassName(cls, item.tag, this.oDomContainer);
+       
+                                               for (var c=0;c<elements.length;c++) {
+                                                       el = elements[c];
+                                                        Event.addListener(el, item.event, item.handler, item.scope, item.correct );
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+               Event.addListener(this.oDomContainer, "click", this.doSelectCell, this);
+               Event.addListener(this.oDomContainer, "mouseover", this.doCellMouseOver, this);
+               Event.addListener(this.oDomContainer, "mouseout", this.doCellMouseOut, this);
+       },
+
+       applyNavListeners : function() {
+               var calParent = this.parent || this,
+                       cal = this,
+                       navBtns = Dom.getElementsByClassName(this.Style.CSS_NAV, "a", this.oDomContainer);
+
+               if (navBtns.length > 0) {
+
+                       Event.addListener(navBtns, "click", function (e, obj) {
+                               var target = Event.getTarget(e);
+                               // this == navBtn
+                               if (this === target || Dom.isAncestor(this, target)) {
+                                       Event.preventDefault(e);
+                               }
+                               var navigator = calParent.oNavigator;
+                               if (navigator) {
+                                       var pgdate = cal.cfg.getProperty("pagedate");
+                                       navigator.setYear(pgdate.getFullYear());
+                                       navigator.setMonth(pgdate.getMonth());
+                                       navigator.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 (date) ? DateMath.getDate(date[0],date[1]-1,date[2]) : null;
+       },
+       
+       /**
+       * 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 = this.getIndexFromId(id);
+               return (id > -1) ? this.cellDates[id] : null;
+       },
+
+       /**
+        * 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;
+       },
+
+       /**
+        * Given the id used to mark each Calendar cell, this method
+        * extracts the index number from the id.
+        * 
+        * @param {String} strId The cell id
+        * @return {Number} The index of the cell, or -1 if id does not contain an index number
+        */
+       getIndexFromId : function(strId) {
+               var idx = -1,
+                       li = strId.lastIndexOf("_cell");
+
+               if (li > -1) {
+                       idx = parseInt(strId.substring(li + 5), 10);
+               }
+
+               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) {
+               Dom.addClass(cell, this.Style.CSS_CELL_OOB);
+               cell.innerHTML = workingDate.getDate();
+               return 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) {
+               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) {
+               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) {
+               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) {
+               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) {
+               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) {
+               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) {
+               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) {
+               Dom.addClass(cell, this.Style.CSS_CELL_OOM);
+               cell.innerHTML=workingDate.getDate();
+               return 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) {
+               Dom.addClass(cell, this.Style.CSS_CELL);
+               Dom.addClass(cell, this.Style.CSS_CELL_RESTRICTED);
+               cell.innerHTML=workingDate.getDate();
+               return 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 = DEF_CFG.PAGEDATE.key;
+               this.cfg.setProperty(cfgPageDate, DateMath.add(this.cfg.getProperty(cfgPageDate), 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 = DEF_CFG.PAGEDATE.key;
+               this.cfg.setProperty(cfgPageDate, DateMath.subtract(this.cfg.getProperty(cfgPageDate), 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 = DEF_CFG.PAGEDATE.key;
+               this.cfg.setProperty(cfgPageDate, DateMath.add(this.cfg.getProperty(cfgPageDate), 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 = DEF_CFG.PAGEDATE.key;
+               this.cfg.setProperty(cfgPageDate, DateMath.subtract(this.cfg.getProperty(cfgPageDate), 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() {
+               this.cfg.resetProperty(DEF_CFG.SELECTED.key);
+               this.cfg.resetProperty(DEF_CFG.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() {
+               this.cfg.setProperty(DEF_CFG.SELECTED.key, []);
+               this.cfg.setProperty(DEF_CFG.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) {
+               this.logger.log("Select: " + date, "info");
+
+               var aToBeSelected = this._toFieldArray(date),
+                       validDates = [],
+                       selected = [],
+                       cfgSelected = DEF_CFG.SELECTED.key;
+
+               this.logger.log("Selection field array: " + aToBeSelected, "info");
+               
+               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) { this.logger.log("All provided dates were OOB. beforeSelect and select events not fired", "info"); }
+
+               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],
+                       cellDate = this.cellDates[cellIndex],
+                       dCellDate = this._toDate(cellDate),
+                       selectable = Dom.hasClass(cell, this.Style.CSS_CELL_SELECTABLE);
+
+               this.logger.log("Select: " + dCellDate, "info");
+               if (!selectable) {this.logger.log("The cell at cellIndex:" + cellIndex + " is not a selectable cell. beforeSelect, select events not fired", "info"); }
+
+               if (selectable) {
+       
+                       this.beforeSelectEvent.fire();
+       
+                       var cfgSelected = DEF_CFG.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) {
+               this.logger.log("Deselect: " + date, "info");
+
+               var aToBeDeselected = this._toFieldArray(date),
+                       validDates = [],
+                       selected = [],
+                       cfgSelected = DEF_CFG.SELECTED.key;
+
+               this.logger.log("Deselection field array: " + aToBeDeselected, "info");
+
+               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) { this.logger.log("All provided dates were OOB. beforeDeselect and deselect events not fired");}
+       
+               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],
+                       cellDate = this.cellDates[cellIndex],
+                       cellDateIndex = this._indexOfSelectedFieldArray(cellDate);
+
+               var selectable = Dom.hasClass(cell, this.Style.CSS_CELL_SELECTABLE);
+               if (!selectable) { this.logger.log("The cell at cellIndex:" + cellIndex + " is not a selectable/deselectable cell", "info"); }
+
+               if (selectable) {
+
+                       this.beforeDeselectEvent.fire();
+
+                       var selected = this.cfg.getProperty(DEF_CFG.SELECTED.key),
+                               dCellDate = this._toDate(cellDate),
+                               selectDate = cellDate.concat();
+
+                       if (cellDateIndex > -1) {
+                               if (this.cfg.getProperty(DEF_CFG.PAGEDATE.key).getMonth() == dCellDate.getMonth() &&
+                                       this.cfg.getProperty(DEF_CFG.PAGEDATE.key).getFullYear() == dCellDate.getFullYear()) {
+                                       Dom.removeClass(cell, this.Style.CSS_CELL_SELECTED);
+                               }
+                               selected.splice(cellDateIndex, 1);
+                       }
+
+                       if (this.parent) {
+                               this.parent.cfg.setProperty(DEF_CFG.SELECTED.key, selected);
+                       } else {
+                               this.cfg.setProperty(DEF_CFG.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 = DEF_CFG.SELECTED.key,
+                       selected = this.cfg.getProperty(cfgSelected),
+                       count = selected.length,
+                       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 (Lang.isString(date)) {
+                       returnDate = this._parseDates(date);
+               } else if (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 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,
+                       seldates = this.cfg.getProperty(DEF_CFG.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(DEF_CFG.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 minDate = this.cfg.getProperty(DEF_CFG.MINDATE.key),
+                       maxDate = this.cfg.getProperty(DEF_CFG.MAXDATE.key),
+                       dm = 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;
+
+               if (date) {
+                       if (date instanceof Date) {
+                               parsedDate = DateMath.findMonthStart(date);
+                       } else {
+                               var month, year, aMonthYear;
+                               aMonthYear = date.split(this.cfg.getProperty(DEF_CFG.DATE_FIELD_DELIMITER.key));
+                               month = parseInt(aMonthYear[this.cfg.getProperty(DEF_CFG.MY_MONTH_POSITION.key)-1], 10)-1;
+                               year = parseInt(aMonthYear[this.cfg.getProperty(DEF_CFG.MY_YEAR_POSITION.key)-1], 10);
+
+                               parsedDate = DateMath.getDate(year, month, 1);
+                       }
+               } else {
+                       parsedDate = 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(DEF_CFG.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),
+                       rArray;
+       
+               if (aDate.length == 2) {
+                       rArray = [aDate[this.Locale.MD_MONTH_POSITION-1],aDate[this.Locale.MD_DAY_POSITION-1]];
+                       rArray.type = 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 = 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 = [],
+                       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),
+                                       dateStart = this._parseDate(aRange[0]),
+                                       dateEnd = this._parseDate(aRange[1]),
+                                       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 = DateMath.add(DateMath.getDate(startDate[0],startDate[1]-1,startDate[2]),DateMath.DAY,1),
+                       dEnd     = DateMath.getDate(endDate[0],  endDate[1]-1,  endDate[2]),
+                       results = [];
+
+               results.push(startDate);
+               while (dCurrent.getTime() <= dEnd.getTime()) {
+                       results.push([dCurrent.getFullYear(),dCurrent.getMonth()+1,dCurrent.getDate()]);
+                       dCurrent = DateMath.add(dCurrent,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(Calendar.RANGE,aDate,fnRender);
+                               } else { // this is a month/day combo
+                                       this._addRenderer(Calendar.MONTH_DAY,aDate,fnRender);
+                               }
+                       } else if (aDate.length == 3) {
+                               this._addRenderer(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(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(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) {
+                       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 = DEF_CFG.PAGEDATE.key,
+                       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 = DEF_CFG.PAGEDATE.key,
+                       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 = [],
+                       selected = this.cfg.getProperty(DEF_CFG.SELECTED.key);
+
+               for (var d=0;d<selected.length;++d) {
+                       var dateArray = selected[d];
+
+                       var date = 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;
+       },
+
+       /**
+        * Destroys the Calendar instance. The method will remove references
+        * to HTML elements, remove any event listeners added by the Calendar,
+        * and destroy the Config and CalendarNavigator instances it has created.
+        *
+        * @method destroy
+        */
+       destroy : function() {
+
+               if (this.beforeDestroyEvent.fire()) {
+                       var cal = this;
+
+                       // Child objects
+                       if (cal.navigator) {
+                               cal.navigator.destroy();
+                       }
+
+                       if (cal.cfg) {
+                               cal.cfg.destroy();
+                       }
+
+                       // DOM event listeners
+                       Event.purgeElement(cal.oDomContainer, true);
+
+                       // Generated markup/DOM - Not removing the container DIV since we didn't create it.
+                       Dom.removeClass(cal.oDomContainer, "withtitle");
+                       Dom.removeClass(cal.oDomContainer, cal.Style.CSS_CONTAINER);
+                       Dom.removeClass(cal.oDomContainer, cal.Style.CSS_SINGLE);
+                       cal.oDomContainer.innerHTML = "";
+
+                       // JS-to-DOM references
+                       cal.oDomContainer = null;
+                       cal.cells = null;
+
+                       this.destroyEvent.fire();
+               }
+       }
+};
+
+YAHOO.widget.Calendar = Calendar;
+
+/**
+* @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;
+
+})();
+
+(function() {
+
+       var Dom = YAHOO.util.Dom,
+               DateMath = YAHOO.widget.DateMath,
+               Event = YAHOO.util.Event,
+               Lang = YAHOO.lang,
+               Calendar = 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.
+*/
+function CalendarGroup(id, containerId, config) {
+       if (arguments.length > 0) {
+               this.init.apply(this, arguments);
+       }
+}
+
+/**
+* The set of default Config property keys and values for the CalendarGroup
+* @property YAHOO.widget.CalendarGroup._DEFAULT_CONFIG
+* @final
+* @static
+* @private
+* @type Object
+*/
+CalendarGroup._DEFAULT_CONFIG = Calendar._DEFAULT_CONFIG;
+CalendarGroup._DEFAULT_CONFIG.PAGES = {key:"pages", value:2};
+
+var DEF_CFG = CalendarGroup._DEFAULT_CONFIG;
+
+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 = Dom.get(container);
+               if (!this.oDomContainer) { this.logger.log("Container not found in document.", "error"); }
+
+               if (!this.oDomContainer.id) {
+                       this.oDomContainer.id = 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.logger = new YAHOO.widget.LogWriter("CalendarGroup " + this.id);
+               this.initEvents();
+               this.initStyles();
+
+               /**
+               * The collection of Calendar pages contained within the CalendarGroup
+               * @property pages
+               * @type YAHOO.widget.Calendar[]
+               */
+               this.pages = [];
+
+               Dom.addClass(this.oDomContainer, CalendarGroup.CSS_CONTAINER);
+               Dom.addClass(this.oDomContainer, 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);
+               }
+
+               this.logger.log("Initialized " + this.pages.length + "-page CalendarGroup", "info");
+       },
+
+       setupConfig : function() {
+
+               var cfg = this.cfg;
+
+               /**
+               * 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
+               */
+               cfg.addProperty(DEF_CFG.PAGES.key, { value:DEF_CFG.PAGES.value, validator:cfg.checkNumber, handler:this.configPages } );
+
+               /**
+               * The month/year representing the current visible Calendar date (mm/yyyy)
+               * @config pagedate
+               * @type String | Date
+               * @default today's date
+               */
+               cfg.addProperty(DEF_CFG.PAGEDATE.key, { value:new Date(), handler:this.configPageDate } );
+
+               /**
+               * The date or range of dates representing the current Calendar selection
+               *
+               * @config selected
+               * @type String
+               * @default []
+               */
+               cfg.addProperty(DEF_CFG.SELECTED.key, { value:[], handler:this.configSelected } );
+
+               /**
+               * The title to display above the CalendarGroup's month header
+               * @config title
+               * @type String
+               * @default ""
+               */
+               cfg.addProperty(DEF_CFG.TITLE.key, { value:DEF_CFG.TITLE.value, handler:this.configTitle } );
+
+               /**
+               * Whether or not a close button should be displayed for this CalendarGroup
+               * @config close
+               * @type Boolean
+               * @default false
+               */
+               cfg.addProperty(DEF_CFG.CLOSE.key, { value:DEF_CFG.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
+               */
+               cfg.addProperty(DEF_CFG.IFRAME.key, { value:DEF_CFG.IFRAME.value, handler:this.configIframe, validator:cfg.checkBoolean } );
+       
+               /**
+               * The minimum selectable date in the current Calendar (mm/dd/yyyy)
+               * @config mindate
+               * @type String | Date
+               * @default null
+               */
+               cfg.addProperty(DEF_CFG.MINDATE.key, { value:DEF_CFG.MINDATE.value, handler:this.delegateConfig } );
+       
+               /**
+               * The maximum selectable date in the current Calendar (mm/dd/yyyy)
+               * @config maxdate
+               * @type String | Date
+               * @default null
+               */
+               cfg.addProperty(DEF_CFG.MAXDATE.key, { value:DEF_CFG.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
+               */
+               cfg.addProperty(DEF_CFG.MULTI_SELECT.key,       { value:DEF_CFG.MULTI_SELECT.value, handler:this.delegateConfig, validator:cfg.checkBoolean } );
+
+               /**
+               * The weekday the week begins on. Default is 0 (Sunday).
+               * @config START_WEEKDAY
+               * @type number
+               * @default 0
+               */      
+               cfg.addProperty(DEF_CFG.START_WEEKDAY.key,      { value:DEF_CFG.START_WEEKDAY.value, handler:this.delegateConfig, validator:cfg.checkNumber  } );
+               
+               /**
+               * True if the Calendar should show weekday labels. True by default.
+               * @config SHOW_WEEKDAYS
+               * @type Boolean
+               * @default true
+               */      
+               cfg.addProperty(DEF_CFG.SHOW_WEEKDAYS.key,      { value:DEF_CFG.SHOW_WEEKDAYS.value, handler:this.delegateConfig, validator:cfg.checkBoolean } );
+               
+               /**
+               * True if the Calendar should show week row headers. False by default.
+               * @config SHOW_WEEK_HEADER
+               * @type Boolean
+               * @default false
+               */      
+               cfg.addProperty(DEF_CFG.SHOW_WEEK_HEADER.key,{ value:DEF_CFG.SHOW_WEEK_HEADER.value, handler:this.delegateConfig, validator:cfg.checkBoolean } );
+               
+               /**
+               * True if the Calendar should show week row footers. False by default.
+               * @config SHOW_WEEK_FOOTER
+               * @type Boolean
+               * @default false
+               */
+               cfg.addProperty(DEF_CFG.SHOW_WEEK_FOOTER.key,{ value:DEF_CFG.SHOW_WEEK_FOOTER.value, handler:this.delegateConfig, validator: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
+               */              
+               cfg.addProperty(DEF_CFG.HIDE_BLANK_WEEKS.key,{ value:DEF_CFG.HIDE_BLANK_WEEKS.value, handler:this.delegateConfig, validator: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
+               */              
+               cfg.addProperty(DEF_CFG.NAV_ARROW_LEFT.key,     { value:DEF_CFG.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
+               */              
+               cfg.addProperty(DEF_CFG.NAV_ARROW_RIGHT.key,    { value:DEF_CFG.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"]
+               */
+               cfg.addProperty(DEF_CFG.MONTHS_SHORT.key,       { value:DEF_CFG.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"
+               */              
+               cfg.addProperty(DEF_CFG.MONTHS_LONG.key,                { value:DEF_CFG.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"]
+               */              
+               cfg.addProperty(DEF_CFG.WEEKDAYS_1CHAR.key,     { value:DEF_CFG.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"]
+               */              
+               cfg.addProperty(DEF_CFG.WEEKDAYS_SHORT.key,     { value:DEF_CFG.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"]
+               */              
+               cfg.addProperty(DEF_CFG.WEEKDAYS_MEDIUM.key,    { value:DEF_CFG.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"]
+               */              
+               cfg.addProperty(DEF_CFG.WEEKDAYS_LONG.key,      { value:DEF_CFG.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"
+               */
+               cfg.addProperty(DEF_CFG.LOCALE_MONTHS.key,      { value:DEF_CFG.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"
+               */      
+               cfg.addProperty(DEF_CFG.LOCALE_WEEKDAYS.key,    { value:DEF_CFG.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 ","
+               */
+               cfg.addProperty(DEF_CFG.DATE_DELIMITER.key,             { value:DEF_CFG.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 "/"
+               */      
+               cfg.addProperty(DEF_CFG.DATE_FIELD_DELIMITER.key,{ value:DEF_CFG.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 "-"
+               */
+               cfg.addProperty(DEF_CFG.DATE_RANGE_DELIMITER.key,{ value:DEF_CFG.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
+               */
+               cfg.addProperty(DEF_CFG.MY_MONTH_POSITION.key,  { value:DEF_CFG.MY_MONTH_POSITION.value, handler:this.delegateConfig, validator:cfg.checkNumber } );
+               
+               /**
+               * The position of the year in a month/year date string
+               * @config MY_YEAR_POSITION
+               * @type Number
+               * @default 2
+               */      
+               cfg.addProperty(DEF_CFG.MY_YEAR_POSITION.key,   { value:DEF_CFG.MY_YEAR_POSITION.value, handler:this.delegateConfig, validator:cfg.checkNumber } );
+               
+               /**
+               * The position of the month in a month/day date string
+               * @config MD_MONTH_POSITION
+               * @type Number
+               * @default 1
+               */      
+               cfg.addProperty(DEF_CFG.MD_MONTH_POSITION.key,  { value:DEF_CFG.MD_MONTH_POSITION.value, handler:this.delegateConfig, validator:cfg.checkNumber } );
+               
+               /**
+               * The position of the day in a month/year date string
+               * @config MD_DAY_POSITION
+               * @type Number
+               * @default 2
+               */      
+               cfg.addProperty(DEF_CFG.MD_DAY_POSITION.key,            { value:DEF_CFG.MD_DAY_POSITION.value, handler:this.delegateConfig, validator:cfg.checkNumber } );
+               
+               /**
+               * The position of the month in a month/day/year date string
+               * @config MDY_MONTH_POSITION
+               * @type Number
+               * @default 1
+               */      
+               cfg.addProperty(DEF_CFG.MDY_MONTH_POSITION.key, { value:DEF_CFG.MDY_MONTH_POSITION.value, handler:this.delegateConfig, validator:cfg.checkNumber } );
+               
+               /**
+               * The position of the day in a month/day/year date string
+               * @config MDY_DAY_POSITION
+               * @type Number
+               * @default 2
+               */      
+               cfg.addProperty(DEF_CFG.MDY_DAY_POSITION.key,   { value:DEF_CFG.MDY_DAY_POSITION.value, handler:this.delegateConfig, validator:cfg.checkNumber } );
+               
+               /**
+               * The position of the year in a month/day/year date string
+               * @config MDY_YEAR_POSITION
+               * @type Number
+               * @default 3
+               */      
+               cfg.addProperty(DEF_CFG.MDY_YEAR_POSITION.key,  { value:DEF_CFG.MDY_YEAR_POSITION.value, handler:this.delegateConfig, validator: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
+               */
+               cfg.addProperty(DEF_CFG.MY_LABEL_MONTH_POSITION.key,    { value:DEF_CFG.MY_LABEL_MONTH_POSITION.value, handler:this.delegateConfig, validator: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
+               */
+               cfg.addProperty(DEF_CFG.MY_LABEL_YEAR_POSITION.key,     { value:DEF_CFG.MY_LABEL_YEAR_POSITION.value, handler:this.delegateConfig, validator:cfg.checkNumber } );
+
+               /**
+               * The suffix used after the month when rendering the Calendar header
+               * @config MY_LABEL_MONTH_SUFFIX
+               * @type String
+               * @default " "
+               */
+               cfg.addProperty(DEF_CFG.MY_LABEL_MONTH_SUFFIX.key,      { value:DEF_CFG.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 ""
+               */
+               cfg.addProperty(DEF_CFG.MY_LABEL_YEAR_SUFFIX.key, { value:DEF_CFG.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
+               */
+               cfg.addProperty(DEF_CFG.NAV.key, { value:DEF_CFG.NAV.value, handler:this.configNavigator } );
+
+               /**
+                * The map of UI strings which the CalendarGroup UI uses.
+                *
+                * @config strings
+                * @type {Object}
+                * @default An object with the properties shown below:
+                *     <dl>
+                *         <dt>previousMonth</dt><dd><em>String</em> : The string to use for the "Previous Month" navigation UI. Defaults to "Previous Month".</dd>
+                *         <dt>nextMonth</dt><dd><em>String</em> : The string to use for the "Next Month" navigation UI. Defaults to "Next Month".</dd>
+                *         <dt>close</dt><dd><em>String</em> : The string to use for the close button label. Defaults to "Close".</dd>
+                *     </dl>
+                */
+               cfg.addProperty(DEF_CFG.STRINGS.key, { 
+                       value:DEF_CFG.STRINGS.value, 
+                       handler:this.configStrings, 
+                       validator: function(val) {
+                               return Lang.isObject(val);
+                       },
+                       supercedes: DEF_CFG.STRINGS.supercedes
+               });
+       },
+
+       /**
+       * Initializes CalendarGroup's built-in CustomEvents
+       * @method initEvents
+       */
+       initEvents : function() {
+
+               var me = this,
+                       strEvent = "Event",
+                       CE = YAHOO.util.CustomEvent;
+
+               /**
+               * 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 = Calendar._EVENT_TYPES;
+
+               /**
+               * Fired before a date selection is made
+               * @event beforeSelectEvent
+               */
+               me.beforeSelectEvent = new CE(defEvents.BEFORE_SELECT);
+               me.beforeSelectEvent.subscribe = sub; me.beforeSelectEvent.unsubscribe = unsub;
+
+               /**
+               * Fired when a date selection is made
+               * @event selectEvent
+               * @param {Array}        Array of Date field arrays in the format [YYYY, MM, DD].
+               */
+               me.selectEvent = new CE(defEvents.SELECT); 
+               me.selectEvent.subscribe = sub; me.selectEvent.unsubscribe = unsub;
+
+               /**
+               * Fired before a date or set of dates is deselected
+               * @event beforeDeselectEvent
+               */
+               me.beforeDeselectEvent = new CE(defEvents.BEFORE_DESELECT); 
+               me.beforeDeselectEvent.subscribe = sub; me.beforeDeselectEvent.unsubscribe = unsub;
+
+               /**
+               * Fired when a date or set of dates has been deselected
+               * @event deselectEvent
+               * @param {Array}        Array of Date field arrays in the format [YYYY, MM, DD].
+               */
+               me.deselectEvent = new CE(defEvents.DESELECT); 
+               me.deselectEvent.subscribe = sub; me.deselectEvent.unsubscribe = unsub;
+               
+               /**
+               * Fired when the Calendar page is changed
+               * @event changePageEvent
+               */
+               me.changePageEvent = new CE(defEvents.CHANGE_PAGE); 
+               me.changePageEvent.subscribe = sub; me.changePageEvent.unsubscribe = unsub;
+
+               /**
+               * Fired before the Calendar is rendered
+               * @event beforeRenderEvent
+               */
+               me.beforeRenderEvent = new CE(defEvents.BEFORE_RENDER);
+               me.beforeRenderEvent.subscribe = sub; me.beforeRenderEvent.unsubscribe = unsub;
+       
+               /**
+               * Fired when the Calendar is rendered
+               * @event renderEvent
+               */
+               me.renderEvent = new CE(defEvents.RENDER);
+               me.renderEvent.subscribe = sub; me.renderEvent.unsubscribe = unsub;
+       
+               /**
+               * Fired when the Calendar is reset
+               * @event resetEvent
+               */
+               me.resetEvent = new CE(defEvents.RESET); 
+               me.resetEvent.subscribe = sub; me.resetEvent.unsubscribe = unsub;
+       
+               /**
+               * Fired when the Calendar is cleared
+               * @event clearEvent
+               */
+               me.clearEvent = new CE(defEvents.CLEAR);
+               me.clearEvent.subscribe = sub; me.clearEvent.unsubscribe = unsub;
+
+               /**
+               * Fired just before the CalendarGroup is to be shown
+               * @event beforeShowEvent
+               */
+               me.beforeShowEvent = new CE(defEvents.BEFORE_SHOW);
+       
+               /**
+               * Fired after the CalendarGroup is shown
+               * @event showEvent
+               */
+               me.showEvent = new CE(defEvents.SHOW);
+       
+               /**
+               * Fired just before the CalendarGroup is to be hidden
+               * @event beforeHideEvent
+               */
+               me.beforeHideEvent = new CE(defEvents.BEFORE_HIDE);
+       
+               /**
+               * Fired after the CalendarGroup is hidden
+               * @event hideEvent
+               */
+               me.hideEvent = new CE(defEvents.HIDE);
+
+               /**
+               * Fired just before the CalendarNavigator is to be shown
+               * @event beforeShowNavEvent
+               */
+               me.beforeShowNavEvent = new CE(defEvents.BEFORE_SHOW_NAV);
+       
+               /**
+               * Fired after the CalendarNavigator is shown
+               * @event showNavEvent
+               */
+               me.showNavEvent = new CE(defEvents.SHOW_NAV);
+       
+               /**
+               * Fired just before the CalendarNavigator is to be hidden
+               * @event beforeHideNavEvent
+               */
+               me.beforeHideNavEvent = new CE(defEvents.BEFORE_HIDE_NAV);
+
+               /**
+               * Fired after the CalendarNavigator is hidden
+               * @event hideNavEvent
+               */
+               me.hideNavEvent = new CE(defEvents.HIDE_NAV);
+
+               /**
+               * Fired just before the CalendarNavigator is to be rendered
+               * @event beforeRenderNavEvent
+               */
+               me.beforeRenderNavEvent = new CE(defEvents.BEFORE_RENDER_NAV);
+
+               /**
+               * Fired after the CalendarNavigator is rendered
+               * @event renderNavEvent
+               */
+               me.renderNavEvent = new CE(defEvents.RENDER_NAV);
+
+               /**
+               * Fired just before the CalendarGroup is to be destroyed
+               * @event beforeDestroyEvent
+               */
+               me.beforeDestroyEvent = new CE(defEvents.BEFORE_DESTROY);
+
+               /**
+               * Fired after the CalendarGroup is destroyed. This event should be used
+               * for notification only. When this event is fired, important CalendarGroup instance
+               * properties, dom references and event listeners have already been 
+               * removed/dereferenced, and hence the CalendarGroup instance is not in a usable 
+               * state.
+               *
+               * @event destroyEvent
+               */
+               me.destroyEvent = new CE(defEvents.DESTROY);
+       },
+       
+       /**
+       * 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],
+                       cfgPageDate = DEF_CFG.PAGEDATE.key,
+                       sep = "_",
+                       caldate,
+                       firstPageDate = null,
+                       groupCalClass = "groupcal",
+                       firstClass = "first-of-type",
+                       lastClass = "last-of-type";
+
+               for (var p=0;p<pageCount;++p) {
+                       var calId = this.id + sep + p,
+                               calContainerId = this.containerId + sep + p,
+                               childConfig = this.cfg.getConfig();
+
+                       childConfig.close = false;
+                       childConfig.title = false;
+                       childConfig.navigator = null;
+
+                       if (p > 0) {
+                               caldate = new Date(firstPageDate);
+                               this._setMonthOnDate(caldate, caldate.getMonth() + p);
+                               childConfig.pageDate = caldate;
+                       }
+
+                       var cal = this.constructChild(calId, calContainerId, childConfig);
+
+                       Dom.removeClass(cal.oDomContainer, this.Style.CSS_SINGLE);
+                       Dom.addClass(cal.oDomContainer, groupCalClass);
+
+                       if (p===0) {
+                               firstPageDate = cal.cfg.getProperty(cfgPageDate);
+                               Dom.addClass(cal.oDomContainer, firstClass);
+                       }
+       
+                       if (p==(pageCount-1)) {
+                               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],
+                       firstPageDate;
+
+               var cfgPageDate = DEF_CFG.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 = DEF_CFG.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(DEF_CFG.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(DEF_CFG.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 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 = DEF_CFG.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 = DEF_CFG.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();
+               }
+
+               this.cfg.setProperty(DEF_CFG.SELECTED.key, []);
+               this.cfg.setProperty(DEF_CFG.PAGEDATE.key, new Date(this.pages[0].today.getTime()));
+               this.render();
+       },
+
+       /**
+       * 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(DEF_CFG.SELECTED.key);
+               for (var d=0;d<selected.length;++d) {
+                       var dateArray = selected[d];
+
+                       var date = 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 newDate = DateMath.add(date, DateMath.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;
+       },
+
+       /**
+        * Destroys the CalendarGroup instance. The method will remove references
+        * to HTML elements, remove any event listeners added by the CalendarGroup.
+        * 
+        * It will also destroy the Config and CalendarNavigator instances created by the 
+        * CalendarGroup and the individual Calendar instances created for each page.
+        *
+        * @method destroy
+        */
+       destroy : function() {
+
+               if (this.beforeDestroyEvent.fire()) {
+
+                       var cal = this;
+       
+                       // Child objects
+                       if (cal.navigator) {
+                               cal.navigator.destroy();
+                       }
+       
+                       if (cal.cfg) {
+                               cal.cfg.destroy();
+                       }
+       
+                       // DOM event listeners
+                       Event.purgeElement(cal.oDomContainer, true);
+       
+                       // Generated markup/DOM - Not removing the container DIV since we didn't create it.
+                       Dom.removeClass(cal.oDomContainer, CalendarGroup.CSS_CONTAINER);
+                       Dom.removeClass(cal.oDomContainer, CalendarGroup.CSS_MULTI_UP);
+                       
+                       for (var i = 0, l = cal.pages.length; i < l; i++) {
+                               cal.pages[i].destroy();
+                               cal.pages[i] = null;
+                       }
+       
+                       cal.oDomContainer.innerHTML = "";
+       
+                       // JS-to-DOM references
+                       cal.oDomContainer = null;
+       
+                       this.destroyEvent.fire();
+               }
+       }
+};
+
+/**
+* CSS class representing the container for the calendar
+* @property YAHOO.widget.CalendarGroup.CSS_CONTAINER
+* @static
+* @final
+* @type String
+*/
+CalendarGroup.CSS_CONTAINER = "yui-calcontainer";
+
+/**
+* CSS class representing the container for the calendar
+* @property YAHOO.widget.CalendarGroup.CSS_MULTI_UP
+* @static
+* @final
+* @type String
+*/
+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
+*/
+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
+*/
+CalendarGroup.CSS_2UPCLOSE = "close-icon";
+
+YAHOO.lang.augmentProto(CalendarGroup, Calendar, "buildDayLabel",
+                                                                                                "buildMonthLabel",
+                                                                                                "renderOutOfBoundsDate",
+                                                                                                "renderRowHeader",
+                                                                                                "renderRowFooter",
+                                                                                                "renderCellDefault",
+                                                                                                "styleCellDefault",
+                                                                                                "renderCellStyleHighlight1",
+                                                                                                "renderCellStyleHighlight2",
+                                                                                                "renderCellStyleHighlight3",
+                                                                                                "renderCellStyleHighlight4",
+                                                                                                "renderCellStyleToday",
+                                                                                                "renderCellStyleSelected",
+                                                                                                "renderCellNotThisMonth",
+                                                                                                "renderBodyCellRestricted",
+                                                                                                "initStyles",
+                                                                                                "configTitle",
+                                                                                                "configClose",
+                                                                                                "configIframe",
+                                                                                                "configStrings",
+                                                                                                "configNavigator",
+                                                                                                "createTitleBar",
+                                                                                                "createCloseButton",
+                                                                                                "removeTitleBar",
+                                                                                                "removeCloseButton",
+                                                                                                "hide",
+                                                                                                "show",
+                                                                                                "toDate",
+                                                                                                "_toDate",
+                                                                                                "_parseArgs",
+                                                                                                "browser");
+
+YAHOO.widget.CalGrp = CalendarGroup;
+YAHOO.widget.CalendarGroup = 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, 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 IE Quirks
+                * @private
+                * @property __isIEQuirks
+                */
+               var ie = YAHOO.env.ua.ie;
+               this.__isIEQuirks = (ie && ((ie <= 6) || (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 or IE in 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;
+
+                       // Artificial delay, just to help the user see something changed
+                       var delay = YAHOO.widget.CalendarNavigator.UPDATE_DELAY;
+                       if (delay > 0) {
+                               var nav = this;
+                               window.setTimeout(function(){ nav._update(cal); }, delay);
+                       } else {
+                               this._update(cal);
+                       }
+               }
+       },
+
+       /**
+        * Updates the Calendar rendered state, based on the state of the CalendarNavigator
+        * @method _update
+        * @param cal The Calendar instance to update
+        * @protected
+        */
+       _update : function(cal) {
+               cal.setYear(this.getYear());
+               cal.setMonth(this.getMonth());
+               cal.render();
+       },
+
+       /**
+        * 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,
+                       f = this.__getCfg("initialFocus");
+
+               if (f && f.toLowerCase) {
+                       f = f.toLowerCase();
+                       if (f == "year") {
+                               el = this.yearEl;
+                               try {
+                                       this.yearEl.select();
+                               } catch (selErr) {
+                                       // Ignore;
+                               }
+                       } else if (f == "month") {
+                               el = this.monthEl;
+                       }
+               }
+
+               if (el && YAHOO.lang.isFunction(el.focus)) {
+                       try {
+                               el.focus();
+                       } catch (focusErr) {
+                               // 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,
+                       KEYS = YAHOO.util.KeyListener.KEY,
+                       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(err) {
+                                       // 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,
+                       KEYS = YAHOO.util.KeyListener.KEY;
+
+               if (E.getCharCode(e) == KEYS.TAB && !e.shiftKey) {
+                       try {
+                               E.preventDefault(e);
+                               this.firstCtrl.focus();
+                       } catch (err) {
+                               // 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,
+                       KEYS = YAHOO.util.KeyListener.KEY;
+
+               if (e.shiftKey && E.getCharCode(e) == KEYS.TAB) {
+                       try {
+                               E.preventDefault(e);
+                               this.lastCtrl.focus();
+                       } catch (err) {
+                               // 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.7.0", build: "1799"});