MediaWiki:Gadget-moment.js

// moment.js // version : 2.0.0 // author : Tim Wood // license : MIT // momentjs.com

(function (undefined) {

/************************************       Constants ************************************/

var moment, VERSION = "2.0.0", round = Math.round, i,       // internal storage for language config files languages = {},

// check for nodeJS hasModule = (typeof module !== 'undefined' && module.exports),

// ASP.NET json date format regex aspNetJsonRegex = /^\/?Date\((\-?\d+)/i,

// format tokens formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|YYYYY|YYYY|YY|a|A|hh?|HH?|mm?|ss?|SS?S?|X|zz?|ZZ?|.)/g,       localFormattingTokens = /(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g,

// parsing tokens parseMultipleFormatChunker = /([0-9a-zA-Z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+)/gi,

// parsing token regexes parseTokenOneOrTwoDigits = /\d\d?/, // 0 - 99 parseTokenOneToThreeDigits = /\d{1,3}/, // 0 - 999 parseTokenThreeDigits = /\d{3}/, // 000 - 999 parseTokenFourDigits = /\d{1,4}/, // 0 - 9999 parseTokenSixDigits = /[+\-]?\d{1,6}/, // -999,999 - 999,999 parseTokenWord = /[0-9]*[a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF]+\s*?[\u0600-\u06FF]+/i, // any word (or two) characters or numbers including two word month in arabic. parseTokenTimezone = /Z|[\+\-]\d\d:?\d\d/i, // +00:00 -00:00 +0000 -0000 or Z       parseTokenT = /T/i, // T (ISO seperator) parseTokenTimestampMs = /[\+\-]?\d+(\.\d{1,3})?/, // 123456789 123456789.123

// preliminary iso regex // 0000-00-00 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 isoRegex = /^\s*\d{4}-\d\d-\d\d((T| )(\d\d(:\d\d(:\d\d(\.\d\d?\d?)?)?)?)?([\+\-]\d\d:?\d\d)?)?/, isoFormat = 'YYYY-MM-DDTHH:mm:ssZ',

// iso time formats and regexes isoTimes = [ ['HH:mm:ss.S', /(T| )\d\d:\d\d:\d\d\.\d{1,3}/], ['HH:mm:ss', /(T| )\d\d:\d\d:\d\d/], ['HH:mm', /(T| )\d\d:\d\d/], ['HH', /(T| )\d\d/] ],

// timezone chunker "+10:00" > ["10", "00"] or "-1530" > ["-15", "30"] parseTimezoneChunker = /([\+\-]|\d\d)/gi,

// getter and setter names proxyGettersAndSetters = 'Month|Date|Hours|Minutes|Seconds|Milliseconds'.split('|'), unitMillisecondFactors = { 'Milliseconds' : 1, 'Seconds' : 1e3, 'Minutes' : 6e4, 'Hours' : 36e5, 'Days' : 864e5, 'Months' : 2592e6, 'Years' : 31536e6 },

// format function strings formatFunctions = {},

// tokens to ordinalize and pad ordinalizeTokens = 'DDD w W M D d'.split(' '), paddedTokens = 'M D H h m s w W'.split(' '),

formatTokenFunctions = { M   : function  { return this.month + 1; },           MMM  : function (format) { return this.lang.monthsShort(this, format); },           MMMM : function (format) { return this.lang.months(this, format); },           D    : function  { return this.date; },           DDD  : function  { return this.dayOfYear; },           d    : function  { return this.day; },           dd   : function (format) { return this.lang.weekdaysMin(this, format); },           ddd  : function (format) { return this.lang.weekdaysShort(this, format); },           dddd : function (format) { return this.lang.weekdays(this, format); },           w    : function  { return this.week; },           W    : function  { return this.isoWeek; },           YY   : function  { return leftZeroFill(this.year % 100, 2); },           YYYY : function  { return leftZeroFill(this.year, 4); },           YYYYY : function  { return leftZeroFill(this.year, 5); },           a    : function  { return this.lang.meridiem(this.hours, this.minutes, true); },           A    : function  { return this.lang.meridiem(this.hours, this.minutes, false); },           H    : function  { return this.hours; },           h    : function  { return this.hours % 12 || 12; },           m    : function  { return this.minutes; },           s    : function  { return this.seconds; },           S    : function  { return (this.milliseconds / 100); },           SS   : function  { return leftZeroFill((this.milliseconds / 10), 2); },           SSS  : function  { return leftZeroFill(this.milliseconds, 3); },           Z    : function  { var a = -this.zone, b = "+"; if (a < 0) { a = -a; b = "-"; }               return b + leftZeroFill((a / 60), 2) + ":" + leftZeroFill(a % 60, 2); },           ZZ   : function  { var a = -this.zone, b = "+"; if (a < 0) { a = -a; b = "-"; }               return b + leftZeroFill((10 * a / 6), 4); },           X    : function  { return this.unix; }       };

function padToken(func, count) { return function (a) { return leftZeroFill(func.call(this, a), count); };   }    function ordinalizeToken(func) { return function (a) { return this.lang.ordinal(func.call(this, a)); };   }

while (ordinalizeTokens.length) { i = ordinalizeTokens.pop; formatTokenFunctions[i + 'o'] = ordinalizeToken(formatTokenFunctions[i]); }   while (paddedTokens.length) { i = paddedTokens.pop; formatTokenFunctions[i + i] = padToken(formatTokenFunctions[i], 2); }   formatTokenFunctions.DDDD = padToken(formatTokenFunctions.DDD, 3);

/************************************       Constructors ************************************/

function Language {

}

// Moment prototype object function Moment(config) { extend(this, config); }

// Duration Constructor function Duration(duration) { var data = this._data = {}, years = duration.years || duration.year || duration.y || 0, months = duration.months || duration.month || duration.M || 0, weeks = duration.weeks || duration.week || duration.w || 0, days = duration.days || duration.day || duration.d || 0, hours = duration.hours || duration.hour || duration.h || 0, minutes = duration.minutes || duration.minute || duration.m || 0, seconds = duration.seconds || duration.second || duration.s || 0, milliseconds = duration.milliseconds || duration.millisecond || duration.ms || 0;

// representation for dateAddRemove this._milliseconds = milliseconds + seconds * 1e3 + // 1000 minutes * 6e4 + // 1000 * 60 hours * 36e5; // 1000 * 60 * 60 // Because of dateAddRemove treats 24 hours as different from a       // day when working around DST, we need to store them separately this._days = days + weeks * 7; // It is impossible translate months into days without knowing // which months you are are talking about, so we have to store // it separately. this._months = months + years * 12;

// The following code bubbles up values, see the tests for // examples of what that means. data.milliseconds = milliseconds % 1000; seconds += absRound(milliseconds / 1000);

data.seconds = seconds % 60; minutes += absRound(seconds / 60);

data.minutes = minutes % 60; hours += absRound(minutes / 60);

data.hours = hours % 24; days += absRound(hours / 24);

days += weeks * 7; data.days = days % 30;

months += absRound(days / 30);

data.months = months % 12; years += absRound(months / 12);

data.years = years; }

/************************************       Helpers ************************************/

function extend(a, b) { for (var i in b) { if (b.hasOwnProperty(i)) { a[i] = b[i]; }       }        return a;    }

function absRound(number) { if (number < 0) { return Math.ceil(number); } else { return Math.floor(number); }   }

// left zero fill a number // see http://jsperf.com/left-zero-filling for performance comparison function leftZeroFill(number, targetLength) { var output = number + ''; while (output.length < targetLength) { output = '0' + output; }       return output; }

// helper function for _.addTime and _.subtractTime function addOrSubtractDurationFromMoment(mom, duration, isAdding) { var ms = duration._milliseconds, d = duration._days, M = duration._months, currentDate;

if (ms) { mom._d.setTime(+mom + ms * isAdding); }       if (d) { mom.date(mom.date + d * isAdding); }       if (M) { currentDate = mom.date; mom.date(1) .month(mom.month + M * isAdding) .date(Math.min(currentDate, mom.daysInMonth)); }   }

// check if is an array function isArray(input) { return Object.prototype.toString.call(input) === '[object Array]'; }

// compare two arrays, return the number of differences function compareArrays(array1, array2) { var len = Math.min(array1.length, array2.length), lengthDiff = Math.abs(array1.length - array2.length), diffs = 0, i;       for (i = 0; i < len; i++) { if (array1[i] !== array2[i]) { diffs++; }       }        return diffs + lengthDiff; }

/************************************       Languages ************************************/

Language.prototype = { set : function (config) { var prop, i;           for (i in config) { prop = config[i]; if (typeof prop === 'function') { this[i] = prop; } else { this['_' + i] = prop; }           }        },

_months : "January_February_March_April_May_June_July_August_September_October_November_December".split("_"), months : function (m) { return this._months[m.month]; },

_monthsShort : "Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"), monthsShort : function (m) { return this._monthsShort[m.month]; },

monthsParse : function (monthName) { var i, mom, regex, output;

if (!this._monthsParse) { this._monthsParse = []; }

for (i = 0; i < 12; i++) { // make the regex if we don't have it already if (!this._monthsParse[i]) { mom = moment([2000, i]); regex = '^' + this.months(mom, ) + '|^' + this.monthsShort(mom, ); this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i'); }               // test the regex if (this._monthsParse[i].test(monthName)) { return i;               } }       },

_weekdays : "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"), weekdays : function (m) { return this._weekdays[m.day]; },

_weekdaysShort : "Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"), weekdaysShort : function (m) { return this._weekdaysShort[m.day]; },

_weekdaysMin : "Su_Mo_Tu_We_Th_Fr_Sa".split("_"), weekdaysMin : function (m) { return this._weekdaysMin[m.day]; },

_longDateFormat : { LT : "h:mm A", L : "MM/DD/YYYY", LL : "MMMM D YYYY", LLL : "MMMM D YYYY LT", LLLL : "dddd, MMMM D YYYY LT" },       longDateFormat : function (key) { var output = this._longDateFormat[key]; if (!output && this._longDateFormat[key.toUpperCase]) { output = this._longDateFormat[key.toUpperCase].replace(/MMMM|MM|DD|dddd/g, function (val) {                   return val.slice(1);                }); this._longDateFormat[key] = output; }           return output; },

meridiem : function (hours, minutes, isLower) { if (hours > 11) { return isLower ? 'pm' : 'PM'; } else { return isLower ? 'am' : 'AM'; }       },

_calendar : { sameDay : '[Today at] LT', nextDay : '[Tomorrow at] LT', nextWeek : 'dddd [at] LT', lastDay : '[Yesterday at] LT', lastWeek : '[last] dddd [at] LT', sameElse : 'L'       }, calendar : function (key, mom) { var output = this._calendar[key]; return typeof output === 'function' ? output.apply(mom) : output; },

_relativeTime : { future : "in %s", past : "%s ago", s : "a few seconds", m : "a minute", mm : "%d minutes", h : "an hour", hh : "%d hours", d : "a day", dd : "%d days", M : "a month", MM : "%d months", y : "a year", yy : "%d years" },       relativeTime : function (number, withoutSuffix, string, isFuture) { var output = this._relativeTime[string]; return (typeof output === 'function') ? output(number, withoutSuffix, string, isFuture) : output.replace(/%d/i, number); },       pastFuture : function (diff, output) { var format = this._relativeTime[diff > 0 ? 'future' : 'past']; return typeof format === 'function' ? format(output) : format.replace(/%s/i, output); },

ordinal : function (number) { return this._ordinal.replace("%d", number); },       _ordinal : "%d",

preparse : function (string) { return string; },

postformat : function (string) { return string; },

week : function (mom) { return weekOfYear(mom, this._week.dow, this._week.doy); },       _week : { dow : 0, // Sunday is the first day of the week. doy : 6 // The week that contains Jan 1st is the first week of the year. }   };

// Loads a language definition into the `languages` cache. The function // takes a key and optionally values. If not in the browser and no values // are provided, it will load the language file module. As a convenience, // this function also returns the language values. function loadLang(key, values) { values.abbr = key; if (!languages[key]) { languages[key] = new Language; }       languages[key].set(values); return languages[key]; }

// Determines which language definition to use and returns it. //   // With no parameters, it will return the global language. If you // pass in a language key, such as 'en', it will return the // definition for 'en', so long as 'en' has already been loaded using // moment.lang. function getLangDefinition(key) { if (!key) { return moment.fn._lang; }       if (!languages[key] && hasModule) { require('./lang/' + key); }       return languages[key]; }

/************************************       Formatting ************************************/

function removeFormattingTokens(input) { if (input.match(/\[.*\]/)) { return input.replace(/^\[|\]$/g, ""); }       return input.replace(/\\/g, ""); }

function makeFormatFunction(format) { var array = format.match(formattingTokens), i, length;

for (i = 0, length = array.length; i < length; i++) { if (formatTokenFunctions[array[i]]) { array[i] = formatTokenFunctions[array[i]]; } else { array[i] = removeFormattingTokens(array[i]); }       }

return function (mom) { var output = ""; for (i = 0; i < length; i++) { output += typeof array[i].call === 'function' ? array[i].call(mom, format) : array[i]; }           return output; };   }

// format date using native date object function formatMoment(m, format) { var i = 5;

function replaceLongDateFormatTokens(input) { return m.lang.longDateFormat(input) || input; }

while (i-- && localFormattingTokens.test(format)) { format = format.replace(localFormattingTokens, replaceLongDateFormatTokens); }

if (!formatFunctions[format]) { formatFunctions[format] = makeFormatFunction(format); }

return formatFunctions[format](m); }

/************************************       Parsing ************************************/

// get the regex to find the next token function getParseRegexForToken(token) { switch (token) { case 'DDDD': return parseTokenThreeDigits; case 'YYYY': return parseTokenFourDigits; case 'YYYYY': return parseTokenSixDigits; case 'S': case 'SS': case 'SSS': case 'DDD': return parseTokenOneToThreeDigits; case 'MMM': case 'MMMM': case 'dd': case 'ddd': case 'dddd': case 'a': case 'A': return parseTokenWord; case 'X': return parseTokenTimestampMs; case 'Z': case 'ZZ': return parseTokenTimezone; case 'T': return parseTokenT; case 'MM': case 'DD': case 'YY': case 'HH': case 'hh': case 'mm': case 'ss': case 'M': case 'D': case 'd': case 'H': case 'h': case 'm': case 's': return parseTokenOneOrTwoDigits; default : return new RegExp(token.replace('\\', '')); }   }

// function to convert string input to date function addTimeToArrayFromToken(token, input, config) { var a, b,           datePartArray = config._a;

switch (token) { // MONTH case 'M' : // fall through to MM       case 'MM' : datePartArray[1] = (input == null) ? 0 : input - 1; break; case 'MMM' : // fall through to MMMM case 'MMMM' : a = getLangDefinition(config._l).monthsParse(input); // if we didn't find a month name, mark the date as invalid. if (a != null) { datePartArray[1] = a;           } else { config._isValid = false; }           break; // DAY OF MONTH case 'D' : // fall through to DDDD case 'DD' : // fall through to DDDD case 'DDD' : // fall through to DDDD case 'DDDD' : if (input != null) { datePartArray[2] = input; }           break; // YEAR case 'YY' : datePartArray[0] = input + (input > 68 ? 1900 : 2000); break; case 'YYYY' : case 'YYYYY' : datePartArray[0] = input; break; // AM / PM       case 'a' : // fall through to A        case 'A' : config._isPm = ((input + '').toLowerCase === 'pm'); break; // 24 HOUR case 'H' : // fall through to hh       case 'HH' : // fall through to hh        case 'h' : // fall through to hh        case 'hh' : datePartArray[3] = input; break; // MINUTE case 'm' : // fall through to mm       case 'mm' : datePartArray[4] = input; break; // SECOND case 's' : // fall through to ss       case 'ss' : datePartArray[5] = input; break; // MILLISECOND case 'S' : case 'SS' : case 'SSS' : datePartArray[6] = (('0.' + input) * 1000); break; // UNIX TIMESTAMP WITH MS       case 'X': config._d = new Date(parseFloat(input) * 1000); break; // TIMEZONE case 'Z' : // fall through to ZZ       case 'ZZ' : config._useUTC = true; a = (input + '').match(parseTimezoneChunker); if (a && a[1]) { config._tzh = a[1]; }           if (a && a[2]) { config._tzm = a[2]; }           // reverse offsets if (a && a[0] === '+') { config._tzh = -config._tzh; config._tzm = -config._tzm; }           break; }

// if the input is null, the date is not valid if (input == null) { config._isValid = false; }   }

// convert an array to a date. // the array should mirror the parameters below // note: all values past the year are optional and will default to the lowest possible value. // [year, month, day, hour, minute, second, millisecond] function dateFromArray(config) { var i, date, input = [];

if (config._d) { return; }

for (i = 0; i < 7; i++) { config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i]; }

// add the offsets to the time to be parsed so that we can have a clean array for checking isValid input[3] += config._tzh || 0; input[4] += config._tzm || 0;

date = new Date(0);

if (config._useUTC) { date.setUTCFullYear(input[0], input[1], input[2]); date.setUTCHours(input[3], input[4], input[5], input[6]); } else { date.setFullYear(input[0], input[1], input[2]); date.setHours(input[3], input[4], input[5], input[6]); }

config._d = date; }

// date from string and format string function makeDateFromStringAndFormat(config) { // This array is used to make a Date, either with `new Date` or `Date.UTC` var tokens = config._f.match(formattingTokens), string = config._i, i, parsedInput;

config._a = [];

for (i = 0; i < tokens.length; i++) { parsedInput = (getParseRegexForToken(tokens[i]).exec(string) || [])[0]; if (parsedInput) { string = string.slice(string.indexOf(parsedInput) + parsedInput.length); }           // don't parse if its not a known token if (formatTokenFunctions[tokens[i]]) { addTimeToArrayFromToken(tokens[i], parsedInput, config); }       }        // handle am pm        if (config._isPm && config._a[3] < 12) { config._a[3] += 12; }       // if is 12 am, change hours to 0 if (config._isPm === false && config._a[3] === 12) { config._a[3] = 0; }       // return dateFromArray(config); }

// date from string and array of format strings function makeDateFromStringAndArray(config) { var tempConfig, tempMoment, bestMoment,

scoreToBeat = 99, i,           currentDate, currentScore;

while (config._f.length) { tempConfig = extend({}, config); tempConfig._f = config._f.pop; makeDateFromStringAndFormat(tempConfig); tempMoment = new Moment(tempConfig);

if (tempMoment.isValid) { bestMoment = tempMoment; break; }

currentScore = compareArrays(tempConfig._a, tempMoment.toArray);

if (currentScore < scoreToBeat) { scoreToBeat = currentScore; bestMoment = tempMoment; }       }

extend(config, bestMoment); }

// date from iso format function makeDateFromString(config) { var i,           string = config._i; if (isoRegex.exec(string)) { config._f = 'YYYY-MM-DDT'; for (i = 0; i < 4; i++) { if (isoTimes[i][1].exec(string)) { config._f += isoTimes[i][0]; break; }           }            if (parseTokenTimezone.exec(string)) { config._f += " Z"; }           makeDateFromStringAndFormat(config); } else { config._d = new Date(string); }   }

function makeDateFromInput(config) { var input = config._i, matched = aspNetJsonRegex.exec(input);

if (input === undefined) { config._d = new Date; } else if (matched) { config._d = new Date(+matched[1]); } else if (typeof input === 'string') { makeDateFromString(config); } else if (isArray(input)) { config._a = input.slice(0); dateFromArray(config); } else { config._d = input instanceof Date ? new Date(+input) : new Date(input); }   }

/************************************       Relative Time ************************************/

// helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize function substituteTimeAgo(string, number, withoutSuffix, isFuture, lang) { return lang.relativeTime(number || 1, !!withoutSuffix, string, isFuture); }

function relativeTime(milliseconds, withoutSuffix, lang) { var seconds = round(Math.abs(milliseconds) / 1000), minutes = round(seconds / 60), hours = round(minutes / 60), days = round(hours / 24), years = round(days / 365), args = seconds < 45 && ['s', seconds] || minutes === 1 && ['m'] || minutes < 45 && ['mm', minutes] || hours === 1 && ['h'] || hours < 22 && ['hh', hours] || days === 1 && ['d'] || days <= 25 && ['dd', days] || days <= 45 && ['M'] || days < 345 && ['MM', round(days / 30)] || years === 1 && ['y'] || ['yy', years]; args[2] = withoutSuffix; args[3] = milliseconds > 0; args[4] = lang; return substituteTimeAgo.apply({}, args); }

/************************************       Week of Year ************************************/

// firstDayOfWeek      0 = sun, 6 = sat //                     the day of the week that starts the week //                     (usually sunday or monday) // firstDayOfWeekOfYear 0 = sun, 6 = sat //                     the first week is the week that contains the first //                     of this day of the week //                     (eg. ISO weeks use thursday (4)) function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) { var end = firstDayOfWeekOfYear - firstDayOfWeek, daysToDayOfWeek = firstDayOfWeekOfYear - mom.day;

if (daysToDayOfWeek > end) { daysToDayOfWeek -= 7; }

if (daysToDayOfWeek < end - 7) { daysToDayOfWeek += 7; }

return Math.ceil(moment(mom).add('d', daysToDayOfWeek).dayOfYear / 7); }

/************************************       Top Level Functions ************************************/

function makeMoment(config) { var input = config._i, format = config._f;

if (input === null || input === '') { return null; }

if (typeof input === 'string') { config._i = input = getLangDefinition.preparse(input); }

if (moment.isMoment(input)) { config = extend({}, input); config._d = new Date(+input._d); } else if (format) { if (isArray(format)) { makeDateFromStringAndArray(config); } else { makeDateFromStringAndFormat(config); }       } else { makeDateFromInput(config); }

return new Moment(config); }

moment = function (input, format, lang) { return makeMoment({           _i : input,            _f : format,            _l : lang,            _isUTC : false        }); };

// creating with utc moment.utc = function (input, format, lang) { return makeMoment({           _useUTC : true,            _isUTC : true,            _l : lang,            _i : input,            _f : format        }); };

// creating with unix timestamp (in seconds) moment.unix = function (input) { return moment(input * 1000); };

// duration moment.duration = function (input, key) { var isDuration = moment.isDuration(input), isNumber = (typeof input === 'number'), duration = (isDuration ? input._data : (isNumber ? {} : input)), ret;

if (isNumber) { if (key) { duration[key] = input; } else { duration.milliseconds = input; }       }

ret = new Duration(duration);

if (isDuration && input.hasOwnProperty('_lang')) { ret._lang = input._lang; }

return ret; };

// version number moment.version = VERSION;

// default format moment.defaultFormat = isoFormat;

// This function will load languages and then set the global language. If   // no arguments are passed in, it will simply return the current global // language key. moment.lang = function (key, values) { var i;

if (!key) { return moment.fn._lang._abbr; }       if (values) { loadLang(key, values); } else if (!languages[key]) { getLangDefinition(key); }       moment.duration.fn._lang = moment.fn._lang = getLangDefinition(key); };

// returns language data moment.langData = function (key) { if (key && key._lang && key._lang._abbr) { key = key._lang._abbr; }       return getLangDefinition(key); };

// compare moment object moment.isMoment = function (obj) { return obj instanceof Moment; };

// for typechecking Duration objects moment.isDuration = function (obj) { return obj instanceof Duration; };

/************************************       Moment Prototype ************************************/

moment.fn = Moment.prototype = {

clone : function { return moment(this); },

valueOf : function { return +this._d; },

unix : function { return Math.floor(+this._d / 1000); },

toString : function { return this.format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ"); },

toDate : function { return this._d; },

toJSON : function { return moment.utc(this).format('YYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); },

toArray : function { var m = this; return [ m.year, m.month, m.date, m.hours, m.minutes, m.seconds, m.milliseconds ];       },

isValid : function { if (this._isValid == null) { if (this._a) { this._isValid = !compareArrays(this._a, (this._isUTC ? moment.utc(this._a) : moment(this._a)).toArray); } else { this._isValid = !isNaN(this._d.getTime); }           }            return !!this._isValid; },

utc : function { this._isUTC = true; return this; },

local : function { this._isUTC = false; return this; },

format : function (inputString) { var output = formatMoment(this, inputString || moment.defaultFormat); return this.lang.postformat(output); },

add : function (input, val) { var dur; // switch args to support add('s', 1) and add(1, 's') if (typeof input === 'string') { dur = moment.duration(+val, input); } else { dur = moment.duration(input, val); }           addOrSubtractDurationFromMoment(this, dur, 1); return this; },

subtract : function (input, val) { var dur; // switch args to support subtract('s', 1) and subtract(1, 's') if (typeof input === 'string') { dur = moment.duration(+val, input); } else { dur = moment.duration(input, val); }           addOrSubtractDurationFromMoment(this, dur, -1); return this; },

diff : function (input, units, asFloat) { var that = this._isUTC ? moment(input).utc : moment(input).local, zoneDiff = (this.zone - that.zone) * 6e4, diff, output;

if (units) { // standardize on singular form units = units.replace(/s$/, ''); }

if (units === 'year' || units === 'month') { diff = (this.daysInMonth + that.daysInMonth) * 432e5; // 24 * 60 * 60 * 1000 / 2 output = ((this.year - that.year) * 12) + (this.month - that.month); output += ((this - moment(this).startOf('month')) - (that - moment(that).startOf('month'))) / diff; if (units === 'year') { output = output / 12; }           } else { diff = (this - that) - zoneDiff; output = units === 'second' ? diff / 1e3 : // 1000 units === 'minute' ? diff / 6e4 : // 1000 * 60 units === 'hour' ? diff / 36e5 : // 1000 * 60 * 60 units === 'day' ? diff / 864e5 : // 1000 * 60 * 60 * 24 units === 'week' ? diff / 6048e5 : // 1000 * 60 * 60 * 24 * 7 diff; }           return asFloat ? output : absRound(output); },

from : function (time, withoutSuffix) { return moment.duration(this.diff(time)).lang(this.lang._abbr).humanize(!withoutSuffix); },

fromNow : function (withoutSuffix) { return this.from(moment, withoutSuffix); },

calendar : function { var diff = this.diff(moment.startOf('day'), 'days', true), format = diff < -6 ? 'sameElse' : diff < -1 ? 'lastWeek' : diff < 0 ? 'lastDay' : diff < 1 ? 'sameDay' : diff < 2 ? 'nextDay' : diff < 7 ? 'nextWeek' : 'sameElse'; return this.format(this.lang.calendar(format, this)); },

isLeapYear : function { var year = this.year; return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; },

isDST : function { return (this.zone < moment([this.year]).zone ||               this.zone < moment([this.year, 5]).zone); },

day : function (input) { var day = this._isUTC ? this._d.getUTCDay : this._d.getDay; return input == null ? day : this.add({ d : input - day }); },

startOf: function (units) { units = units.replace(/s$/, ''); // the following switch intentionally omits break keywords // to utilize falling through the cases. switch (units) { case 'year': this.month(0); /* falls through */ case 'month': this.date(1); /* falls through */ case 'week': case 'day': this.hours(0); /* falls through */ case 'hour': this.minutes(0); /* falls through */ case 'minute': this.seconds(0); /* falls through */ case 'second': this.milliseconds(0); /* falls through */ }

// weeks are a special case if (units === 'week') { this.day(0); }

return this; },

endOf: function (units) { return this.startOf(units).add(units.replace(/s?$/, 's'), 1).subtract('ms', 1); },

isAfter: function (input, units) { units = typeof units !== 'undefined' ? units : 'millisecond'; return +this.clone.startOf(units) > +moment(input).startOf(units); },

isBefore: function (input, units) { units = typeof units !== 'undefined' ? units : 'millisecond'; return +this.clone.startOf(units) < +moment(input).startOf(units); },

isSame: function (input, units) { units = typeof units !== 'undefined' ? units : 'millisecond'; return +this.clone.startOf(units) === +moment(input).startOf(units); },

zone : function { return this._isUTC ? 0 : this._d.getTimezoneOffset; },

daysInMonth : function { return moment.utc([this.year, this.month + 1, 0]).date; },

dayOfYear : function (input) { var dayOfYear = round((moment(this).startOf('day') - moment(this).startOf('year')) / 864e5) + 1; return input == null ? dayOfYear : this.add("d", (input - dayOfYear)); },

isoWeek : function (input) { var week = weekOfYear(this, 1, 4); return input == null ? week : this.add("d", (input - week) * 7); },

week : function (input) { var week = this.lang.week(this); return input == null ? week : this.add("d", (input - week) * 7); },

// If passed a language key, it will set the language for this // instance. Otherwise, it will return the language configuration // variables for this instance. lang : function (key) { if (key === undefined) { return this._lang; } else { this._lang = getLangDefinition(key); return this; }       }    };

// helper for adding shortcuts function makeGetterAndSetter(name, key) { moment.fn[name] = moment.fn[name + 's'] = function (input) { var utc = this._isUTC ? 'UTC' : ''; if (input != null) { this._d['set' + utc + key](input); return this; } else { return this._d['get' + utc + key]; }       };    }

// loop through and add shortcuts (Month, Date, Hours, Minutes, Seconds, Milliseconds) for (i = 0; i < proxyGettersAndSetters.length; i ++) { makeGetterAndSetter(proxyGettersAndSetters[i].toLowerCase.replace(/s$/, ''), proxyGettersAndSetters[i]); }

// add shortcut for year (uses different syntax than the getter/setter 'year' == 'FullYear') makeGetterAndSetter('year', 'FullYear');

// add plural methods moment.fn.days = moment.fn.day; moment.fn.weeks = moment.fn.week; moment.fn.isoWeeks = moment.fn.isoWeek;

/************************************       Duration Prototype ************************************/

moment.duration.fn = Duration.prototype = { weeks : function { return absRound(this.days / 7); },

valueOf : function { return this._milliseconds + this._days * 864e5 + this._months * 2592e6; },

humanize : function (withSuffix) { var difference = +this, output = relativeTime(difference, !withSuffix, this.lang);

if (withSuffix) { output = this.lang.pastFuture(difference, output); }

return this.lang.postformat(output); },

lang : moment.fn.lang };

function makeDurationGetter(name) { moment.duration.fn[name] = function { return this._data[name]; };   }

function makeDurationAsGetter(name, factor) { moment.duration.fn['as' + name] = function { return +this / factor; };   }

for (i in unitMillisecondFactors) { if (unitMillisecondFactors.hasOwnProperty(i)) { makeDurationAsGetter(i, unitMillisecondFactors[i]); makeDurationGetter(i.toLowerCase); }   }

makeDurationAsGetter('Weeks', 6048e5);

/************************************       Default Lang ************************************/

// Set default language, other languages will inherit from English. moment.lang('en', {       ordinal : function (number) {            var b = number % 10,                output = ( (number % 100 / 10) === 1) ? 'th' :                (b === 1) ? 'st' :                (b === 2) ? 'nd' :                (b === 3) ? 'rd' : 'th';            return number + output;        }    });

/************************************       Exposing Moment ************************************/

// CommonJS module is defined if (hasModule) { module.exports = moment; }   /*global ender:false */ if (typeof ender === 'undefined') { // here, `this` means `window` in the browser, or `global` on the server // add `moment` as a global object via a string identifier, // for Closure Compiler "advanced" mode this['moment'] = moment; }   /*global define:false */ if (typeof define === "function" && define.amd) { define("moment", [], function {            return moment;        }); } }).call(this);