Show:
                            /**
                             * The CalendarBase submodule is a basic UI calendar view that displays
                             * a range of dates in a two-dimensional month grid, with one or more
                             * months visible at a single time. CalendarBase supports custom date
                             * rendering, multiple calendar panes, and selection.
                             * @module calendar
                             * @submodule calendar-base
                             */
                            
                            var getCN                 = Y.ClassNameManager.getClassName,
                                CALENDAR              = 'calendar',
                                CAL_GRID              = getCN(CALENDAR, 'grid'),
                                CAL_LEFT_GRID         = getCN(CALENDAR, 'left-grid'),
                                CAL_RIGHT_GRID        = getCN(CALENDAR, 'right-grid'),
                                CAL_BODY              = getCN(CALENDAR, 'body'),
                                CAL_HD                = getCN(CALENDAR, 'header'),
                                CAL_HD_LABEL          = getCN(CALENDAR, 'header-label'),
                                CAL_WDAYROW           = getCN(CALENDAR, 'weekdayrow'),
                                CAL_WDAY              = getCN(CALENDAR, 'weekday'),
                                CAL_COL_HIDDEN        = getCN(CALENDAR, 'column-hidden'),
                                CAL_DAY_SELECTED      = getCN(CALENDAR, 'day-selected'),
                                SELECTION_DISABLED    = getCN(CALENDAR, 'selection-disabled'),
                                CAL_ROW               = getCN(CALENDAR, 'row'),
                                CAL_DAY               = getCN(CALENDAR, 'day'),
                                CAL_PREVMONTH_DAY     = getCN(CALENDAR, 'prevmonth-day'),
                                CAL_NEXTMONTH_DAY     = getCN(CALENDAR, 'nextmonth-day'),
                                CAL_ANCHOR            = getCN(CALENDAR, 'anchor'),
                                CAL_PANE              = getCN(CALENDAR, 'pane'),
                                CAL_STATUS            = getCN(CALENDAR, 'status'),
                                L           = Y.Lang,
                                substitute  = L.sub,
                                arrayEach   = Y.Array.each,
                                objEach     = Y.Object.each,
                                iOf         = Y.Array.indexOf,
                                hasKey      = Y.Object.hasKey,
                                setVal      = Y.Object.setValue,
                                isEmpty     = Y.Object.isEmpty,
                                ydate       = Y.DataType.Date;
                            
                            /** Create a calendar view to represent a single or multiple
                                * month range of dates, rendered as a grid with date and
                                * weekday labels.
                                *
                                * @class CalendarBase
                                * @extends Widget
                                * @param config {Object} Configuration object (see Configuration
                                * attributes)
                                * @constructor
                                */
                            function CalendarBase() {
                                CalendarBase.superclass.constructor.apply ( this, arguments );
                            }
                            
                            
                            
                            Y.CalendarBase = Y.extend( CalendarBase, Y.Widget, {
                            
                                /**
                                 * A storage for various properties of individual month
                                 * panes.
                                 *
                                 * @property _paneProperties
                                 * @type Object
                                 * @private
                                 */
                                _paneProperties : {},
                            
                                /**
                                 * The number of month panes in the calendar, deduced
                                 * from the CONTENT_TEMPLATE's number of {calendar_grid}
                                 * tokens.
                                 *
                                 * @property _paneNumber
                                 * @type Number
                                 * @private
                                 */
                                _paneNumber : 1,
                            
                                /**
                                 * The unique id used to prefix various elements of this
                                 * calendar instance.
                                 *
                                 * @property _calendarId
                                 * @type String
                                 * @private
                                 */
                                _calendarId : null,
                            
                                /**
                                 * The hash map of selected dates, populated with
                                 * selectDates() and deselectDates() methods
                                 *
                                 * @property _selectedDates
                                 * @type Object
                                 * @private
                                 */
                                _selectedDates : {},
                            
                                /**
                                 * A private copy of the rules object, populated
                                 * by setting the customRenderer attribute.
                                 *
                                 * @property _rules
                                 * @type Object
                                 * @private
                                 */
                                _rules : {},
                            
                                /**
                                 * A private copy of the filterFunction, populated
                                 * by setting the customRenderer attribute.
                                 *
                                 * @property _filterFunction
                                 * @type Function
                                 * @private
                                 */
                                _filterFunction : null,
                            
                                /**
                                 * Storage for calendar cells modified by any custom
                                 * formatting. The storage is cleared, used to restore
                                 * cells to the original state, and repopulated accordingly
                                 * when the calendar is rerendered.
                                 *
                                 * @property _storedDateCells
                                 * @type Object
                                 * @private
                                 */
                                _storedDateCells : {},
                            
                                /**
                                 * Designated initializer
                                 * Initializes instance-level properties of
                                 * calendar.
                                 *
                                 * @method initializer
                                 */
                                initializer : function () {
                                    this._paneProperties = {};
                                    this._calendarId = Y.guid('calendar');
                                    this._selectedDates = {};
                                    if (isEmpty(this._rules)) {
                                         this._rules = {};
                                    }
                                    this._storedDateCells = {};
                                },
                            
                                /**
                                 * renderUI implementation
                                 *
                                 * Creates a visual representation of the calendar based on existing parameters.
                                 * @method renderUI
                                 */
                                renderUI : function () {
                            
                                    var contentBox = this.get('contentBox');
                                    contentBox.appendChild(this._initCalendarHTML(this.get('date')));
                            
                                    if (this.get('showPrevMonth')) {
                                            this._afterShowPrevMonthChange();
                                    }
                                    if (this.get('showNextMonth')) {
                                            this._afterShowNextMonthChange();
                                    }
                            
                                    this._renderCustomRules();
                                    this._renderSelectedDates();
                            
                                    this.get("boundingBox").setAttribute("aria-labelledby", this._calendarId + "_header");
                            
                                },
                            
                                /**
                                 * bindUI implementation
                                 *
                                 * Assigns listeners to relevant events that change the state
                                 * of the calendar.
                                 * @method bindUI
                                 */
                                bindUI : function () {
                                    this.after('dateChange', this._afterDateChange);
                                    this.after('showPrevMonthChange', this._afterShowPrevMonthChange);
                                    this.after('showNextMonthChange', this._afterShowNextMonthChange);
                                    this.after('headerRendererChange', this._afterHeaderRendererChange);
                                    this.after('customRendererChange', this._afterCustomRendererChange);
                                    this.after('enabledDatesRuleChange', this._afterCustomRendererChange);
                                    this.after('disabledDatesRuleChange', this._afterCustomRendererChange);
                                    this.after('focusedChange', this._afterFocusedChange);
                                    this.after('selectionChange', this._renderSelectedDates);
                                    this._bindCalendarEvents();
                                },
                            
                            
                                /**
                                 * An internal utility method that generates a list of selected dates
                                 * from the hash storage.
                                 *
                                 * @method _getSelectedDatesList
                                 * @protected
                                 * @return {Array} The array of `Date`s that are currently selected.
                                 */
                                _getSelectedDatesList : function () {
                                    var output = [];
                            
                                    objEach (this._selectedDates, function (year) {
                                        objEach (year, function (month) {
                                            objEach (month, function (day) {
                                                output.push (day);
                                            }, this);
                                        }, this);
                                    }, this);
                            
                                    return output;
                                },
                            
                                /**
                                 * A utility method that returns all dates selected in a specific month.
                                 *
                                 * @method _getSelectedDatesInMonth
                                 * @param {Date} oDate corresponding to the month for which selected dates
                                 * are requested.
                                 * @protected
                                 * @return {Array} The array of `Date`s in a given month that are currently selected.
                                 */
                                _getSelectedDatesInMonth : function (oDate) {
                                    var year = oDate.getFullYear(),
                                        month = oDate.getMonth();
                            
                                    if (hasKey(this._selectedDates, year) && hasKey(this._selectedDates[year], month)) {
                                        return Y.Object.values(this._selectedDates[year][month]);
                                    } else {
                                        return [];
                                    }
                                },
                            
                            
                                /**
                                 * An internal parsing method that receives a String list of numbers
                                 * and number ranges (of the form "1,2,3,4-6,7-9,10,11" etc.) and checks
                                 * whether a specific number is included in this list. Used for looking
                                 * up dates in the customRenderer rule set.
                                 *
                                 * @method _isNumInList
                                 * @param {Number} num The number to look for in a list.
                                 * @param {String} strList The list of numbers of the form "1,2,3,4-6,7-8,9", etc.
                                 * @private
                                 * @return {boolean} Returns true if the given number is in the given list.
                                 */
                                _isNumInList : function (num, strList) {
                                    if (strList === "all") {
                                        return true;
                                    } else {
                                        var elements = strList.split(","),
                                            i = elements.length,
                                            range;
                            
                                        while (i--) {
                                            range = elements[i].split("-");
                                            if (range.length === 2 && num >= parseInt(range[0], 10) && num <= parseInt(range[1], 10)) {
                                                return true;
                                            }
                                            else if (range.length === 1 && (parseInt(elements[i], 10) === num)) {
                                                return true;
                                            }
                                        }
                                        return false;
                                    }
                                },
                            
                                /**
                                 * Given a specific date, returns an array of rules (from the customRenderer rule set)
                                 * that the given date matches.
                                 *
                                 * @method _getRulesForDate
                                 * @param {Date} oDate The date for which an array of rules is needed
                                 * @private
                                 * @return {Array} Returns an array of `String`s, each containg the name of
                                 * a rule that the given date matches.
                                 */
                                _getRulesForDate : function (oDate) {
                                    var year = oDate.getFullYear(),
                                            month = oDate.getMonth(),
                                            date = oDate.getDate(),
                                            wday = oDate.getDay(),
                                            rules = this._rules,
                                            outputRules = [],
                                            years, months, dates, days;
                            
                                    for (years in rules) {
                                        if (this._isNumInList(year, years)) {
                                            if (L.isString(rules[years])) {
                                                    outputRules.push(rules[years]);
                                            }
                                            else {
                                                for (months in rules[years]) {
                                                    if (this._isNumInList(month, months)) {
                                                        if (L.isString(rules[years][months])) {
                                                                outputRules.push(rules[years][months]);
                                                        }
                                                        else {
                                                            for (dates in rules[years][months]) {
                                                                if (this._isNumInList(date, dates)) {
                                                                    if (L.isString(rules[years][months][dates])) {
                                                                            outputRules.push(rules[years][months][dates]);
                                                                    }
                                                                    else {
                                                                        for (days in rules[years][months][dates]) {
                                                                            if (this._isNumInList(wday, days)) {
                                                                                if (L.isString(rules[years][months][dates][days])) {
                                                                                    outputRules.push(rules[years][months][dates][days]);
                                                                                }
                                                                            }
                                                                        }
                                                                    }
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                    return outputRules;
                                },
                            
                                /**
                                 * A utility method which, given a specific date and a name of the rule,
                                 * checks whether the date matches the given rule.
                                 *
                                 * @method _matchesRule
                                 * @param {Date} oDate The date to check
                                 * @param {String} rule The name of the rule that the date should match.
                                 * @private
                                 * @return {boolean} Returns true if the date matches the given rule.
                                 *
                                 */
                                _matchesRule : function (oDate, rule) {
                                    return (iOf(this._getRulesForDate(oDate), rule) >= 0);
                                },
                            
                                /**
                                 * A utility method which checks whether a given date matches the `enabledDatesRule`
                                 * or does not match the `disabledDatesRule` and therefore whether it can be selected.
                                 * @method _canBeSelected
                                 * @param {Date} oDate The date to check
                                 * @private
                                 * @return {boolean} Returns true if the date can be selected; false otherwise.
                                 */
                                _canBeSelected : function (oDate) {
                            
                                    var enabledDatesRule = this.get("enabledDatesRule"),
                                        disabledDatesRule = this.get("disabledDatesRule");
                            
                                    if (enabledDatesRule) {
                                        return this._matchesRule(oDate, enabledDatesRule);
                                    } else if (disabledDatesRule) {
                                        return !this._matchesRule(oDate, disabledDatesRule);
                                    } else {
                                        return true;
                                    }
                                },
                            
                                /**
                                 * Selects a given date or array of dates.
                                 * @method selectDates
                                 * @param {Date|Array} dates A `Date` or `Array` of `Date`s.
                                 * @return {CalendarBase} A reference to this object
                                 * @chainable
                                 */
                                selectDates : function (dates) {
                                    if (ydate.isValidDate(dates)) {
                                        this._addDateToSelection(dates);
                                    }
                                    else if (L.isArray(dates)) {
                                        this._addDatesToSelection(dates);
                                    }
                                    return this;
                                },
                            
                                /**
                                 * Deselects a given date or array of dates, or deselects
                                 * all dates if no argument is specified.
                                 * @method deselectDates
                                 * @param {Date|Array} [dates] A `Date` or `Array` of `Date`s, or no
                                 * argument if all dates should be deselected.
                                 * @return {CalendarBase} A reference to this object
                                 * @chainable
                                 */
                                deselectDates : function (dates) {
                                    if (!dates) {
                                        this._clearSelection();
                                    }
                                    else if (ydate.isValidDate(dates)) {
                                        this._removeDateFromSelection(dates);
                                    }
                                    else if (L.isArray(dates)) {
                                        this._removeDatesFromSelection(dates);
                                    }
                                    return this;
                                },
                            
                                /**
                                 * A utility method that adds a given date to selection..
                                 * @method _addDateToSelection
                                 * @param {Date} oDate The date to add to selection.
                                 * @param {Number} [index] An optional parameter that is used
                                 * to differentiate between individual date selections and multiple
                                 * date selections.
                                 * @private
                                 */
                                _addDateToSelection : function (oDate, index) {
                                    oDate = this._normalizeTime(oDate);
                            
                                    if (this._canBeSelected(oDate)) {
                            
                                        var year = oDate.getFullYear(),
                                            month = oDate.getMonth(),
                                            day = oDate.getDate();
                            
                                        if (hasKey(this._selectedDates, year)) {
                                            if (hasKey(this._selectedDates[year], month)) {
                                                this._selectedDates[year][month][day] = oDate;
                                            } else {
                                                this._selectedDates[year][month] = {};
                                                this._selectedDates[year][month][day] = oDate;
                                            }
                                        } else {
                                            this._selectedDates[year] = {};
                                            this._selectedDates[year][month] = {};
                                            this._selectedDates[year][month][day] = oDate;
                                        }
                            
                                        this._selectedDates = setVal(this._selectedDates, [year, month, day], oDate);
                            
                                        if (!index) {
                                            this._fireSelectionChange();
                                        }
                                    }
                                },
                            
                                /**
                                 * A utility method that adds a given list of dates to selection.
                                 * @method _addDatesToSelection
                                 * @param {Array} datesArray The list of dates to add to selection.
                                 * @private
                                 */
                                _addDatesToSelection : function (datesArray) {
                                    arrayEach(datesArray, this._addDateToSelection, this);
                                    this._fireSelectionChange();
                                },
                            
                                /**
                                 * A utility method that adds a given range of dates to selection.
                                 * @method _addDateRangeToSelection
                                 * @param {Date} startDate The first date of the given range.
                                 * @param {Date} endDate The last date of the given range.
                                 * @private
                                 */
                                _addDateRangeToSelection : function (startDate, endDate) {
                            
                                    var timezoneDifference = (endDate.getTimezoneOffset() - startDate.getTimezoneOffset())*60000,
                                        startTime = startDate.getTime(),
                                        endTime   = endDate.getTime(),
                                        tempTime,
                                        time,
                                        addedDate;
                            
                                    if (startTime > endTime) {
                                        tempTime = startTime;
                                        startTime = endTime;
                                        endTime = tempTime + timezoneDifference;
                                    } else {
                                        endTime = endTime - timezoneDifference;
                                    }
                            
                            
                                    for (time = startTime; time <= endTime; time += 86400000) {
                                        addedDate = new Date(time);
                                        addedDate.setHours(12);
                                        this._addDateToSelection(addedDate, time);
                                    }
                                    this._fireSelectionChange();
                                },
                            
                                /**
                                 * A utility method that removes a given date from selection..
                                 * @method _removeDateFromSelection
                                 * @param {Date} oDate The date to remove from selection.
                                 * @param {Number} [index] An optional parameter that is used
                                 * to differentiate between individual date selections and multiple
                                 * date selections.
                                 * @private
                                 */
                                _removeDateFromSelection : function (oDate, index) {
                                    var year = oDate.getFullYear(),
                                        month = oDate.getMonth(),
                                        day = oDate.getDate();
                            
                                    if (hasKey(this._selectedDates, year) &&
                                        hasKey(this._selectedDates[year], month) &&
                                        hasKey(this._selectedDates[year][month], day)
                                    ) {
                                        delete this._selectedDates[year][month][day];
                                        if (!index) {
                                            this._fireSelectionChange();
                                        }
                                    }
                                },
                            
                                /**
                                 * A utility method that removes a given list of dates from selection.
                                 * @method _removeDatesFromSelection
                                 * @param {Array} datesArray The list of dates to remove from selection.
                                 * @private
                                 */
                                _removeDatesFromSelection : function (datesArray) {
                                    arrayEach(datesArray, this._removeDateFromSelection, this);
                                    this._fireSelectionChange();
                                },
                            
                                /**
                                 * A utility method that removes a given range of dates from selection.
                                 * @method _removeDateRangeFromSelection
                                 * @param {Date} startDate The first date of the given range.
                                 * @param {Date} endDate The last date of the given range.
                                 * @private
                                 */
                                _removeDateRangeFromSelection : function (startDate, endDate) {
                                    var startTime = startDate.getTime(),
                                        endTime   = endDate.getTime(),
                                        time;
                            
                                    for (time = startTime; time <= endTime; time += 86400000) {
                                        this._removeDateFromSelection(new Date(time), time);
                                    }
                            
                                    this._fireSelectionChange();
                                },
                            
                                /**
                                 * A utility method that removes all dates from selection.
                                 * @method _clearSelection
                                 * @param {boolean} noevent A Boolean specifying whether a selectionChange
                                 * event should be fired. If true, the event is not fired.
                                 * @private
                                 */
                                _clearSelection : function (noevent) {
                                    this._selectedDates = {};
                                    this.get("contentBox").all("." + CAL_DAY_SELECTED).removeClass(CAL_DAY_SELECTED).setAttribute("aria-selected", false);
                                    if (!noevent) {
                                        this._fireSelectionChange();
                                    }
                                },
                            
                                /**
                                 * A utility method that fires a selectionChange event.
                                 * @method _fireSelectionChange
                                 * @private
                                 */
                                _fireSelectionChange : function () {
                            
                                    /**
                                    * Fired when the set of selected dates changes. Contains a payload with
                                    * a `newSelection` property with an array of selected dates.
                                    *
                                    * @event selectionChange
                                    */
                                    this.fire("selectionChange", {newSelection: this._getSelectedDatesList()});
                                },
                            
                                /**
                                 * A utility method that restores cells modified by custom formatting.
                                 * @method _restoreModifiedCells
                                 * @private
                                 */
                                _restoreModifiedCells : function () {
                                    var contentbox = this.get("contentBox"),
                                        id;
                                    for (id in this._storedDateCells) {
                                        contentbox.one("#" + id).replace(this._storedDateCells[id]);
                                        delete this._storedDateCells[id];
                                    }
                                },
                            
                                /**
                                 * A rendering assist method that renders all cells modified by the customRenderer
                                 * rules, as well as the enabledDatesRule and disabledDatesRule.
                                 * @method _renderCustomRules
                                 * @private
                                 */
                                _renderCustomRules : function () {
                            
                                    this.get("contentBox").all("." + CAL_DAY + ",." + CAL_NEXTMONTH_DAY).removeClass(SELECTION_DISABLED).setAttribute("aria-disabled", false);
                            
                                    if (!isEmpty(this._rules)) {
                                        var paneNum,
                                            paneDate,
                                            dateArray;
                            
                                        for (paneNum = 0; paneNum < this._paneNumber; paneNum++) {
                                            paneDate = ydate.addMonths(this.get("date"), paneNum);
                                            dateArray = ydate.listOfDatesInMonth(paneDate);
                                            arrayEach(dateArray, Y.bind(this._renderCustomRulesHelper, this));
                                        }
                                    }
                                },
                            
                                /**
                                * A handler for a date selection event (either a click or a keyboard
                                *   selection) that adds the appropriate CSS class to a specific DOM
                                *   node corresponding to the date and sets its aria-selected
                                *   attribute to true.
                                *
                                * @method _renderCustomRulesHelper
                                * @private
                                */
                                _renderCustomRulesHelper: function (date) {
                                    var enRule = this.get("enabledDatesRule"),
                                        disRule = this.get("disabledDatesRule"),
                                        matchingRules,
                                        dateNode;
                            
                                    matchingRules = this._getRulesForDate(date);
                                    if (matchingRules.length > 0) {
                                        if ((enRule && iOf(matchingRules, enRule) < 0) || (!enRule && disRule && iOf(matchingRules, disRule) >= 0)) {
                                            this._disableDate(date);
                                        }
                            
                                        if (L.isFunction(this._filterFunction)) {
                                            dateNode = this._dateToNode(date);
                                            this._storedDateCells[dateNode.get("id")] = dateNode.cloneNode(true);
                                            this._filterFunction (date, dateNode, matchingRules);
                                        }
                                    } else if (enRule) {
                                        this._disableDate(date);
                                    }
                                },
                            
                                /**
                                 * A rendering assist method that renders all cells that are currently selected.
                                 * @method _renderSelectedDates
                                 * @private
                                 */
                                _renderSelectedDates : function () {
                                    this.get("contentBox").all("." + CAL_DAY_SELECTED).removeClass(CAL_DAY_SELECTED).setAttribute("aria-selected", false);
                            
                                    var paneNum,
                                        paneDate,
                                        dateArray;
                            
                                    for (paneNum = 0; paneNum < this._paneNumber; paneNum++) {
                                        paneDate = ydate.addMonths(this.get("date"), paneNum);
                                        dateArray = this._getSelectedDatesInMonth(paneDate);
                            
                                        arrayEach(dateArray, Y.bind(this._renderSelectedDatesHelper, this));
                                    }
                                },
                            
                                /**
                                * Takes in a date and determines whether that date has any rules
                                *   matching it in the customRenderer; then calls the specified
                                *   filterFunction if that's the case and/or disables the date
                                *   if the rule is specified as a disabledDatesRule.
                                *
                                * @method _renderSelectedDatesHelper
                                * @private
                                */
                                _renderSelectedDatesHelper: function (date) {
                                    this._dateToNode(date).addClass(CAL_DAY_SELECTED).setAttribute("aria-selected", true);
                                },
                            
                                /**
                                 * Add the selection-disabled class and aria-disabled attribute to a node corresponding
                                 * to a given date.
                                 *
                                 * @method _disableDate
                                 * @param {Date} date The date to disable
                                 * @private
                                 */
                                _disableDate: function (date) {
                                   this._dateToNode(date).addClass(SELECTION_DISABLED).setAttribute("aria-disabled", true);
                                },
                            
                                /**
                                 * A utility method that converts a date to the node wrapping the calendar cell
                                 * the date corresponds to..
                                 * @method _dateToNode
                                 * @param {Date} oDate The date to convert to Node
                                 * @protected
                                 * @return {Node} The node wrapping the DOM element of the cell the date
                                 * corresponds to.
                                 */
                                _dateToNode : function (oDate) {
                                    var day = oDate.getDate(),
                                        col = 0,
                                        daymod = day%7,
                                        paneNum = (12 + oDate.getMonth() - this.get("date").getMonth()) % 12,
                                        paneId = this._calendarId + "_pane_" + paneNum,
                                        cutoffCol = this._paneProperties[paneId].cutoffCol;
                            
                                    switch (daymod) {
                                        case (0):
                                            if (cutoffCol >= 6) {
                                                col = 12;
                                            } else {
                                                col = 5;
                                            }
                                            break;
                                        case (1):
                                                col = 6;
                                            break;
                                        case (2):
                                            if (cutoffCol > 0) {
                                                col = 7;
                                            } else {
                                                col = 0;
                                            }
                                            break;
                                        case (3):
                                            if (cutoffCol > 1) {
                                                col = 8;
                                            } else {
                                                col = 1;
                                            }
                                            break;
                                        case (4):
                                            if (cutoffCol > 2) {
                                                col = 9;
                                            } else {
                                                col = 2;
                                            }
                                            break;
                                        case (5):
                                            if (cutoffCol > 3) {
                                                col = 10;
                                            } else {
                                                col = 3;
                                            }
                                            break;
                                        case (6):
                                            if (cutoffCol > 4) {
                                                col = 11;
                                            } else {
                                                col = 4;
                                            }
                                            break;
                                    }
                                    return(this.get("contentBox").one("#" + this._calendarId + "_pane_" + paneNum + "_" + col + "_" + day));
                            
                                },
                            
                                /**
                                 * A utility method that converts a node corresponding to the DOM element of
                                 * the cell for a particular date to that date.
                                 * @method _nodeToDate
                                 * @param {Node} oNode The Node wrapping the DOM element of a particular date cell.
                                 * @protected
                                 * @return {Date} The date corresponding to the DOM element that the given node wraps.
                                 */
                                _nodeToDate : function (oNode) {
                            
                                    var idParts = oNode.get("id").split("_").reverse(),
                                        paneNum = parseInt(idParts[2], 10),
                                        day  = parseInt(idParts[0], 10),
                                        shiftedDate = ydate.addMonths(this.get("date"), paneNum),
                                        year = shiftedDate.getFullYear(),
                                        month = shiftedDate.getMonth();
                            
                                    return new Date(year, month, day, 12, 0, 0, 0);
                                },
                            
                                /**
                                 * A placeholder method, called from bindUI, to bind the Calendar events.
                                 * @method _bindCalendarEvents
                                 * @protected
                                 */
                                _bindCalendarEvents : function () {},
                            
                                /**
                                 * A utility method that normalizes a given date by converting it to the 1st
                                 * day of the month the date is in, with the time set to noon.
                                 * @method _normalizeDate
                                 * @param {Date} oDate The date to normalize
                                 * @protected
                                 * @return {Date} The normalized date, set to the first of the month, with time
                                 * set to noon.
                                 */
                                _normalizeDate : function (date) {
                                    if (date) {
                                        return new Date(date.getFullYear(), date.getMonth(), 1, 12, 0, 0, 0);
                                    } else {
                                        return null;
                                    }
                                },
                            
                                /**
                                 * A utility method that normalizes a given date by setting its time to noon.
                                 * @method _normalizeTime
                                 * @param {Date} oDate The date to normalize
                                 * @protected
                                 * @return {Date} The normalized date
                                 * set to noon.
                                 */
                                _normalizeTime : function (date) {
                                    if (date) {
                                        return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 12, 0, 0, 0);
                                    } else {
                                        return null;
                                    }
                                },
                            
                            
                                /**
                                 * A render assist utility method that computes the cutoff column for the calendar
                                 * rendering mask.
                                 * @method _getCutoffColumn
                                 * @param {Date} date The date of the month grid to compute the cutoff column for.
                                 * @param {Number} firstday The first day of the week (modified by internationalized calendars)
                                 * @private
                                 * @return {Number} The number of the cutoff column.
                                 */
                                _getCutoffColumn : function (date, firstday) {
                                    var distance = this._normalizeDate(date).getDay() - firstday,
                                        cutOffColumn = 6 - (distance + 7) % 7;
                                    return cutOffColumn;
                                },
                            
                                /**
                                 * A render assist method that turns on the view of the previous month's dates
                                 * in a given calendar pane.
                                 * @method _turnPrevMonthOn
                                 * @param {Node} pane The calendar pane that needs its previous month's dates view
                                 * modified.
                                 * @protected
                                 */
                                _turnPrevMonthOn : function (pane) {
                                    var pane_id = pane.get("id"),
                                        pane_date = this._paneProperties[pane_id].paneDate,
                                        daysInPrevMonth = ydate.daysInMonth(ydate.addMonths(pane_date, -1)),
                                        cell;
                            
                                    if (!this._paneProperties[pane_id].hasOwnProperty("daysInPrevMonth")) {
                                        this._paneProperties[pane_id].daysInPrevMonth = 0;
                                    }
                            
                                    if (daysInPrevMonth !== this._paneProperties[pane_id].daysInPrevMonth) {
                            
                                        this._paneProperties[pane_id].daysInPrevMonth = daysInPrevMonth;
                            
                                        for (cell = 5; cell >= 0; cell--) {
                                            pane.one("#" + pane_id + "_" + cell + "_" + (cell-5)).set('text', daysInPrevMonth--);
                                        }
                                    }
                                },
                            
                                /**
                                 * A render assist method that turns off the view of the previous month's dates
                                 * in a given calendar pane.
                                 * @method _turnPrevMonthOff
                                 * @param {Node} pane The calendar pane that needs its previous month's dates view
                                 * modified.
                                 * @protected
                                 */
                                _turnPrevMonthOff : function (pane) {
                                    var pane_id = pane.get("id"),
                                        cell;
                            
                                    this._paneProperties[pane_id].daysInPrevMonth = 0;
                            
                                    for (cell = 5; cell >= 0; cell--) {
                                        pane.one("#" + pane_id + "_" + cell + "_" + (cell-5)).setContent("&nbsp;");
                                    }
                                },
                            
                                /**
                                 * A render assist method that cleans up the last few cells in the month grid
                                 * when the number of days in the month changes.
                                 * @method _cleanUpNextMonthCells
                                 * @param {Node} pane The calendar pane that needs the last date cells cleaned up.
                                 * @private
                                 */
                                _cleanUpNextMonthCells : function (pane) {
                                    var pane_id = pane.get("id");
                                        pane.one("#" + pane_id + "_6_29").removeClass(CAL_NEXTMONTH_DAY);
                                        pane.one("#" + pane_id + "_7_30").removeClass(CAL_NEXTMONTH_DAY);
                                        pane.one("#" + pane_id + "_8_31").removeClass(CAL_NEXTMONTH_DAY);
                                        pane.one("#" + pane_id + "_0_30").removeClass(CAL_NEXTMONTH_DAY);
                                        pane.one("#" + pane_id + "_1_31").removeClass(CAL_NEXTMONTH_DAY);
                                },
                            
                                /**
                                 * A render assist method that turns on the view of the next month's dates
                                 * in a given calendar pane.
                                 * @method _turnNextMonthOn
                                 * @param {Node} pane The calendar pane that needs its next month's dates view
                                 * modified.
                                 * @protected
                                 */
                                _turnNextMonthOn : function (pane) {
                                    var dayCounter = 1,
                                        pane_id = pane.get("id"),
                                        daysInMonth = this._paneProperties[pane_id].daysInMonth,
                                        cutoffCol = this._paneProperties[pane_id].cutoffCol,
                                        cell,
                                        startingCell;
                            
                                    for (cell = daysInMonth - 22; cell < cutoffCol + 7; cell++) {
                                        pane.one("#" + pane_id + "_" + cell + "_" + (cell+23)).set("text", dayCounter++).addClass(CAL_NEXTMONTH_DAY);
                                    }
                            
                                    startingCell = cutoffCol;
                            
                                    if (daysInMonth === 31 && (cutoffCol <= 1)) {
                                        startingCell = 2;
                                    } else if (daysInMonth === 30 && cutoffCol === 0) {
                                        startingCell = 1;
                                    }
                            
                                    for (cell = startingCell ; cell < cutoffCol + 7; cell++) {
                                        pane.one("#" + pane_id + "_" + cell + "_" + (cell+30)).set("text", dayCounter++).addClass(CAL_NEXTMONTH_DAY);
                                    }
                                },
                            
                                /**
                                 * A render assist method that turns off the view of the next month's dates
                                 * in a given calendar pane.
                                 * @method _turnNextMonthOff
                                 * @param {Node} pane The calendar pane that needs its next month's dates view
                                 * modified.
                                 * @protected
                                 */
                                _turnNextMonthOff : function (pane) {
                                        var pane_id = pane.get("id"),
                                            daysInMonth = this._paneProperties[pane_id].daysInMonth,
                                            cutoffCol = this._paneProperties[pane_id].cutoffCol,
                                            cell,
                                            startingCell;
                            
                                        for (cell = daysInMonth - 22; cell <= 12; cell++) {
                                            pane.one("#" + pane_id + "_" + cell + "_" + (cell+23)).setContent("&nbsp;").addClass(CAL_NEXTMONTH_DAY);
                                        }
                            
                                        startingCell = 0;
                            
                                        if (daysInMonth === 31 && (cutoffCol <= 1)) {
                                            startingCell = 2;
                                        } else if (daysInMonth === 30 && cutoffCol === 0) {
                                            startingCell = 1;
                                        }
                            
                                        for (cell = startingCell ; cell <= 12; cell++) {
                                            pane.one("#" + pane_id + "_" + cell + "_" + (cell+30)).setContent("&nbsp;").addClass(CAL_NEXTMONTH_DAY);
                                        }
                                },
                            
                                /**
                                 * The handler for the change in the showNextMonth attribute.
                                 * @method _afterShowNextMonthChange
                                 * @private
                                 */
                                _afterShowNextMonthChange : function () {
                            
                                    var contentBox = this.get('contentBox'),
                                        lastPane = contentBox.one("#" + this._calendarId + "_pane_" + (this._paneNumber - 1));
                            
                                    this._cleanUpNextMonthCells(lastPane);
                            
                                    if (this.get('showNextMonth')) {
                                        this._turnNextMonthOn(lastPane);
                                    } else {
                                        this._turnNextMonthOff(lastPane);
                                    }
                            
                                },
                            
                                /**
                                 * The handler for the change in the showPrevMonth attribute.
                                 * @method _afterShowPrevMonthChange
                                 * @private
                                 */
                                _afterShowPrevMonthChange : function () {
                                    var contentBox = this.get('contentBox'),
                                        firstPane = contentBox.one("#" + this._calendarId + "_pane_" + 0);
                            
                                    if (this.get('showPrevMonth')) {
                                        this._turnPrevMonthOn(firstPane);
                                    } else {
                                        this._turnPrevMonthOff(firstPane);
                                    }
                            
                                },
                            
                                 /**
                                 * The handler for the change in the headerRenderer attribute.
                                 * @method _afterHeaderRendererChange
                                 * @private
                                 */
                                _afterHeaderRendererChange : function () {
                                    var headerCell = this.get("contentBox").one("." + CAL_HD_LABEL);
                                    headerCell.setContent(this._updateCalendarHeader(this.get('date')));
                                },
                            
                                 /**
                                 * The handler for the change in the customRenderer attribute.
                                 * @method _afterCustomRendererChange
                                 * @private
                                 */
                                _afterCustomRendererChange : function () {
                                    this._restoreModifiedCells();
                                    this._renderCustomRules();
                                },
                            
                                 /**
                                 * The handler for the change in the date attribute. Modifies the calendar
                                 * view by shifting the calendar grid mask and running custom rendering and
                                 * selection rendering as necessary.
                                 * @method _afterDateChange
                                 * @private
                                 */
                                _afterDateChange : function () {
                            
                                    var contentBox = this.get('contentBox'),
                                        headerCell = contentBox.one("." + CAL_HD).one("." + CAL_HD_LABEL),
                                        calendarPanes = contentBox.all("." + CAL_GRID),
                                        currentDate = this.get("date"),
                                        counter = 0;
                            
                                    contentBox.setStyle("visibility", "hidden");
                                    headerCell.setContent(this._updateCalendarHeader(currentDate));
                            
                                    this._restoreModifiedCells();
                            
                                    calendarPanes.each(function (curNode) {
                                        this._rerenderCalendarPane(ydate.addMonths(currentDate, counter++), curNode);
                                    }, this);
                            
                                    this._afterShowPrevMonthChange();
                                    this._afterShowNextMonthChange();
                            
                                    this._renderCustomRules();
                                    this._renderSelectedDates();
                            
                                    contentBox.setStyle("visibility", "inherit");
                                },
                            
                            
                                 /**
                                 * A rendering assist method that initializes the HTML for a single
                                 * calendar pane.
                                 * @method _initCalendarPane
                                 * @param {Date} baseDate The date corresponding to the month of the given
                                 * calendar pane.
                                 * @param {String} pane_id The id of the pane, to be used as a prefix for
                                 * element ids in the given pane.
                                 * @private
                                 */
                                _initCalendarPane : function (baseDate, pane_id) {
                                    var dateFormat = Y.Intl.get('datatype-date-format'),
                                        weekDays = dateFormat.A,
                                        // Get the first day of the week from the internationalization package, or else use Sunday as default.
                                        firstday = this.get('strings.first_weekday') || 0,
                                        // Compute the cutoff column of the masked calendar table, based on the start date and the first day of week.
                                        cutoffCol = this._getCutoffColumn(baseDate, firstday),
                                        // Compute the number of days in the month based on starting date
                                        daysInMonth = ydate.daysInMonth(baseDate),
                                        // Initialize the array of individual row HTML strings
                                        row_array = ['','','','','',''],
                                        // Initialize the partial templates object
                                        partials = {},
                            
                                        shortWeekDays,
                                        day,
                                        row,
                                        column,
                                        date,
                                        id_date,
                                        calendar_day_class,
                                        column_visibility,
                                        output;
                            
                                    if (Y.Intl.getLang('calendar-base')) {
                                        shortWeekDays = this.get('strings.very_short_weekdays');
                                    } else {
                                        shortWeekDays = dateFormat.a;
                                    }
                            
                                    // Initialize the partial template for the weekday row cells.
                                    partials.weekday_row = '';
                            
                                    // Populate the partial template for the weekday row cells with weekday names
                                    for (day = firstday; day <= firstday + 6; day++) {
                                        partials.weekday_row +=
                                            substitute(CalendarBase.WEEKDAY_TEMPLATE, {
                                                short_weekdayname: shortWeekDays[day%7],
                                                weekdayname: weekDays[day%7]
                                            });
                                    }
                            
                                    // Populate the partial template for the weekday row container with the weekday row cells
                                    partials.weekday_row_template = substitute(CalendarBase.WEEKDAY_ROW_TEMPLATE, partials);
                            
                                    // Populate the array of individual row HTML strings
                                    for (row = 0; row <= 5; row++) {
                            
                                        for (column = 0; column <= 12; column++) {
                            
                                            // Compute the value of the date that needs to populate the cell
                                            date = 7*row - 5 + column;
                            
                                            // Compose the value of the unique id of the current calendar cell
                                            id_date = pane_id + "_" + column + "_" + date;
                            
                                            // Set the calendar day class to one of three possible values
                                            calendar_day_class = CAL_DAY;
                            
                                            if (date < 1) {
                                                calendar_day_class = CAL_PREVMONTH_DAY;
                                            } else if (date > daysInMonth) {
                                                calendar_day_class = CAL_NEXTMONTH_DAY;
                                            }
                            
                                            // Cut off dates that fall before the first and after the last date of the month
                                            if (date < 1 || date > daysInMonth) {
                                                date = "&nbsp;";
                                            }
                            
                                            // Decide on whether a column in the masked table is visible or not based on the value of the cutoff column.
                                            column_visibility = (column >= cutoffCol && column < (cutoffCol + 7)) ? '' : CAL_COL_HIDDEN;
                            
                                            // Substitute the values into the partial calendar day template and add it to the current row HTML string
                                            row_array[row] += substitute (CalendarBase.CALDAY_TEMPLATE, {
                                                day_content: date,
                                                calendar_col_class: "calendar_col" + column,
                                                calendar_col_visibility_class: column_visibility,
                                                calendar_day_class: calendar_day_class,
                                                calendar_day_id: id_date
                                            });
                                        }
                                    }
                            
                                    // Instantiate the partial calendar pane body template
                                    partials.body_template = '';
                            
                                    // Populate the body template with the rows templates
                                    arrayEach (row_array, function (v) {
                                         partials.body_template += substitute(CalendarBase.CALDAY_ROW_TEMPLATE, {calday_row: v});
                                    });
                            
                                    // Populate the calendar grid id
                                    partials.calendar_pane_id = pane_id;
                            
                                    // Populate the calendar pane tabindex
                                    partials.calendar_pane_tabindex = this.get("tabIndex");
                                    partials.pane_arialabel = ydate.format(baseDate, { format: "%B %Y" });
                            
                            
                                    // Generate final output by substituting class names.
                                    output = substitute(substitute (CalendarBase.CALENDAR_GRID_TEMPLATE, partials),
                                                                                    CalendarBase.CALENDAR_STRINGS);
                            
                                    // Store the initialized pane information
                                    this._paneProperties[pane_id] = {cutoffCol: cutoffCol, daysInMonth: daysInMonth, paneDate: baseDate};
                            
                                    return output;
                                },
                            
                                 /**
                                 * A rendering assist method that rerenders a specified calendar pane, based
                                 * on a new Date.
                                 * @method _rerenderCalendarPane
                                 * @param {Date} newDate The date corresponding to the month of the given
                                 * calendar pane.
                                 * @param {Node} pane The node corresponding to the calendar pane to be rerenders.
                                 * @private
                                 */
                                _rerenderCalendarPane : function (newDate, pane) {
                            
                                    // Get the first day of the week from the internationalization package, or else use Sunday as default.
                                    var firstday = this.get('strings.first_weekday') || 0,
                                        // Compute the cutoff column of the masked calendar table, based on the start date and the first day of week.
                                        cutoffCol = this._getCutoffColumn(newDate, firstday),
                                        // Compute the number of days in the month based on starting date
                                        daysInMonth = ydate.daysInMonth(newDate),
                                        // Get pane id for easier reference
                                        paneId = pane.get("id"),
                                        column,
                                        currentColumn,
                                        curCell;
                            
                                    // Hide the pane before making DOM changes to speed them up
                                    pane.setStyle("visibility", "hidden");
                                    pane.setAttribute("aria-label", ydate.format(newDate, {format:"%B %Y"}));
                            
                                    // Go through all columns, and flip their visibility setting based on whether they are within the unmasked range.
                                    for (column = 0; column <= 12; column++) {
                                        currentColumn = pane.all("." + "calendar_col" + column);
                                        currentColumn.removeClass(CAL_COL_HIDDEN);
                            
                                        if (column < cutoffCol || column >= (cutoffCol + 7)) {
                                            currentColumn.addClass(CAL_COL_HIDDEN);
                                        } else {
                                            // Clean up dates in visible columns to account for the correct number of days in a month
                                            switch(column) {
                                                case 0:
                                                    curCell = pane.one("#" + paneId + "_0_30");
                                                    if (daysInMonth >= 30) {
                                                        curCell.set("text", "30");
                                                        curCell.removeClass(CAL_NEXTMONTH_DAY).addClass(CAL_DAY);
                                                    } else {
                                                        curCell.setContent("&nbsp;");
                                                        curCell.removeClass(CAL_DAY).addClass(CAL_NEXTMONTH_DAY);
                                                    }
                                                    break;
                                                case 1:
                                                    curCell = pane.one("#" + paneId + "_1_31");
                                                    if (daysInMonth >= 31) {
                                                        curCell.set("text", "31");
                                                        curCell.removeClass(CAL_NEXTMONTH_DAY).addClass(CAL_DAY);
                                                    } else {
                                                        curCell.setContent("&nbsp;");
                                                        curCell.removeClass(CAL_DAY).addClass(CAL_NEXTMONTH_DAY);
                                                    }
                                                    break;
                                                case 6:
                                                    curCell = pane.one("#" + paneId + "_6_29");
                                                    if (daysInMonth >= 29) {
                                                        curCell.set("text", "29");
                                                        curCell.removeClass(CAL_NEXTMONTH_DAY).addClass(CAL_DAY);
                                                    } else {
                                                        curCell.setContent("&nbsp;");
                                                        curCell.removeClass(CAL_DAY).addClass(CAL_NEXTMONTH_DAY);
                                                    }
                                                    break;
                                                case 7:
                                                    curCell = pane.one("#" + paneId + "_7_30");
                                                    if (daysInMonth >= 30) {
                                                        curCell.set("text", "30");
                                                        curCell.removeClass(CAL_NEXTMONTH_DAY).addClass(CAL_DAY);
                                                    } else {
                                                        curCell.setContent("&nbsp;");
                                                        curCell.removeClass(CAL_DAY).addClass(CAL_NEXTMONTH_DAY);
                                                    }
                                                    break;
                                                case 8:
                                                    curCell = pane.one("#" + paneId + "_8_31");
                                                    if (daysInMonth >= 31) {
                                                        curCell.set("text", "31");
                                                        curCell.removeClass(CAL_NEXTMONTH_DAY).addClass(CAL_DAY);
                                                    } else {
                                                        curCell.setContent("&nbsp;");
                                                        curCell.removeClass(CAL_DAY).addClass(CAL_NEXTMONTH_DAY);
                                                    }
                                                    break;
                                            }
                                        }
                                    }
                            
                                    // Update stored pane properties
                                    this._paneProperties[paneId].cutoffCol = cutoffCol;
                                    this._paneProperties[paneId].daysInMonth = daysInMonth;
                                    this._paneProperties[paneId].paneDate = newDate;
                            
                                    // Bring the pane visibility back after all DOM changes are done
                                    pane.setStyle("visibility", "inherit");
                            
                                },
                            
                                 /**
                                 * A rendering assist method that updates the calendar header based
                                 * on a given date and potentially the provided headerRenderer.
                                 * @method _updateCalendarHeader
                                 * @param {Date} baseDate The date with which to update the calendar header.
                                 * @private
                                 */
                                _updateCalendarHeader : function (baseDate) {
                                    var headerString = "",
                                        headerRenderer = this.get("headerRenderer");
                            
                                    if (Y.Lang.isString(headerRenderer)) {
                                        headerString = ydate.format(baseDate, {format:headerRenderer});
                                    } else if (headerRenderer instanceof Function) {
                                        headerString = headerRenderer.call(this, baseDate);
                                    }
                            
                                    return headerString;
                                },
                            
                                 /**
                                 * A rendering assist method that initializes the calendar header HTML
                                 * based on a given date and potentially the provided headerRenderer.
                                 * @method _initCalendarHeader
                                 * @param {Date} baseDate The date with which to initialize the calendar header.
                                 * @private
                                 */
                                _initCalendarHeader : function (baseDate) {
                                    return substitute(substitute(CalendarBase.HEADER_TEMPLATE, {
                                            calheader: this._updateCalendarHeader(baseDate),
                                            calendar_id: this._calendarId
                                        }), CalendarBase.CALENDAR_STRINGS );
                                },
                            
                                 /**
                                 * A rendering assist method that initializes the calendar HTML
                                 * based on a given date.
                                 * @method _initCalendarHTML
                                 * @param {Date} baseDate The date with which to initialize the calendar.
                                 * @private
                                 */
                                _initCalendarHTML : function (baseDate) {
                                    // Instantiate the partials holder
                                    var partials = {},
                                        // Counter for iterative template replacement.
                                        counter = 0,
                                        singlePane,
                                        output;
                            
                                    // Generate the template for the header
                                    partials.header_template =  this._initCalendarHeader(baseDate);
                                    partials.calendar_id = this._calendarId;
                            
                                    partials.body_template = substitute(substitute (CalendarBase.CONTENT_TEMPLATE, partials),
                                                                                                             CalendarBase.CALENDAR_STRINGS);
                            
                                    // Instantiate the iterative template replacer function
                                    function paneReplacer () {
                                        singlePane = this._initCalendarPane(ydate.addMonths(baseDate, counter), partials.calendar_id + "_pane_" + counter);
                                        counter++;
                                        return singlePane;
                                    }
                            
                                    // Go through all occurrences of the calendar_grid_template token and replace it with an appropriate calendar grid.
                                    output = partials.body_template.replace(/\{calendar_grid_template\}/g, Y.bind(paneReplacer, this));
                            
                                    // Update the paneNumber count
                                    this._paneNumber = counter;
                            
                                    return output;
                                }
                            }, {
                            
                                 /**
                                    * The CSS classnames for the calendar templates.
                                    * @property CALENDAR_STRINGS
                                    * @type Object
                                    * @readOnly
                                    * @protected
                                    * @static
                                    */
                                CALENDAR_STRINGS: {
                                    calendar_grid_class       : CAL_GRID,
                                    calendar_body_class       : CAL_BODY,
                                    calendar_hd_class         : CAL_HD,
                                    calendar_hd_label_class   : CAL_HD_LABEL,
                                    calendar_weekdayrow_class : CAL_WDAYROW,
                                    calendar_weekday_class    : CAL_WDAY,
                                    calendar_row_class        : CAL_ROW,
                                    calendar_day_class        : CAL_DAY,
                                    calendar_dayanchor_class  : CAL_ANCHOR,
                                    calendar_pane_class       : CAL_PANE,
                                    calendar_right_grid_class : CAL_RIGHT_GRID,
                                    calendar_left_grid_class  : CAL_LEFT_GRID,
                                    calendar_status_class     : CAL_STATUS
                                },
                            
                                /*
                            
                                ARIA_STATUS_TEMPLATE: '<div role="status" aria-atomic="true" class="{calendar_status_class}"></div>',
                            
                                AriaStatus : null,
                            
                                updateStatus : function (statusString) {
                            
                                    if (!CalendarBase.AriaStatus) {
                                        CalendarBase.AriaStatus = create(
                                                                                     substitute (CalendarBase.ARIA_STATUS_TEMPLATE,
                                                                                                             CalendarBase.CALENDAR_STRINGS));
                                        Y.one("body").append(CalendarBase.AriaStatus);
                                    }
                            
                                        CalendarBase.AriaStatus.set("text", statusString);
                                },
                            
                                */
                            
                                 /**
                                    * The main content template for calendar.
                                    * @property CONTENT_TEMPLATE
                                    * @type String
                                    * @protected
                                    * @static
                                    */
                                CONTENT_TEMPLATE:  '<div class="yui3-g {calendar_pane_class}" id="{calendar_id}">' +
                                                    '{header_template}' +
                                                    '<div class="yui3-u-1">' +
                                                    '{calendar_grid_template}' +
                                                    '</div>' +
                                                    '</div>',
                            
                                 /**
                                    * A single pane template for calendar (same as default CONTENT_TEMPLATE)
                                    * @property ONE_PANE_TEMPLATE
                                    * @type String
                                    * @protected
                                    * @readOnly
                                    * @static
                                    */
                                ONE_PANE_TEMPLATE: '<div class="yui3-g {calendar_pane_class}" id="{calendar_id}">' +
                                                        '{header_template}' +
                                                        '<div class="yui3-u-1">' +
                                                            '{calendar_grid_template}' +
                                                        '</div>' +
                                                    '</div>',
                            
                                 /**
                                    * A two pane template for calendar.
                                    * @property TWO_PANE_TEMPLATE
                                    * @type String
                                    * @protected
                                    * @readOnly
                                    * @static
                                    */
                                TWO_PANE_TEMPLATE: '<div class="yui3-g {calendar_pane_class}" id="{calendar_id}">' +
                                                        '{header_template}' +
                                                        '<div class="yui3-u-1-2">'+
                                                            '<div class = "{calendar_left_grid_class}">' +
                                                                '{calendar_grid_template}' +
                                                            '</div>' +
                                                        '</div>' +
                                                        '<div class="yui3-u-1-2">' +
                                                            '<div class = "{calendar_right_grid_class}">' +
                                                                '{calendar_grid_template}' +
                                                            '</div>' +
                                                        '</div>' +
                                                    '</div>',
                                 /**
                                    * A three pane template for calendar.
                                    * @property THREE_PANE_TEMPLATE
                                    * @type String
                                    * @protected
                                    * @readOnly
                                    * @static
                                    */
                                THREE_PANE_TEMPLATE: '<div class="yui3-g {calendar_pane_class}" id="{calendar_id}">' +
                                                        '{header_template}' +
                                                        '<div class="yui3-u-1-3">' +
                                                            '<div class="{calendar_left_grid_class}">' +
                                                                '{calendar_grid_template}' +
                                                            '</div>' +
                                                        '</div>' +
                                                        '<div class="yui3-u-1-3">' +
                                                            '{calendar_grid_template}' +
                                                        '</div>' +
                                                        '<div class="yui3-u-1-3">' +
                                                            '<div class="{calendar_right_grid_class}">' +
                                                                '{calendar_grid_template}' +
                                                            '</div>' +
                                                        '</div>' +
                                                    '</div>',
                                 /**
                                    * A template for the calendar grid.
                                    * @property CALENDAR_GRID_TEMPLATE
                                    * @type String
                                    * @protected
                                    * @static
                                    */
                                CALENDAR_GRID_TEMPLATE: '<table class="{calendar_grid_class}" id="{calendar_pane_id}" role="grid" aria-readonly="true" ' +
                                                            'aria-label="{pane_arialabel}" tabindex="{calendar_pane_tabindex}">' +
                                                            '<thead>' +
                                                                '{weekday_row_template}' +
                                                            '</thead>' +
                                                            '<tbody>' +
                                                                '{body_template}' +
                                                            '</tbody>' +
                                                        '</table>',
                            
                                 /**
                                    * A template for the calendar header.
                                    * @property HEADER_TEMPLATE
                                    * @type String
                                    * @protected
                                    * @static
                                    */
                                HEADER_TEMPLATE: '<div class="yui3-g {calendar_hd_class}">' +
                                                    '<div class="yui3-u {calendar_hd_label_class}" id="{calendar_id}_header" aria-role="heading">' +
                                                        '{calheader}' +
                                                    '</div>' +
                                                '</div>',
                            
                                 /**
                                    * A template for the row of weekday names.
                                    * @property WEEKDAY_ROW_TEMPLATE
                                    * @type String
                                    * @protected
                                    * @static
                                    */
                                WEEKDAY_ROW_TEMPLATE: '<tr class="{calendar_weekdayrow_class}" role="row">' +
                                                        '{weekday_row}' +
                                                    '</tr>',
                            
                                 /**
                                    * A template for a single row of calendar days.
                                    * @property CALDAY_ROW_TEMPLATE
                                    * @type String
                                    * @protected
                                    * @static
                                    */
                                CALDAY_ROW_TEMPLATE: '<tr class="{calendar_row_class}" role="row">' +
                                                        '{calday_row}' +
                                                    '</tr>',
                            
                                 /**
                                    * A template for a single cell with a weekday name.
                                    * @property WEEKDAY_TEMPLATE
                                    * @type String
                                    * @protected
                                    * @static
                                    */
                                WEEKDAY_TEMPLATE: '<th class="{calendar_weekday_class}" role="columnheader" aria-label="{weekdayname}">{short_weekdayname}</th>',
                            
                                 /**
                                    * A template for a single cell with a calendar day.
                                    * @property CALDAY_TEMPLATE
                                    * @type String
                                    * @protected
                                    * @static
                                    */
                                CALDAY_TEMPLATE: '<td class="{calendar_col_class} {calendar_day_class} {calendar_col_visibility_class}" id="{calendar_day_id}" ' +
                                                    'role="gridcell" tabindex="-1">' +
                                                    '{day_content}' +
                                                '</td>',
                            
                                 /**
                                    * The identity of the widget.
                                    *
                                    * @property NAME
                                    * @type String
                                    * @default 'calendarBase'
                                    * @readOnly
                                    * @protected
                                    * @static
                                    */
                                NAME: 'calendarBase',
                            
                                 /**
                                    * Static property used to define the default attribute configuration of
                                    * the Widget.
                                    *
                                    * @property ATTRS
                                    * @type {Object}
                                    * @protected
                                    * @static
                                    */
                                ATTRS: {
                                    tabIndex: {
                                        value: 1
                                    },
                                    /**
                                     * The date corresponding to the current calendar view. Always
                                     * normalized to the first of the month that contains the date
                                     * at assignment time. Used as the first date visible in the
                                     * calendar.
                                     *
                                     * @attribute date
                                     * @type Date
                                     * @default The first of the month containing today's date, as
                                     * set on the end user's system.
                                     */
                                    date: {
                                        value: new Date(),
                                        setter: function (val) {
                                            var newDate = this._normalizeDate(val);
                                            if (ydate.areEqual(newDate, this.get('date'))) {
                                                    return this.get('date');
                                            } else {
                                                    return newDate;
                                            }
                                        }
                                    },
                            
                                    /**
                                     * A setting specifying whether to shows days from the previous
                                     * month in the visible month's grid, if there are empty preceding
                                     * cells available.
                                     *
                                     * @attribute showPrevMonth
                                     * @type boolean
                                     * @default false
                                     */
                                    showPrevMonth: {
                                        value: false
                                    },
                            
                                    /**
                                     * A setting specifying whether to shows days from the next
                                     * month in the visible month's grid, if there are empty
                                     * cells available at the end.
                                     *
                                     * @attribute showNextMonth
                                     * @type boolean
                                     * @default false
                                     */
                                    showNextMonth: {
                                        value: false
                                    },
                            
                                    /**
                                     * Strings and properties derived from the internationalization packages
                                     * for the calendar.
                                     *
                                     * @attribute strings
                                     * @type Object
                                     * @protected
                                     */
                                    strings : {
                                        valueFn: function() { return Y.Intl.get("calendar-base"); }
                                    },
                            
                                    /**
                                     * Custom header renderer for the calendar.
                                     *
                                     * @attribute headerRenderer
                                     * @type String | Function
                                     */
                                    headerRenderer: {
                                        value: "%B %Y"
                                    },
                            
                                    /**
                                     * The name of the rule which all enabled dates should match.
                                     * Either disabledDatesRule or enabledDatesRule should be specified,
                                     * or neither, but not both.
                                     *
                                     * @attribute enabledDatesRule
                                     * @type String
                                     * @default null
                                     */
                                    enabledDatesRule: {
                                        value: null
                                    },
                            
                                    /**
                                     * The name of the rule which all disabled dates should match.
                                     * Either disabledDatesRule or enabledDatesRule should be specified,
                                     * or neither, but not both.
                                     *
                                     * @attribute disabledDatesRule
                                     * @type String
                                     * @default null
                                     */
                                    disabledDatesRule: {
                                        value: null
                                    },
                            
                                    /**
                                     * A read-only attribute providing a list of currently selected dates.
                                     *
                                     * @attribute selectedDates
                                     * @readOnly
                                     * @type Array
                                     */
                                    selectedDates : {
                                        readOnly: true,
                                        getter: function () {
                                            return (this._getSelectedDatesList());
                                        }
                                    },
                            
                                    /**
                                     * An object of the form {rules:Object, filterFunction:Function},
                                     * providing  set of rules and a custom rendering function for
                                     * customizing specific calendar cells.
                                     *
                                     * @attribute customRenderer
                                     * @type Object
                                     * @default {}
                                     */
                                    customRenderer : {
                                        lazyAdd: false,
                                        value: {},
                                        setter: function (val) {
                                            this._rules = val.rules;
                                            this._filterFunction = val.filterFunction;
                                        }
                                    }
                                }
                            
                            });