Merge "Make validation for page more strict on djvu to take only numbers"
[mediawiki.git] / resources / lib / moment / moment.js
blob257ee7ec1a545e1115658e445008f78f364807c3
1 //! moment.js
2 //! version : 2.6.0
3 //! authors : Tim Wood, Iskren Chernev, Moment.js contributors
4 //! license : MIT
5 //! momentjs.com
7 (function (undefined) {
9     /************************************
10         Constants
11     ************************************/
13     var moment,
14         VERSION = "2.6.0",
15         // the global-scope this is NOT the global object in Node.js
16         globalScope = typeof global !== 'undefined' ? global : this,
17         oldGlobalMoment,
18         round = Math.round,
19         i,
21         YEAR = 0,
22         MONTH = 1,
23         DATE = 2,
24         HOUR = 3,
25         MINUTE = 4,
26         SECOND = 5,
27         MILLISECOND = 6,
29         // internal storage for language config files
30         languages = {},
32         // moment internal properties
33         momentProperties = {
34             _isAMomentObject: null,
35             _i : null,
36             _f : null,
37             _l : null,
38             _strict : null,
39             _isUTC : null,
40             _offset : null,  // optional. Combine with _isUTC
41             _pf : null,
42             _lang : null  // optional
43         },
45         // check for nodeJS
46         hasModule = (typeof module !== 'undefined' && module.exports),
48         // ASP.NET json date format regex
49         aspNetJsonRegex = /^\/?Date\((\-?\d+)/i,
50         aspNetTimeSpanJsonRegex = /(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/,
52         // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html
53         // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere
54         isoDurationRegex = /^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/,
56         // format tokens
57         formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Q|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|X|zz?|ZZ?|.)/g,
58         localFormattingTokens = /(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g,
60         // parsing token regexes
61         parseTokenOneOrTwoDigits = /\d\d?/, // 0 - 99
62         parseTokenOneToThreeDigits = /\d{1,3}/, // 0 - 999
63         parseTokenOneToFourDigits = /\d{1,4}/, // 0 - 9999
64         parseTokenOneToSixDigits = /[+\-]?\d{1,6}/, // -999,999 - 999,999
65         parseTokenDigits = /\d+/, // nonzero number of digits
66         parseTokenWord = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i, // any word (or two) characters or numbers including two/three word month in arabic.
67         parseTokenTimezone = /Z|[\+\-]\d\d:?\d\d/gi, // +00:00 -00:00 +0000 -0000 or Z
68         parseTokenT = /T/i, // T (ISO separator)
69         parseTokenTimestampMs = /[\+\-]?\d+(\.\d{1,3})?/, // 123456789 123456789.123
70         parseTokenOrdinal = /\d{1,2}/,
72         //strict parsing regexes
73         parseTokenOneDigit = /\d/, // 0 - 9
74         parseTokenTwoDigits = /\d\d/, // 00 - 99
75         parseTokenThreeDigits = /\d{3}/, // 000 - 999
76         parseTokenFourDigits = /\d{4}/, // 0000 - 9999
77         parseTokenSixDigits = /[+-]?\d{6}/, // -999,999 - 999,999
78         parseTokenSignedNumber = /[+-]?\d+/, // -inf - inf
80         // iso 8601 regex
81         // 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00)
82         isoRegex = /^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,
84         isoFormat = 'YYYY-MM-DDTHH:mm:ssZ',
86         isoDates = [
87             ['YYYYYY-MM-DD', /[+-]\d{6}-\d{2}-\d{2}/],
88             ['YYYY-MM-DD', /\d{4}-\d{2}-\d{2}/],
89             ['GGGG-[W]WW-E', /\d{4}-W\d{2}-\d/],
90             ['GGGG-[W]WW', /\d{4}-W\d{2}/],
91             ['YYYY-DDD', /\d{4}-\d{3}/]
92         ],
94         // iso time formats and regexes
95         isoTimes = [
96             ['HH:mm:ss.SSSS', /(T| )\d\d:\d\d:\d\d\.\d+/],
97             ['HH:mm:ss', /(T| )\d\d:\d\d:\d\d/],
98             ['HH:mm', /(T| )\d\d:\d\d/],
99             ['HH', /(T| )\d\d/]
100         ],
102         // timezone chunker "+10:00" > ["10", "00"] or "-1530" > ["-15", "30"]
103         parseTimezoneChunker = /([\+\-]|\d\d)/gi,
105         // getter and setter names
106         proxyGettersAndSetters = 'Date|Hours|Minutes|Seconds|Milliseconds'.split('|'),
107         unitMillisecondFactors = {
108             'Milliseconds' : 1,
109             'Seconds' : 1e3,
110             'Minutes' : 6e4,
111             'Hours' : 36e5,
112             'Days' : 864e5,
113             'Months' : 2592e6,
114             'Years' : 31536e6
115         },
117         unitAliases = {
118             ms : 'millisecond',
119             s : 'second',
120             m : 'minute',
121             h : 'hour',
122             d : 'day',
123             D : 'date',
124             w : 'week',
125             W : 'isoWeek',
126             M : 'month',
127             Q : 'quarter',
128             y : 'year',
129             DDD : 'dayOfYear',
130             e : 'weekday',
131             E : 'isoWeekday',
132             gg: 'weekYear',
133             GG: 'isoWeekYear'
134         },
136         camelFunctions = {
137             dayofyear : 'dayOfYear',
138             isoweekday : 'isoWeekday',
139             isoweek : 'isoWeek',
140             weekyear : 'weekYear',
141             isoweekyear : 'isoWeekYear'
142         },
144         // format function strings
145         formatFunctions = {},
147         // tokens to ordinalize and pad
148         ordinalizeTokens = 'DDD w W M D d'.split(' '),
149         paddedTokens = 'M D H h m s w W'.split(' '),
151         formatTokenFunctions = {
152             M    : function () {
153                 return this.month() + 1;
154             },
155             MMM  : function (format) {
156                 return this.lang().monthsShort(this, format);
157             },
158             MMMM : function (format) {
159                 return this.lang().months(this, format);
160             },
161             D    : function () {
162                 return this.date();
163             },
164             DDD  : function () {
165                 return this.dayOfYear();
166             },
167             d    : function () {
168                 return this.day();
169             },
170             dd   : function (format) {
171                 return this.lang().weekdaysMin(this, format);
172             },
173             ddd  : function (format) {
174                 return this.lang().weekdaysShort(this, format);
175             },
176             dddd : function (format) {
177                 return this.lang().weekdays(this, format);
178             },
179             w    : function () {
180                 return this.week();
181             },
182             W    : function () {
183                 return this.isoWeek();
184             },
185             YY   : function () {
186                 return leftZeroFill(this.year() % 100, 2);
187             },
188             YYYY : function () {
189                 return leftZeroFill(this.year(), 4);
190             },
191             YYYYY : function () {
192                 return leftZeroFill(this.year(), 5);
193             },
194             YYYYYY : function () {
195                 var y = this.year(), sign = y >= 0 ? '+' : '-';
196                 return sign + leftZeroFill(Math.abs(y), 6);
197             },
198             gg   : function () {
199                 return leftZeroFill(this.weekYear() % 100, 2);
200             },
201             gggg : function () {
202                 return leftZeroFill(this.weekYear(), 4);
203             },
204             ggggg : function () {
205                 return leftZeroFill(this.weekYear(), 5);
206             },
207             GG   : function () {
208                 return leftZeroFill(this.isoWeekYear() % 100, 2);
209             },
210             GGGG : function () {
211                 return leftZeroFill(this.isoWeekYear(), 4);
212             },
213             GGGGG : function () {
214                 return leftZeroFill(this.isoWeekYear(), 5);
215             },
216             e : function () {
217                 return this.weekday();
218             },
219             E : function () {
220                 return this.isoWeekday();
221             },
222             a    : function () {
223                 return this.lang().meridiem(this.hours(), this.minutes(), true);
224             },
225             A    : function () {
226                 return this.lang().meridiem(this.hours(), this.minutes(), false);
227             },
228             H    : function () {
229                 return this.hours();
230             },
231             h    : function () {
232                 return this.hours() % 12 || 12;
233             },
234             m    : function () {
235                 return this.minutes();
236             },
237             s    : function () {
238                 return this.seconds();
239             },
240             S    : function () {
241                 return toInt(this.milliseconds() / 100);
242             },
243             SS   : function () {
244                 return leftZeroFill(toInt(this.milliseconds() / 10), 2);
245             },
246             SSS  : function () {
247                 return leftZeroFill(this.milliseconds(), 3);
248             },
249             SSSS : function () {
250                 return leftZeroFill(this.milliseconds(), 3);
251             },
252             Z    : function () {
253                 var a = -this.zone(),
254                     b = "+";
255                 if (a < 0) {
256                     a = -a;
257                     b = "-";
258                 }
259                 return b + leftZeroFill(toInt(a / 60), 2) + ":" + leftZeroFill(toInt(a) % 60, 2);
260             },
261             ZZ   : function () {
262                 var a = -this.zone(),
263                     b = "+";
264                 if (a < 0) {
265                     a = -a;
266                     b = "-";
267                 }
268                 return b + leftZeroFill(toInt(a / 60), 2) + leftZeroFill(toInt(a) % 60, 2);
269             },
270             z : function () {
271                 return this.zoneAbbr();
272             },
273             zz : function () {
274                 return this.zoneName();
275             },
276             X    : function () {
277                 return this.unix();
278             },
279             Q : function () {
280                 return this.quarter();
281             }
282         },
284         lists = ['months', 'monthsShort', 'weekdays', 'weekdaysShort', 'weekdaysMin'];
286     function defaultParsingFlags() {
287         // We need to deep clone this object, and es5 standard is not very
288         // helpful.
289         return {
290             empty : false,
291             unusedTokens : [],
292             unusedInput : [],
293             overflow : -2,
294             charsLeftOver : 0,
295             nullInput : false,
296             invalidMonth : null,
297             invalidFormat : false,
298             userInvalidated : false,
299             iso: false
300         };
301     }
303     function deprecate(msg, fn) {
304         var firstTime = true;
305         function printMsg() {
306             if (moment.suppressDeprecationWarnings === false &&
307                     typeof console !== 'undefined' && console.warn) {
308                 console.warn("Deprecation warning: " + msg);
309             }
310         }
311         return extend(function () {
312             if (firstTime) {
313                 printMsg();
314                 firstTime = false;
315             }
316             return fn.apply(this, arguments);
317         }, fn);
318     }
320     function padToken(func, count) {
321         return function (a) {
322             return leftZeroFill(func.call(this, a), count);
323         };
324     }
325     function ordinalizeToken(func, period) {
326         return function (a) {
327             return this.lang().ordinal(func.call(this, a), period);
328         };
329     }
331     while (ordinalizeTokens.length) {
332         i = ordinalizeTokens.pop();
333         formatTokenFunctions[i + 'o'] = ordinalizeToken(formatTokenFunctions[i], i);
334     }
335     while (paddedTokens.length) {
336         i = paddedTokens.pop();
337         formatTokenFunctions[i + i] = padToken(formatTokenFunctions[i], 2);
338     }
339     formatTokenFunctions.DDDD = padToken(formatTokenFunctions.DDD, 3);
342     /************************************
343         Constructors
344     ************************************/
346     function Language() {
348     }
350     // Moment prototype object
351     function Moment(config) {
352         checkOverflow(config);
353         extend(this, config);
354     }
356     // Duration Constructor
357     function Duration(duration) {
358         var normalizedInput = normalizeObjectUnits(duration),
359             years = normalizedInput.year || 0,
360             quarters = normalizedInput.quarter || 0,
361             months = normalizedInput.month || 0,
362             weeks = normalizedInput.week || 0,
363             days = normalizedInput.day || 0,
364             hours = normalizedInput.hour || 0,
365             minutes = normalizedInput.minute || 0,
366             seconds = normalizedInput.second || 0,
367             milliseconds = normalizedInput.millisecond || 0;
369         // representation for dateAddRemove
370         this._milliseconds = +milliseconds +
371             seconds * 1e3 + // 1000
372             minutes * 6e4 + // 1000 * 60
373             hours * 36e5; // 1000 * 60 * 60
374         // Because of dateAddRemove treats 24 hours as different from a
375         // day when working around DST, we need to store them separately
376         this._days = +days +
377             weeks * 7;
378         // It is impossible translate months into days without knowing
379         // which months you are are talking about, so we have to store
380         // it separately.
381         this._months = +months +
382             quarters * 3 +
383             years * 12;
385         this._data = {};
387         this._bubble();
388     }
390     /************************************
391         Helpers
392     ************************************/
395     function extend(a, b) {
396         for (var i in b) {
397             if (b.hasOwnProperty(i)) {
398                 a[i] = b[i];
399             }
400         }
402         if (b.hasOwnProperty("toString")) {
403             a.toString = b.toString;
404         }
406         if (b.hasOwnProperty("valueOf")) {
407             a.valueOf = b.valueOf;
408         }
410         return a;
411     }
413     function cloneMoment(m) {
414         var result = {}, i;
415         for (i in m) {
416             if (m.hasOwnProperty(i) && momentProperties.hasOwnProperty(i)) {
417                 result[i] = m[i];
418             }
419         }
421         return result;
422     }
424     function absRound(number) {
425         if (number < 0) {
426             return Math.ceil(number);
427         } else {
428             return Math.floor(number);
429         }
430     }
432     // left zero fill a number
433     // see http://jsperf.com/left-zero-filling for performance comparison
434     function leftZeroFill(number, targetLength, forceSign) {
435         var output = '' + Math.abs(number),
436             sign = number >= 0;
438         while (output.length < targetLength) {
439             output = '0' + output;
440         }
441         return (sign ? (forceSign ? '+' : '') : '-') + output;
442     }
444     // helper function for _.addTime and _.subtractTime
445     function addOrSubtractDurationFromMoment(mom, duration, isAdding, updateOffset) {
446         var milliseconds = duration._milliseconds,
447             days = duration._days,
448             months = duration._months;
449         updateOffset = updateOffset == null ? true : updateOffset;
451         if (milliseconds) {
452             mom._d.setTime(+mom._d + milliseconds * isAdding);
453         }
454         if (days) {
455             rawSetter(mom, 'Date', rawGetter(mom, 'Date') + days * isAdding);
456         }
457         if (months) {
458             rawMonthSetter(mom, rawGetter(mom, 'Month') + months * isAdding);
459         }
460         if (updateOffset) {
461             moment.updateOffset(mom, days || months);
462         }
463     }
465     // check if is an array
466     function isArray(input) {
467         return Object.prototype.toString.call(input) === '[object Array]';
468     }
470     function isDate(input) {
471         return  Object.prototype.toString.call(input) === '[object Date]' ||
472                 input instanceof Date;
473     }
475     // compare two arrays, return the number of differences
476     function compareArrays(array1, array2, dontConvert) {
477         var len = Math.min(array1.length, array2.length),
478             lengthDiff = Math.abs(array1.length - array2.length),
479             diffs = 0,
480             i;
481         for (i = 0; i < len; i++) {
482             if ((dontConvert && array1[i] !== array2[i]) ||
483                 (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) {
484                 diffs++;
485             }
486         }
487         return diffs + lengthDiff;
488     }
490     function normalizeUnits(units) {
491         if (units) {
492             var lowered = units.toLowerCase().replace(/(.)s$/, '$1');
493             units = unitAliases[units] || camelFunctions[lowered] || lowered;
494         }
495         return units;
496     }
498     function normalizeObjectUnits(inputObject) {
499         var normalizedInput = {},
500             normalizedProp,
501             prop;
503         for (prop in inputObject) {
504             if (inputObject.hasOwnProperty(prop)) {
505                 normalizedProp = normalizeUnits(prop);
506                 if (normalizedProp) {
507                     normalizedInput[normalizedProp] = inputObject[prop];
508                 }
509             }
510         }
512         return normalizedInput;
513     }
515     function makeList(field) {
516         var count, setter;
518         if (field.indexOf('week') === 0) {
519             count = 7;
520             setter = 'day';
521         }
522         else if (field.indexOf('month') === 0) {
523             count = 12;
524             setter = 'month';
525         }
526         else {
527             return;
528         }
530         moment[field] = function (format, index) {
531             var i, getter,
532                 method = moment.fn._lang[field],
533                 results = [];
535             if (typeof format === 'number') {
536                 index = format;
537                 format = undefined;
538             }
540             getter = function (i) {
541                 var m = moment().utc().set(setter, i);
542                 return method.call(moment.fn._lang, m, format || '');
543             };
545             if (index != null) {
546                 return getter(index);
547             }
548             else {
549                 for (i = 0; i < count; i++) {
550                     results.push(getter(i));
551                 }
552                 return results;
553             }
554         };
555     }
557     function toInt(argumentForCoercion) {
558         var coercedNumber = +argumentForCoercion,
559             value = 0;
561         if (coercedNumber !== 0 && isFinite(coercedNumber)) {
562             if (coercedNumber >= 0) {
563                 value = Math.floor(coercedNumber);
564             } else {
565                 value = Math.ceil(coercedNumber);
566             }
567         }
569         return value;
570     }
572     function daysInMonth(year, month) {
573         return new Date(Date.UTC(year, month + 1, 0)).getUTCDate();
574     }
576     function weeksInYear(year, dow, doy) {
577         return weekOfYear(moment([year, 11, 31 + dow - doy]), dow, doy).week;
578     }
580     function daysInYear(year) {
581         return isLeapYear(year) ? 366 : 365;
582     }
584     function isLeapYear(year) {
585         return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
586     }
588     function checkOverflow(m) {
589         var overflow;
590         if (m._a && m._pf.overflow === -2) {
591             overflow =
592                 m._a[MONTH] < 0 || m._a[MONTH] > 11 ? MONTH :
593                 m._a[DATE] < 1 || m._a[DATE] > daysInMonth(m._a[YEAR], m._a[MONTH]) ? DATE :
594                 m._a[HOUR] < 0 || m._a[HOUR] > 23 ? HOUR :
595                 m._a[MINUTE] < 0 || m._a[MINUTE] > 59 ? MINUTE :
596                 m._a[SECOND] < 0 || m._a[SECOND] > 59 ? SECOND :
597                 m._a[MILLISECOND] < 0 || m._a[MILLISECOND] > 999 ? MILLISECOND :
598                 -1;
600             if (m._pf._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) {
601                 overflow = DATE;
602             }
604             m._pf.overflow = overflow;
605         }
606     }
608     function isValid(m) {
609         if (m._isValid == null) {
610             m._isValid = !isNaN(m._d.getTime()) &&
611                 m._pf.overflow < 0 &&
612                 !m._pf.empty &&
613                 !m._pf.invalidMonth &&
614                 !m._pf.nullInput &&
615                 !m._pf.invalidFormat &&
616                 !m._pf.userInvalidated;
618             if (m._strict) {
619                 m._isValid = m._isValid &&
620                     m._pf.charsLeftOver === 0 &&
621                     m._pf.unusedTokens.length === 0;
622             }
623         }
624         return m._isValid;
625     }
627     function normalizeLanguage(key) {
628         return key ? key.toLowerCase().replace('_', '-') : key;
629     }
631     // Return a moment from input, that is local/utc/zone equivalent to model.
632     function makeAs(input, model) {
633         return model._isUTC ? moment(input).zone(model._offset || 0) :
634             moment(input).local();
635     }
637     /************************************
638         Languages
639     ************************************/
642     extend(Language.prototype, {
644         set : function (config) {
645             var prop, i;
646             for (i in config) {
647                 prop = config[i];
648                 if (typeof prop === 'function') {
649                     this[i] = prop;
650                 } else {
651                     this['_' + i] = prop;
652                 }
653             }
654         },
656         _months : "January_February_March_April_May_June_July_August_September_October_November_December".split("_"),
657         months : function (m) {
658             return this._months[m.month()];
659         },
661         _monthsShort : "Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),
662         monthsShort : function (m) {
663             return this._monthsShort[m.month()];
664         },
666         monthsParse : function (monthName) {
667             var i, mom, regex;
669             if (!this._monthsParse) {
670                 this._monthsParse = [];
671             }
673             for (i = 0; i < 12; i++) {
674                 // make the regex if we don't have it already
675                 if (!this._monthsParse[i]) {
676                     mom = moment.utc([2000, i]);
677                     regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, '');
678                     this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i');
679                 }
680                 // test the regex
681                 if (this._monthsParse[i].test(monthName)) {
682                     return i;
683                 }
684             }
685         },
687         _weekdays : "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),
688         weekdays : function (m) {
689             return this._weekdays[m.day()];
690         },
692         _weekdaysShort : "Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),
693         weekdaysShort : function (m) {
694             return this._weekdaysShort[m.day()];
695         },
697         _weekdaysMin : "Su_Mo_Tu_We_Th_Fr_Sa".split("_"),
698         weekdaysMin : function (m) {
699             return this._weekdaysMin[m.day()];
700         },
702         weekdaysParse : function (weekdayName) {
703             var i, mom, regex;
705             if (!this._weekdaysParse) {
706                 this._weekdaysParse = [];
707             }
709             for (i = 0; i < 7; i++) {
710                 // make the regex if we don't have it already
711                 if (!this._weekdaysParse[i]) {
712                     mom = moment([2000, 1]).day(i);
713                     regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, '');
714                     this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i');
715                 }
716                 // test the regex
717                 if (this._weekdaysParse[i].test(weekdayName)) {
718                     return i;
719                 }
720             }
721         },
723         _longDateFormat : {
724             LT : "h:mm A",
725             L : "MM/DD/YYYY",
726             LL : "MMMM D YYYY",
727             LLL : "MMMM D YYYY LT",
728             LLLL : "dddd, MMMM D YYYY LT"
729         },
730         longDateFormat : function (key) {
731             var output = this._longDateFormat[key];
732             if (!output && this._longDateFormat[key.toUpperCase()]) {
733                 output = this._longDateFormat[key.toUpperCase()].replace(/MMMM|MM|DD|dddd/g, function (val) {
734                     return val.slice(1);
735                 });
736                 this._longDateFormat[key] = output;
737             }
738             return output;
739         },
741         isPM : function (input) {
742             // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays
743             // Using charAt should be more compatible.
744             return ((input + '').toLowerCase().charAt(0) === 'p');
745         },
747         _meridiemParse : /[ap]\.?m?\.?/i,
748         meridiem : function (hours, minutes, isLower) {
749             if (hours > 11) {
750                 return isLower ? 'pm' : 'PM';
751             } else {
752                 return isLower ? 'am' : 'AM';
753             }
754         },
756         _calendar : {
757             sameDay : '[Today at] LT',
758             nextDay : '[Tomorrow at] LT',
759             nextWeek : 'dddd [at] LT',
760             lastDay : '[Yesterday at] LT',
761             lastWeek : '[Last] dddd [at] LT',
762             sameElse : 'L'
763         },
764         calendar : function (key, mom) {
765             var output = this._calendar[key];
766             return typeof output === 'function' ? output.apply(mom) : output;
767         },
769         _relativeTime : {
770             future : "in %s",
771             past : "%s ago",
772             s : "a few seconds",
773             m : "a minute",
774             mm : "%d minutes",
775             h : "an hour",
776             hh : "%d hours",
777             d : "a day",
778             dd : "%d days",
779             M : "a month",
780             MM : "%d months",
781             y : "a year",
782             yy : "%d years"
783         },
784         relativeTime : function (number, withoutSuffix, string, isFuture) {
785             var output = this._relativeTime[string];
786             return (typeof output === 'function') ?
787                 output(number, withoutSuffix, string, isFuture) :
788                 output.replace(/%d/i, number);
789         },
790         pastFuture : function (diff, output) {
791             var format = this._relativeTime[diff > 0 ? 'future' : 'past'];
792             return typeof format === 'function' ? format(output) : format.replace(/%s/i, output);
793         },
795         ordinal : function (number) {
796             return this._ordinal.replace("%d", number);
797         },
798         _ordinal : "%d",
800         preparse : function (string) {
801             return string;
802         },
804         postformat : function (string) {
805             return string;
806         },
808         week : function (mom) {
809             return weekOfYear(mom, this._week.dow, this._week.doy).week;
810         },
812         _week : {
813             dow : 0, // Sunday is the first day of the week.
814             doy : 6  // The week that contains Jan 1st is the first week of the year.
815         },
817         _invalidDate: 'Invalid date',
818         invalidDate: function () {
819             return this._invalidDate;
820         }
821     });
823     // Loads a language definition into the `languages` cache.  The function
824     // takes a key and optionally values.  If not in the browser and no values
825     // are provided, it will load the language file module.  As a convenience,
826     // this function also returns the language values.
827     function loadLang(key, values) {
828         values.abbr = key;
829         if (!languages[key]) {
830             languages[key] = new Language();
831         }
832         languages[key].set(values);
833         return languages[key];
834     }
836     // Remove a language from the `languages` cache. Mostly useful in tests.
837     function unloadLang(key) {
838         delete languages[key];
839     }
841     // Determines which language definition to use and returns it.
842     //
843     // With no parameters, it will return the global language.  If you
844     // pass in a language key, such as 'en', it will return the
845     // definition for 'en', so long as 'en' has already been loaded using
846     // moment.lang.
847     function getLangDefinition(key) {
848         var i = 0, j, lang, next, split,
849             get = function (k) {
850                 if (!languages[k] && hasModule) {
851                     try {
852                         require('./lang/' + k);
853                     } catch (e) { }
854                 }
855                 return languages[k];
856             };
858         if (!key) {
859             return moment.fn._lang;
860         }
862         if (!isArray(key)) {
863             //short-circuit everything else
864             lang = get(key);
865             if (lang) {
866                 return lang;
867             }
868             key = [key];
869         }
871         //pick the language from the array
872         //try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each
873         //substring from most specific to least, but move to the next array item if it's a more specific variant than the current root
874         while (i < key.length) {
875             split = normalizeLanguage(key[i]).split('-');
876             j = split.length;
877             next = normalizeLanguage(key[i + 1]);
878             next = next ? next.split('-') : null;
879             while (j > 0) {
880                 lang = get(split.slice(0, j).join('-'));
881                 if (lang) {
882                     return lang;
883                 }
884                 if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) {
885                     //the next array item is better than a shallower substring of this one
886                     break;
887                 }
888                 j--;
889             }
890             i++;
891         }
892         return moment.fn._lang;
893     }
895     /************************************
896         Formatting
897     ************************************/
900     function removeFormattingTokens(input) {
901         if (input.match(/\[[\s\S]/)) {
902             return input.replace(/^\[|\]$/g, "");
903         }
904         return input.replace(/\\/g, "");
905     }
907     function makeFormatFunction(format) {
908         var array = format.match(formattingTokens), i, length;
910         for (i = 0, length = array.length; i < length; i++) {
911             if (formatTokenFunctions[array[i]]) {
912                 array[i] = formatTokenFunctions[array[i]];
913             } else {
914                 array[i] = removeFormattingTokens(array[i]);
915             }
916         }
918         return function (mom) {
919             var output = "";
920             for (i = 0; i < length; i++) {
921                 output += array[i] instanceof Function ? array[i].call(mom, format) : array[i];
922             }
923             return output;
924         };
925     }
927     // format date using native date object
928     function formatMoment(m, format) {
930         if (!m.isValid()) {
931             return m.lang().invalidDate();
932         }
934         format = expandFormat(format, m.lang());
936         if (!formatFunctions[format]) {
937             formatFunctions[format] = makeFormatFunction(format);
938         }
940         return formatFunctions[format](m);
941     }
943     function expandFormat(format, lang) {
944         var i = 5;
946         function replaceLongDateFormatTokens(input) {
947             return lang.longDateFormat(input) || input;
948         }
950         localFormattingTokens.lastIndex = 0;
951         while (i >= 0 && localFormattingTokens.test(format)) {
952             format = format.replace(localFormattingTokens, replaceLongDateFormatTokens);
953             localFormattingTokens.lastIndex = 0;
954             i -= 1;
955         }
957         return format;
958     }
961     /************************************
962         Parsing
963     ************************************/
966     // get the regex to find the next token
967     function getParseRegexForToken(token, config) {
968         var a, strict = config._strict;
969         switch (token) {
970         case 'Q':
971             return parseTokenOneDigit;
972         case 'DDDD':
973             return parseTokenThreeDigits;
974         case 'YYYY':
975         case 'GGGG':
976         case 'gggg':
977             return strict ? parseTokenFourDigits : parseTokenOneToFourDigits;
978         case 'Y':
979         case 'G':
980         case 'g':
981             return parseTokenSignedNumber;
982         case 'YYYYYY':
983         case 'YYYYY':
984         case 'GGGGG':
985         case 'ggggg':
986             return strict ? parseTokenSixDigits : parseTokenOneToSixDigits;
987         case 'S':
988             if (strict) { return parseTokenOneDigit; }
989             /* falls through */
990         case 'SS':
991             if (strict) { return parseTokenTwoDigits; }
992             /* falls through */
993         case 'SSS':
994             if (strict) { return parseTokenThreeDigits; }
995             /* falls through */
996         case 'DDD':
997             return parseTokenOneToThreeDigits;
998         case 'MMM':
999         case 'MMMM':
1000         case 'dd':
1001         case 'ddd':
1002         case 'dddd':
1003             return parseTokenWord;
1004         case 'a':
1005         case 'A':
1006             return getLangDefinition(config._l)._meridiemParse;
1007         case 'X':
1008             return parseTokenTimestampMs;
1009         case 'Z':
1010         case 'ZZ':
1011             return parseTokenTimezone;
1012         case 'T':
1013             return parseTokenT;
1014         case 'SSSS':
1015             return parseTokenDigits;
1016         case 'MM':
1017         case 'DD':
1018         case 'YY':
1019         case 'GG':
1020         case 'gg':
1021         case 'HH':
1022         case 'hh':
1023         case 'mm':
1024         case 'ss':
1025         case 'ww':
1026         case 'WW':
1027             return strict ? parseTokenTwoDigits : parseTokenOneOrTwoDigits;
1028         case 'M':
1029         case 'D':
1030         case 'd':
1031         case 'H':
1032         case 'h':
1033         case 'm':
1034         case 's':
1035         case 'w':
1036         case 'W':
1037         case 'e':
1038         case 'E':
1039             return parseTokenOneOrTwoDigits;
1040         case 'Do':
1041             return parseTokenOrdinal;
1042         default :
1043             a = new RegExp(regexpEscape(unescapeFormat(token.replace('\\', '')), "i"));
1044             return a;
1045         }
1046     }
1048     function timezoneMinutesFromString(string) {
1049         string = string || "";
1050         var possibleTzMatches = (string.match(parseTokenTimezone) || []),
1051             tzChunk = possibleTzMatches[possibleTzMatches.length - 1] || [],
1052             parts = (tzChunk + '').match(parseTimezoneChunker) || ['-', 0, 0],
1053             minutes = +(parts[1] * 60) + toInt(parts[2]);
1055         return parts[0] === '+' ? -minutes : minutes;
1056     }
1058     // function to convert string input to date
1059     function addTimeToArrayFromToken(token, input, config) {
1060         var a, datePartArray = config._a;
1062         switch (token) {
1063         // QUARTER
1064         case 'Q':
1065             if (input != null) {
1066                 datePartArray[MONTH] = (toInt(input) - 1) * 3;
1067             }
1068             break;
1069         // MONTH
1070         case 'M' : // fall through to MM
1071         case 'MM' :
1072             if (input != null) {
1073                 datePartArray[MONTH] = toInt(input) - 1;
1074             }
1075             break;
1076         case 'MMM' : // fall through to MMMM
1077         case 'MMMM' :
1078             a = getLangDefinition(config._l).monthsParse(input);
1079             // if we didn't find a month name, mark the date as invalid.
1080             if (a != null) {
1081                 datePartArray[MONTH] = a;
1082             } else {
1083                 config._pf.invalidMonth = input;
1084             }
1085             break;
1086         // DAY OF MONTH
1087         case 'D' : // fall through to DD
1088         case 'DD' :
1089             if (input != null) {
1090                 datePartArray[DATE] = toInt(input);
1091             }
1092             break;
1093         case 'Do' :
1094             if (input != null) {
1095                 datePartArray[DATE] = toInt(parseInt(input, 10));
1096             }
1097             break;
1098         // DAY OF YEAR
1099         case 'DDD' : // fall through to DDDD
1100         case 'DDDD' :
1101             if (input != null) {
1102                 config._dayOfYear = toInt(input);
1103             }
1105             break;
1106         // YEAR
1107         case 'YY' :
1108             datePartArray[YEAR] = moment.parseTwoDigitYear(input);
1109             break;
1110         case 'YYYY' :
1111         case 'YYYYY' :
1112         case 'YYYYYY' :
1113             datePartArray[YEAR] = toInt(input);
1114             break;
1115         // AM / PM
1116         case 'a' : // fall through to A
1117         case 'A' :
1118             config._isPm = getLangDefinition(config._l).isPM(input);
1119             break;
1120         // 24 HOUR
1121         case 'H' : // fall through to hh
1122         case 'HH' : // fall through to hh
1123         case 'h' : // fall through to hh
1124         case 'hh' :
1125             datePartArray[HOUR] = toInt(input);
1126             break;
1127         // MINUTE
1128         case 'm' : // fall through to mm
1129         case 'mm' :
1130             datePartArray[MINUTE] = toInt(input);
1131             break;
1132         // SECOND
1133         case 's' : // fall through to ss
1134         case 'ss' :
1135             datePartArray[SECOND] = toInt(input);
1136             break;
1137         // MILLISECOND
1138         case 'S' :
1139         case 'SS' :
1140         case 'SSS' :
1141         case 'SSSS' :
1142             datePartArray[MILLISECOND] = toInt(('0.' + input) * 1000);
1143             break;
1144         // UNIX TIMESTAMP WITH MS
1145         case 'X':
1146             config._d = new Date(parseFloat(input) * 1000);
1147             break;
1148         // TIMEZONE
1149         case 'Z' : // fall through to ZZ
1150         case 'ZZ' :
1151             config._useUTC = true;
1152             config._tzm = timezoneMinutesFromString(input);
1153             break;
1154         case 'w':
1155         case 'ww':
1156         case 'W':
1157         case 'WW':
1158         case 'd':
1159         case 'dd':
1160         case 'ddd':
1161         case 'dddd':
1162         case 'e':
1163         case 'E':
1164             token = token.substr(0, 1);
1165             /* falls through */
1166         case 'gg':
1167         case 'gggg':
1168         case 'GG':
1169         case 'GGGG':
1170         case 'GGGGG':
1171             token = token.substr(0, 2);
1172             if (input) {
1173                 config._w = config._w || {};
1174                 config._w[token] = input;
1175             }
1176             break;
1177         }
1178     }
1180     // convert an array to a date.
1181     // the array should mirror the parameters below
1182     // note: all values past the year are optional and will default to the lowest possible value.
1183     // [year, month, day , hour, minute, second, millisecond]
1184     function dateFromConfig(config) {
1185         var i, date, input = [], currentDate,
1186             yearToUse, fixYear, w, temp, lang, weekday, week;
1188         if (config._d) {
1189             return;
1190         }
1192         currentDate = currentDateArray(config);
1194         //compute day of the year from weeks and weekdays
1195         if (config._w && config._a[DATE] == null && config._a[MONTH] == null) {
1196             fixYear = function (val) {
1197                 var intVal = parseInt(val, 10);
1198                 return val ?
1199                   (val.length < 3 ? (intVal > 68 ? 1900 + intVal : 2000 + intVal) : intVal) :
1200                   (config._a[YEAR] == null ? moment().weekYear() : config._a[YEAR]);
1201             };
1203             w = config._w;
1204             if (w.GG != null || w.W != null || w.E != null) {
1205                 temp = dayOfYearFromWeeks(fixYear(w.GG), w.W || 1, w.E, 4, 1);
1206             }
1207             else {
1208                 lang = getLangDefinition(config._l);
1209                 weekday = w.d != null ?  parseWeekday(w.d, lang) :
1210                   (w.e != null ?  parseInt(w.e, 10) + lang._week.dow : 0);
1212                 week = parseInt(w.w, 10) || 1;
1214                 //if we're parsing 'd', then the low day numbers may be next week
1215                 if (w.d != null && weekday < lang._week.dow) {
1216                     week++;
1217                 }
1219                 temp = dayOfYearFromWeeks(fixYear(w.gg), week, weekday, lang._week.doy, lang._week.dow);
1220             }
1222             config._a[YEAR] = temp.year;
1223             config._dayOfYear = temp.dayOfYear;
1224         }
1226         //if the day of the year is set, figure out what it is
1227         if (config._dayOfYear) {
1228             yearToUse = config._a[YEAR] == null ? currentDate[YEAR] : config._a[YEAR];
1230             if (config._dayOfYear > daysInYear(yearToUse)) {
1231                 config._pf._overflowDayOfYear = true;
1232             }
1234             date = makeUTCDate(yearToUse, 0, config._dayOfYear);
1235             config._a[MONTH] = date.getUTCMonth();
1236             config._a[DATE] = date.getUTCDate();
1237         }
1239         // Default to current date.
1240         // * if no year, month, day of month are given, default to today
1241         // * if day of month is given, default month and year
1242         // * if month is given, default only year
1243         // * if year is given, don't default anything
1244         for (i = 0; i < 3 && config._a[i] == null; ++i) {
1245             config._a[i] = input[i] = currentDate[i];
1246         }
1248         // Zero out whatever was not defaulted, including time
1249         for (; i < 7; i++) {
1250             config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i];
1251         }
1253         // add the offsets to the time to be parsed so that we can have a clean array for checking isValid
1254         input[HOUR] += toInt((config._tzm || 0) / 60);
1255         input[MINUTE] += toInt((config._tzm || 0) % 60);
1257         config._d = (config._useUTC ? makeUTCDate : makeDate).apply(null, input);
1258     }
1260     function dateFromObject(config) {
1261         var normalizedInput;
1263         if (config._d) {
1264             return;
1265         }
1267         normalizedInput = normalizeObjectUnits(config._i);
1268         config._a = [
1269             normalizedInput.year,
1270             normalizedInput.month,
1271             normalizedInput.day,
1272             normalizedInput.hour,
1273             normalizedInput.minute,
1274             normalizedInput.second,
1275             normalizedInput.millisecond
1276         ];
1278         dateFromConfig(config);
1279     }
1281     function currentDateArray(config) {
1282         var now = new Date();
1283         if (config._useUTC) {
1284             return [
1285                 now.getUTCFullYear(),
1286                 now.getUTCMonth(),
1287                 now.getUTCDate()
1288             ];
1289         } else {
1290             return [now.getFullYear(), now.getMonth(), now.getDate()];
1291         }
1292     }
1294     // date from string and format string
1295     function makeDateFromStringAndFormat(config) {
1297         config._a = [];
1298         config._pf.empty = true;
1300         // This array is used to make a Date, either with `new Date` or `Date.UTC`
1301         var lang = getLangDefinition(config._l),
1302             string = '' + config._i,
1303             i, parsedInput, tokens, token, skipped,
1304             stringLength = string.length,
1305             totalParsedInputLength = 0;
1307         tokens = expandFormat(config._f, lang).match(formattingTokens) || [];
1309         for (i = 0; i < tokens.length; i++) {
1310             token = tokens[i];
1311             parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0];
1312             if (parsedInput) {
1313                 skipped = string.substr(0, string.indexOf(parsedInput));
1314                 if (skipped.length > 0) {
1315                     config._pf.unusedInput.push(skipped);
1316                 }
1317                 string = string.slice(string.indexOf(parsedInput) + parsedInput.length);
1318                 totalParsedInputLength += parsedInput.length;
1319             }
1320             // don't parse if it's not a known token
1321             if (formatTokenFunctions[token]) {
1322                 if (parsedInput) {
1323                     config._pf.empty = false;
1324                 }
1325                 else {
1326                     config._pf.unusedTokens.push(token);
1327                 }
1328                 addTimeToArrayFromToken(token, parsedInput, config);
1329             }
1330             else if (config._strict && !parsedInput) {
1331                 config._pf.unusedTokens.push(token);
1332             }
1333         }
1335         // add remaining unparsed input length to the string
1336         config._pf.charsLeftOver = stringLength - totalParsedInputLength;
1337         if (string.length > 0) {
1338             config._pf.unusedInput.push(string);
1339         }
1341         // handle am pm
1342         if (config._isPm && config._a[HOUR] < 12) {
1343             config._a[HOUR] += 12;
1344         }
1345         // if is 12 am, change hours to 0
1346         if (config._isPm === false && config._a[HOUR] === 12) {
1347             config._a[HOUR] = 0;
1348         }
1350         dateFromConfig(config);
1351         checkOverflow(config);
1352     }
1354     function unescapeFormat(s) {
1355         return s.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) {
1356             return p1 || p2 || p3 || p4;
1357         });
1358     }
1360     // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
1361     function regexpEscape(s) {
1362         return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
1363     }
1365     // date from string and array of format strings
1366     function makeDateFromStringAndArray(config) {
1367         var tempConfig,
1368             bestMoment,
1370             scoreToBeat,
1371             i,
1372             currentScore;
1374         if (config._f.length === 0) {
1375             config._pf.invalidFormat = true;
1376             config._d = new Date(NaN);
1377             return;
1378         }
1380         for (i = 0; i < config._f.length; i++) {
1381             currentScore = 0;
1382             tempConfig = extend({}, config);
1383             tempConfig._pf = defaultParsingFlags();
1384             tempConfig._f = config._f[i];
1385             makeDateFromStringAndFormat(tempConfig);
1387             if (!isValid(tempConfig)) {
1388                 continue;
1389             }
1391             // if there is any input that was not parsed add a penalty for that format
1392             currentScore += tempConfig._pf.charsLeftOver;
1394             //or tokens
1395             currentScore += tempConfig._pf.unusedTokens.length * 10;
1397             tempConfig._pf.score = currentScore;
1399             if (scoreToBeat == null || currentScore < scoreToBeat) {
1400                 scoreToBeat = currentScore;
1401                 bestMoment = tempConfig;
1402             }
1403         }
1405         extend(config, bestMoment || tempConfig);
1406     }
1408     // date from iso format
1409     function makeDateFromString(config) {
1410         var i, l,
1411             string = config._i,
1412             match = isoRegex.exec(string);
1414         if (match) {
1415             config._pf.iso = true;
1416             for (i = 0, l = isoDates.length; i < l; i++) {
1417                 if (isoDates[i][1].exec(string)) {
1418                     // match[5] should be "T" or undefined
1419                     config._f = isoDates[i][0] + (match[6] || " ");
1420                     break;
1421                 }
1422             }
1423             for (i = 0, l = isoTimes.length; i < l; i++) {
1424                 if (isoTimes[i][1].exec(string)) {
1425                     config._f += isoTimes[i][0];
1426                     break;
1427                 }
1428             }
1429             if (string.match(parseTokenTimezone)) {
1430                 config._f += "Z";
1431             }
1432             makeDateFromStringAndFormat(config);
1433         }
1434         else {
1435             moment.createFromInputFallback(config);
1436         }
1437     }
1439     function makeDateFromInput(config) {
1440         var input = config._i,
1441             matched = aspNetJsonRegex.exec(input);
1443         if (input === undefined) {
1444             config._d = new Date();
1445         } else if (matched) {
1446             config._d = new Date(+matched[1]);
1447         } else if (typeof input === 'string') {
1448             makeDateFromString(config);
1449         } else if (isArray(input)) {
1450             config._a = input.slice(0);
1451             dateFromConfig(config);
1452         } else if (isDate(input)) {
1453             config._d = new Date(+input);
1454         } else if (typeof(input) === 'object') {
1455             dateFromObject(config);
1456         } else if (typeof(input) === 'number') {
1457             // from milliseconds
1458             config._d = new Date(input);
1459         } else {
1460             moment.createFromInputFallback(config);
1461         }
1462     }
1464     function makeDate(y, m, d, h, M, s, ms) {
1465         //can't just apply() to create a date:
1466         //http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply
1467         var date = new Date(y, m, d, h, M, s, ms);
1469         //the date constructor doesn't accept years < 1970
1470         if (y < 1970) {
1471             date.setFullYear(y);
1472         }
1473         return date;
1474     }
1476     function makeUTCDate(y) {
1477         var date = new Date(Date.UTC.apply(null, arguments));
1478         if (y < 1970) {
1479             date.setUTCFullYear(y);
1480         }
1481         return date;
1482     }
1484     function parseWeekday(input, language) {
1485         if (typeof input === 'string') {
1486             if (!isNaN(input)) {
1487                 input = parseInt(input, 10);
1488             }
1489             else {
1490                 input = language.weekdaysParse(input);
1491                 if (typeof input !== 'number') {
1492                     return null;
1493                 }
1494             }
1495         }
1496         return input;
1497     }
1499     /************************************
1500         Relative Time
1501     ************************************/
1504     // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize
1505     function substituteTimeAgo(string, number, withoutSuffix, isFuture, lang) {
1506         return lang.relativeTime(number || 1, !!withoutSuffix, string, isFuture);
1507     }
1509     function relativeTime(milliseconds, withoutSuffix, lang) {
1510         var seconds = round(Math.abs(milliseconds) / 1000),
1511             minutes = round(seconds / 60),
1512             hours = round(minutes / 60),
1513             days = round(hours / 24),
1514             years = round(days / 365),
1515             args = seconds < 45 && ['s', seconds] ||
1516                 minutes === 1 && ['m'] ||
1517                 minutes < 45 && ['mm', minutes] ||
1518                 hours === 1 && ['h'] ||
1519                 hours < 22 && ['hh', hours] ||
1520                 days === 1 && ['d'] ||
1521                 days <= 25 && ['dd', days] ||
1522                 days <= 45 && ['M'] ||
1523                 days < 345 && ['MM', round(days / 30)] ||
1524                 years === 1 && ['y'] || ['yy', years];
1525         args[2] = withoutSuffix;
1526         args[3] = milliseconds > 0;
1527         args[4] = lang;
1528         return substituteTimeAgo.apply({}, args);
1529     }
1532     /************************************
1533         Week of Year
1534     ************************************/
1537     // firstDayOfWeek       0 = sun, 6 = sat
1538     //                      the day of the week that starts the week
1539     //                      (usually sunday or monday)
1540     // firstDayOfWeekOfYear 0 = sun, 6 = sat
1541     //                      the first week is the week that contains the first
1542     //                      of this day of the week
1543     //                      (eg. ISO weeks use thursday (4))
1544     function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) {
1545         var end = firstDayOfWeekOfYear - firstDayOfWeek,
1546             daysToDayOfWeek = firstDayOfWeekOfYear - mom.day(),
1547             adjustedMoment;
1550         if (daysToDayOfWeek > end) {
1551             daysToDayOfWeek -= 7;
1552         }
1554         if (daysToDayOfWeek < end - 7) {
1555             daysToDayOfWeek += 7;
1556         }
1558         adjustedMoment = moment(mom).add('d', daysToDayOfWeek);
1559         return {
1560             week: Math.ceil(adjustedMoment.dayOfYear() / 7),
1561             year: adjustedMoment.year()
1562         };
1563     }
1565     //http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday
1566     function dayOfYearFromWeeks(year, week, weekday, firstDayOfWeekOfYear, firstDayOfWeek) {
1567         var d = makeUTCDate(year, 0, 1).getUTCDay(), daysToAdd, dayOfYear;
1569         weekday = weekday != null ? weekday : firstDayOfWeek;
1570         daysToAdd = firstDayOfWeek - d + (d > firstDayOfWeekOfYear ? 7 : 0) - (d < firstDayOfWeek ? 7 : 0);
1571         dayOfYear = 7 * (week - 1) + (weekday - firstDayOfWeek) + daysToAdd + 1;
1573         return {
1574             year: dayOfYear > 0 ? year : year - 1,
1575             dayOfYear: dayOfYear > 0 ?  dayOfYear : daysInYear(year - 1) + dayOfYear
1576         };
1577     }
1579     /************************************
1580         Top Level Functions
1581     ************************************/
1583     function makeMoment(config) {
1584         var input = config._i,
1585             format = config._f;
1587         if (input === null || (format === undefined && input === '')) {
1588             return moment.invalid({nullInput: true});
1589         }
1591         if (typeof input === 'string') {
1592             config._i = input = getLangDefinition().preparse(input);
1593         }
1595         if (moment.isMoment(input)) {
1596             config = cloneMoment(input);
1598             config._d = new Date(+input._d);
1599         } else if (format) {
1600             if (isArray(format)) {
1601                 makeDateFromStringAndArray(config);
1602             } else {
1603                 makeDateFromStringAndFormat(config);
1604             }
1605         } else {
1606             makeDateFromInput(config);
1607         }
1609         return new Moment(config);
1610     }
1612     moment = function (input, format, lang, strict) {
1613         var c;
1615         if (typeof(lang) === "boolean") {
1616             strict = lang;
1617             lang = undefined;
1618         }
1619         // object construction must be done this way.
1620         // https://github.com/moment/moment/issues/1423
1621         c = {};
1622         c._isAMomentObject = true;
1623         c._i = input;
1624         c._f = format;
1625         c._l = lang;
1626         c._strict = strict;
1627         c._isUTC = false;
1628         c._pf = defaultParsingFlags();
1630         return makeMoment(c);
1631     };
1633     moment.suppressDeprecationWarnings = false;
1635     moment.createFromInputFallback = deprecate(
1636             "moment construction falls back to js Date. This is " +
1637             "discouraged and will be removed in upcoming major " +
1638             "release. Please refer to " +
1639             "https://github.com/moment/moment/issues/1407 for more info.",
1640             function (config) {
1641         config._d = new Date(config._i);
1642     });
1644     // creating with utc
1645     moment.utc = function (input, format, lang, strict) {
1646         var c;
1648         if (typeof(lang) === "boolean") {
1649             strict = lang;
1650             lang = undefined;
1651         }
1652         // object construction must be done this way.
1653         // https://github.com/moment/moment/issues/1423
1654         c = {};
1655         c._isAMomentObject = true;
1656         c._useUTC = true;
1657         c._isUTC = true;
1658         c._l = lang;
1659         c._i = input;
1660         c._f = format;
1661         c._strict = strict;
1662         c._pf = defaultParsingFlags();
1664         return makeMoment(c).utc();
1665     };
1667     // creating with unix timestamp (in seconds)
1668     moment.unix = function (input) {
1669         return moment(input * 1000);
1670     };
1672     // duration
1673     moment.duration = function (input, key) {
1674         var duration = input,
1675             // matching against regexp is expensive, do it on demand
1676             match = null,
1677             sign,
1678             ret,
1679             parseIso;
1681         if (moment.isDuration(input)) {
1682             duration = {
1683                 ms: input._milliseconds,
1684                 d: input._days,
1685                 M: input._months
1686             };
1687         } else if (typeof input === 'number') {
1688             duration = {};
1689             if (key) {
1690                 duration[key] = input;
1691             } else {
1692                 duration.milliseconds = input;
1693             }
1694         } else if (!!(match = aspNetTimeSpanJsonRegex.exec(input))) {
1695             sign = (match[1] === "-") ? -1 : 1;
1696             duration = {
1697                 y: 0,
1698                 d: toInt(match[DATE]) * sign,
1699                 h: toInt(match[HOUR]) * sign,
1700                 m: toInt(match[MINUTE]) * sign,
1701                 s: toInt(match[SECOND]) * sign,
1702                 ms: toInt(match[MILLISECOND]) * sign
1703             };
1704         } else if (!!(match = isoDurationRegex.exec(input))) {
1705             sign = (match[1] === "-") ? -1 : 1;
1706             parseIso = function (inp) {
1707                 // We'd normally use ~~inp for this, but unfortunately it also
1708                 // converts floats to ints.
1709                 // inp may be undefined, so careful calling replace on it.
1710                 var res = inp && parseFloat(inp.replace(',', '.'));
1711                 // apply sign while we're at it
1712                 return (isNaN(res) ? 0 : res) * sign;
1713             };
1714             duration = {
1715                 y: parseIso(match[2]),
1716                 M: parseIso(match[3]),
1717                 d: parseIso(match[4]),
1718                 h: parseIso(match[5]),
1719                 m: parseIso(match[6]),
1720                 s: parseIso(match[7]),
1721                 w: parseIso(match[8])
1722             };
1723         }
1725         ret = new Duration(duration);
1727         if (moment.isDuration(input) && input.hasOwnProperty('_lang')) {
1728             ret._lang = input._lang;
1729         }
1731         return ret;
1732     };
1734     // version number
1735     moment.version = VERSION;
1737     // default format
1738     moment.defaultFormat = isoFormat;
1740     // Plugins that add properties should also add the key here (null value),
1741     // so we can properly clone ourselves.
1742     moment.momentProperties = momentProperties;
1744     // This function will be called whenever a moment is mutated.
1745     // It is intended to keep the offset in sync with the timezone.
1746     moment.updateOffset = function () {};
1748     // This function will load languages and then set the global language.  If
1749     // no arguments are passed in, it will simply return the current global
1750     // language key.
1751     moment.lang = function (key, values) {
1752         var r;
1753         if (!key) {
1754             return moment.fn._lang._abbr;
1755         }
1756         if (values) {
1757             loadLang(normalizeLanguage(key), values);
1758         } else if (values === null) {
1759             unloadLang(key);
1760             key = 'en';
1761         } else if (!languages[key]) {
1762             getLangDefinition(key);
1763         }
1764         r = moment.duration.fn._lang = moment.fn._lang = getLangDefinition(key);
1765         return r._abbr;
1766     };
1768     // returns language data
1769     moment.langData = function (key) {
1770         if (key && key._lang && key._lang._abbr) {
1771             key = key._lang._abbr;
1772         }
1773         return getLangDefinition(key);
1774     };
1776     // compare moment object
1777     moment.isMoment = function (obj) {
1778         return obj instanceof Moment ||
1779             (obj != null &&  obj.hasOwnProperty('_isAMomentObject'));
1780     };
1782     // for typechecking Duration objects
1783     moment.isDuration = function (obj) {
1784         return obj instanceof Duration;
1785     };
1787     for (i = lists.length - 1; i >= 0; --i) {
1788         makeList(lists[i]);
1789     }
1791     moment.normalizeUnits = function (units) {
1792         return normalizeUnits(units);
1793     };
1795     moment.invalid = function (flags) {
1796         var m = moment.utc(NaN);
1797         if (flags != null) {
1798             extend(m._pf, flags);
1799         }
1800         else {
1801             m._pf.userInvalidated = true;
1802         }
1804         return m;
1805     };
1807     moment.parseZone = function () {
1808         return moment.apply(null, arguments).parseZone();
1809     };
1811     moment.parseTwoDigitYear = function (input) {
1812         return toInt(input) + (toInt(input) > 68 ? 1900 : 2000);
1813     };
1815     /************************************
1816         Moment Prototype
1817     ************************************/
1820     extend(moment.fn = Moment.prototype, {
1822         clone : function () {
1823             return moment(this);
1824         },
1826         valueOf : function () {
1827             return +this._d + ((this._offset || 0) * 60000);
1828         },
1830         unix : function () {
1831             return Math.floor(+this / 1000);
1832         },
1834         toString : function () {
1835             return this.clone().lang('en').format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ");
1836         },
1838         toDate : function () {
1839             return this._offset ? new Date(+this) : this._d;
1840         },
1842         toISOString : function () {
1843             var m = moment(this).utc();
1844             if (0 < m.year() && m.year() <= 9999) {
1845                 return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
1846             } else {
1847                 return formatMoment(m, 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
1848             }
1849         },
1851         toArray : function () {
1852             var m = this;
1853             return [
1854                 m.year(),
1855                 m.month(),
1856                 m.date(),
1857                 m.hours(),
1858                 m.minutes(),
1859                 m.seconds(),
1860                 m.milliseconds()
1861             ];
1862         },
1864         isValid : function () {
1865             return isValid(this);
1866         },
1868         isDSTShifted : function () {
1870             if (this._a) {
1871                 return this.isValid() && compareArrays(this._a, (this._isUTC ? moment.utc(this._a) : moment(this._a)).toArray()) > 0;
1872             }
1874             return false;
1875         },
1877         parsingFlags : function () {
1878             return extend({}, this._pf);
1879         },
1881         invalidAt: function () {
1882             return this._pf.overflow;
1883         },
1885         utc : function () {
1886             return this.zone(0);
1887         },
1889         local : function () {
1890             this.zone(0);
1891             this._isUTC = false;
1892             return this;
1893         },
1895         format : function (inputString) {
1896             var output = formatMoment(this, inputString || moment.defaultFormat);
1897             return this.lang().postformat(output);
1898         },
1900         add : function (input, val) {
1901             var dur;
1902             // switch args to support add('s', 1) and add(1, 's')
1903             if (typeof input === 'string') {
1904                 dur = moment.duration(+val, input);
1905             } else {
1906                 dur = moment.duration(input, val);
1907             }
1908             addOrSubtractDurationFromMoment(this, dur, 1);
1909             return this;
1910         },
1912         subtract : function (input, val) {
1913             var dur;
1914             // switch args to support subtract('s', 1) and subtract(1, 's')
1915             if (typeof input === 'string') {
1916                 dur = moment.duration(+val, input);
1917             } else {
1918                 dur = moment.duration(input, val);
1919             }
1920             addOrSubtractDurationFromMoment(this, dur, -1);
1921             return this;
1922         },
1924         diff : function (input, units, asFloat) {
1925             var that = makeAs(input, this),
1926                 zoneDiff = (this.zone() - that.zone()) * 6e4,
1927                 diff, output;
1929             units = normalizeUnits(units);
1931             if (units === 'year' || units === 'month') {
1932                 // average number of days in the months in the given dates
1933                 diff = (this.daysInMonth() + that.daysInMonth()) * 432e5; // 24 * 60 * 60 * 1000 / 2
1934                 // difference in months
1935                 output = ((this.year() - that.year()) * 12) + (this.month() - that.month());
1936                 // adjust by taking difference in days, average number of days
1937                 // and dst in the given months.
1938                 output += ((this - moment(this).startOf('month')) -
1939                         (that - moment(that).startOf('month'))) / diff;
1940                 // same as above but with zones, to negate all dst
1941                 output -= ((this.zone() - moment(this).startOf('month').zone()) -
1942                         (that.zone() - moment(that).startOf('month').zone())) * 6e4 / diff;
1943                 if (units === 'year') {
1944                     output = output / 12;
1945                 }
1946             } else {
1947                 diff = (this - that);
1948                 output = units === 'second' ? diff / 1e3 : // 1000
1949                     units === 'minute' ? diff / 6e4 : // 1000 * 60
1950                     units === 'hour' ? diff / 36e5 : // 1000 * 60 * 60
1951                     units === 'day' ? (diff - zoneDiff) / 864e5 : // 1000 * 60 * 60 * 24, negate dst
1952                     units === 'week' ? (diff - zoneDiff) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst
1953                     diff;
1954             }
1955             return asFloat ? output : absRound(output);
1956         },
1958         from : function (time, withoutSuffix) {
1959             return moment.duration(this.diff(time)).lang(this.lang()._abbr).humanize(!withoutSuffix);
1960         },
1962         fromNow : function (withoutSuffix) {
1963             return this.from(moment(), withoutSuffix);
1964         },
1966         calendar : function () {
1967             // We want to compare the start of today, vs this.
1968             // Getting start-of-today depends on whether we're zone'd or not.
1969             var sod = makeAs(moment(), this).startOf('day'),
1970                 diff = this.diff(sod, 'days', true),
1971                 format = diff < -6 ? 'sameElse' :
1972                     diff < -1 ? 'lastWeek' :
1973                     diff < 0 ? 'lastDay' :
1974                     diff < 1 ? 'sameDay' :
1975                     diff < 2 ? 'nextDay' :
1976                     diff < 7 ? 'nextWeek' : 'sameElse';
1977             return this.format(this.lang().calendar(format, this));
1978         },
1980         isLeapYear : function () {
1981             return isLeapYear(this.year());
1982         },
1984         isDST : function () {
1985             return (this.zone() < this.clone().month(0).zone() ||
1986                 this.zone() < this.clone().month(5).zone());
1987         },
1989         day : function (input) {
1990             var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay();
1991             if (input != null) {
1992                 input = parseWeekday(input, this.lang());
1993                 return this.add({ d : input - day });
1994             } else {
1995                 return day;
1996             }
1997         },
1999         month : makeAccessor('Month', true),
2001         startOf: function (units) {
2002             units = normalizeUnits(units);
2003             // the following switch intentionally omits break keywords
2004             // to utilize falling through the cases.
2005             switch (units) {
2006             case 'year':
2007                 this.month(0);
2008                 /* falls through */
2009             case 'quarter':
2010             case 'month':
2011                 this.date(1);
2012                 /* falls through */
2013             case 'week':
2014             case 'isoWeek':
2015             case 'day':
2016                 this.hours(0);
2017                 /* falls through */
2018             case 'hour':
2019                 this.minutes(0);
2020                 /* falls through */
2021             case 'minute':
2022                 this.seconds(0);
2023                 /* falls through */
2024             case 'second':
2025                 this.milliseconds(0);
2026                 /* falls through */
2027             }
2029             // weeks are a special case
2030             if (units === 'week') {
2031                 this.weekday(0);
2032             } else if (units === 'isoWeek') {
2033                 this.isoWeekday(1);
2034             }
2036             // quarters are also special
2037             if (units === 'quarter') {
2038                 this.month(Math.floor(this.month() / 3) * 3);
2039             }
2041             return this;
2042         },
2044         endOf: function (units) {
2045             units = normalizeUnits(units);
2046             return this.startOf(units).add((units === 'isoWeek' ? 'week' : units), 1).subtract('ms', 1);
2047         },
2049         isAfter: function (input, units) {
2050             units = typeof units !== 'undefined' ? units : 'millisecond';
2051             return +this.clone().startOf(units) > +moment(input).startOf(units);
2052         },
2054         isBefore: function (input, units) {
2055             units = typeof units !== 'undefined' ? units : 'millisecond';
2056             return +this.clone().startOf(units) < +moment(input).startOf(units);
2057         },
2059         isSame: function (input, units) {
2060             units = units || 'ms';
2061             return +this.clone().startOf(units) === +makeAs(input, this).startOf(units);
2062         },
2064         min: function (other) {
2065             other = moment.apply(null, arguments);
2066             return other < this ? this : other;
2067         },
2069         max: function (other) {
2070             other = moment.apply(null, arguments);
2071             return other > this ? this : other;
2072         },
2074         // keepTime = true means only change the timezone, without affecting
2075         // the local hour. So 5:31:26 +0300 --[zone(2, true)]--> 5:31:26 +0200
2076         // It is possible that 5:31:26 doesn't exist int zone +0200, so we
2077         // adjust the time as needed, to be valid.
2078         //
2079         // Keeping the time actually adds/subtracts (one hour)
2080         // from the actual represented time. That is why we call updateOffset
2081         // a second time. In case it wants us to change the offset again
2082         // _changeInProgress == true case, then we have to adjust, because
2083         // there is no such time in the given timezone.
2084         zone : function (input, keepTime) {
2085             var offset = this._offset || 0;
2086             if (input != null) {
2087                 if (typeof input === "string") {
2088                     input = timezoneMinutesFromString(input);
2089                 }
2090                 if (Math.abs(input) < 16) {
2091                     input = input * 60;
2092                 }
2093                 this._offset = input;
2094                 this._isUTC = true;
2095                 if (offset !== input) {
2096                     if (!keepTime || this._changeInProgress) {
2097                         addOrSubtractDurationFromMoment(this,
2098                                 moment.duration(offset - input, 'm'), 1, false);
2099                     } else if (!this._changeInProgress) {
2100                         this._changeInProgress = true;
2101                         moment.updateOffset(this, true);
2102                         this._changeInProgress = null;
2103                     }
2104                 }
2105             } else {
2106                 return this._isUTC ? offset : this._d.getTimezoneOffset();
2107             }
2108             return this;
2109         },
2111         zoneAbbr : function () {
2112             return this._isUTC ? "UTC" : "";
2113         },
2115         zoneName : function () {
2116             return this._isUTC ? "Coordinated Universal Time" : "";
2117         },
2119         parseZone : function () {
2120             if (this._tzm) {
2121                 this.zone(this._tzm);
2122             } else if (typeof this._i === 'string') {
2123                 this.zone(this._i);
2124             }
2125             return this;
2126         },
2128         hasAlignedHourOffset : function (input) {
2129             if (!input) {
2130                 input = 0;
2131             }
2132             else {
2133                 input = moment(input).zone();
2134             }
2136             return (this.zone() - input) % 60 === 0;
2137         },
2139         daysInMonth : function () {
2140             return daysInMonth(this.year(), this.month());
2141         },
2143         dayOfYear : function (input) {
2144             var dayOfYear = round((moment(this).startOf('day') - moment(this).startOf('year')) / 864e5) + 1;
2145             return input == null ? dayOfYear : this.add("d", (input - dayOfYear));
2146         },
2148         quarter : function (input) {
2149             return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3);
2150         },
2152         weekYear : function (input) {
2153             var year = weekOfYear(this, this.lang()._week.dow, this.lang()._week.doy).year;
2154             return input == null ? year : this.add("y", (input - year));
2155         },
2157         isoWeekYear : function (input) {
2158             var year = weekOfYear(this, 1, 4).year;
2159             return input == null ? year : this.add("y", (input - year));
2160         },
2162         week : function (input) {
2163             var week = this.lang().week(this);
2164             return input == null ? week : this.add("d", (input - week) * 7);
2165         },
2167         isoWeek : function (input) {
2168             var week = weekOfYear(this, 1, 4).week;
2169             return input == null ? week : this.add("d", (input - week) * 7);
2170         },
2172         weekday : function (input) {
2173             var weekday = (this.day() + 7 - this.lang()._week.dow) % 7;
2174             return input == null ? weekday : this.add("d", input - weekday);
2175         },
2177         isoWeekday : function (input) {
2178             // behaves the same as moment#day except
2179             // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6)
2180             // as a setter, sunday should belong to the previous week.
2181             return input == null ? this.day() || 7 : this.day(this.day() % 7 ? input : input - 7);
2182         },
2184         isoWeeksInYear : function () {
2185             return weeksInYear(this.year(), 1, 4);
2186         },
2188         weeksInYear : function () {
2189             var weekInfo = this._lang._week;
2190             return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy);
2191         },
2193         get : function (units) {
2194             units = normalizeUnits(units);
2195             return this[units]();
2196         },
2198         set : function (units, value) {
2199             units = normalizeUnits(units);
2200             if (typeof this[units] === 'function') {
2201                 this[units](value);
2202             }
2203             return this;
2204         },
2206         // If passed a language key, it will set the language for this
2207         // instance.  Otherwise, it will return the language configuration
2208         // variables for this instance.
2209         lang : function (key) {
2210             if (key === undefined) {
2211                 return this._lang;
2212             } else {
2213                 this._lang = getLangDefinition(key);
2214                 return this;
2215             }
2216         }
2217     });
2219     function rawMonthSetter(mom, value) {
2220         var dayOfMonth;
2222         // TODO: Move this out of here!
2223         if (typeof value === 'string') {
2224             value = mom.lang().monthsParse(value);
2225             // TODO: Another silent failure?
2226             if (typeof value !== 'number') {
2227                 return mom;
2228             }
2229         }
2231         dayOfMonth = Math.min(mom.date(),
2232                 daysInMonth(mom.year(), value));
2233         mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth);
2234         return mom;
2235     }
2237     function rawGetter(mom, unit) {
2238         return mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]();
2239     }
2241     function rawSetter(mom, unit, value) {
2242         if (unit === 'Month') {
2243             return rawMonthSetter(mom, value);
2244         } else {
2245             return mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value);
2246         }
2247     }
2249     function makeAccessor(unit, keepTime) {
2250         return function (value) {
2251             if (value != null) {
2252                 rawSetter(this, unit, value);
2253                 moment.updateOffset(this, keepTime);
2254                 return this;
2255             } else {
2256                 return rawGetter(this, unit);
2257             }
2258         };
2259     }
2261     moment.fn.millisecond = moment.fn.milliseconds = makeAccessor('Milliseconds', false);
2262     moment.fn.second = moment.fn.seconds = makeAccessor('Seconds', false);
2263     moment.fn.minute = moment.fn.minutes = makeAccessor('Minutes', false);
2264     // Setting the hour should keep the time, because the user explicitly
2265     // specified which hour he wants. So trying to maintain the same hour (in
2266     // a new timezone) makes sense. Adding/subtracting hours does not follow
2267     // this rule.
2268     moment.fn.hour = moment.fn.hours = makeAccessor('Hours', true);
2269     // moment.fn.month is defined separately
2270     moment.fn.date = makeAccessor('Date', true);
2271     moment.fn.dates = deprecate("dates accessor is deprecated. Use date instead.", makeAccessor('Date', true));
2272     moment.fn.year = makeAccessor('FullYear', true);
2273     moment.fn.years = deprecate("years accessor is deprecated. Use year instead.", makeAccessor('FullYear', true));
2275     // add plural methods
2276     moment.fn.days = moment.fn.day;
2277     moment.fn.months = moment.fn.month;
2278     moment.fn.weeks = moment.fn.week;
2279     moment.fn.isoWeeks = moment.fn.isoWeek;
2280     moment.fn.quarters = moment.fn.quarter;
2282     // add aliased format methods
2283     moment.fn.toJSON = moment.fn.toISOString;
2285     /************************************
2286         Duration Prototype
2287     ************************************/
2290     extend(moment.duration.fn = Duration.prototype, {
2292         _bubble : function () {
2293             var milliseconds = this._milliseconds,
2294                 days = this._days,
2295                 months = this._months,
2296                 data = this._data,
2297                 seconds, minutes, hours, years;
2299             // The following code bubbles up values, see the tests for
2300             // examples of what that means.
2301             data.milliseconds = milliseconds % 1000;
2303             seconds = absRound(milliseconds / 1000);
2304             data.seconds = seconds % 60;
2306             minutes = absRound(seconds / 60);
2307             data.minutes = minutes % 60;
2309             hours = absRound(minutes / 60);
2310             data.hours = hours % 24;
2312             days += absRound(hours / 24);
2313             data.days = days % 30;
2315             months += absRound(days / 30);
2316             data.months = months % 12;
2318             years = absRound(months / 12);
2319             data.years = years;
2320         },
2322         weeks : function () {
2323             return absRound(this.days() / 7);
2324         },
2326         valueOf : function () {
2327             return this._milliseconds +
2328               this._days * 864e5 +
2329               (this._months % 12) * 2592e6 +
2330               toInt(this._months / 12) * 31536e6;
2331         },
2333         humanize : function (withSuffix) {
2334             var difference = +this,
2335                 output = relativeTime(difference, !withSuffix, this.lang());
2337             if (withSuffix) {
2338                 output = this.lang().pastFuture(difference, output);
2339             }
2341             return this.lang().postformat(output);
2342         },
2344         add : function (input, val) {
2345             // supports only 2.0-style add(1, 's') or add(moment)
2346             var dur = moment.duration(input, val);
2348             this._milliseconds += dur._milliseconds;
2349             this._days += dur._days;
2350             this._months += dur._months;
2352             this._bubble();
2354             return this;
2355         },
2357         subtract : function (input, val) {
2358             var dur = moment.duration(input, val);
2360             this._milliseconds -= dur._milliseconds;
2361             this._days -= dur._days;
2362             this._months -= dur._months;
2364             this._bubble();
2366             return this;
2367         },
2369         get : function (units) {
2370             units = normalizeUnits(units);
2371             return this[units.toLowerCase() + 's']();
2372         },
2374         as : function (units) {
2375             units = normalizeUnits(units);
2376             return this['as' + units.charAt(0).toUpperCase() + units.slice(1) + 's']();
2377         },
2379         lang : moment.fn.lang,
2381         toIsoString : function () {
2382             // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js
2383             var years = Math.abs(this.years()),
2384                 months = Math.abs(this.months()),
2385                 days = Math.abs(this.days()),
2386                 hours = Math.abs(this.hours()),
2387                 minutes = Math.abs(this.minutes()),
2388                 seconds = Math.abs(this.seconds() + this.milliseconds() / 1000);
2390             if (!this.asSeconds()) {
2391                 // this is the same as C#'s (Noda) and python (isodate)...
2392                 // but not other JS (goog.date)
2393                 return 'P0D';
2394             }
2396             return (this.asSeconds() < 0 ? '-' : '') +
2397                 'P' +
2398                 (years ? years + 'Y' : '') +
2399                 (months ? months + 'M' : '') +
2400                 (days ? days + 'D' : '') +
2401                 ((hours || minutes || seconds) ? 'T' : '') +
2402                 (hours ? hours + 'H' : '') +
2403                 (minutes ? minutes + 'M' : '') +
2404                 (seconds ? seconds + 'S' : '');
2405         }
2406     });
2408     function makeDurationGetter(name) {
2409         moment.duration.fn[name] = function () {
2410             return this._data[name];
2411         };
2412     }
2414     function makeDurationAsGetter(name, factor) {
2415         moment.duration.fn['as' + name] = function () {
2416             return +this / factor;
2417         };
2418     }
2420     for (i in unitMillisecondFactors) {
2421         if (unitMillisecondFactors.hasOwnProperty(i)) {
2422             makeDurationAsGetter(i, unitMillisecondFactors[i]);
2423             makeDurationGetter(i.toLowerCase());
2424         }
2425     }
2427     makeDurationAsGetter('Weeks', 6048e5);
2428     moment.duration.fn.asMonths = function () {
2429         return (+this - this.years() * 31536e6) / 2592e6 + this.years() * 12;
2430     };
2433     /************************************
2434         Default Lang
2435     ************************************/
2438     // Set default language, other languages will inherit from English.
2439     moment.lang('en', {
2440         ordinal : function (number) {
2441             var b = number % 10,
2442                 output = (toInt(number % 100 / 10) === 1) ? 'th' :
2443                 (b === 1) ? 'st' :
2444                 (b === 2) ? 'nd' :
2445                 (b === 3) ? 'rd' : 'th';
2446             return number + output;
2447         }
2448     });
2450     /* EMBED_LANGUAGES */
2452     /************************************
2453         Exposing Moment
2454     ************************************/
2456     function makeGlobal(shouldDeprecate) {
2457         /*global ender:false */
2458         if (typeof ender !== 'undefined') {
2459             return;
2460         }
2461         oldGlobalMoment = globalScope.moment;
2462         if (shouldDeprecate) {
2463             globalScope.moment = deprecate(
2464                     "Accessing Moment through the global scope is " +
2465                     "deprecated, and will be removed in an upcoming " +
2466                     "release.",
2467                     moment);
2468         } else {
2469             globalScope.moment = moment;
2470         }
2471     }
2473     // CommonJS module is defined
2474     if (hasModule) {
2475         module.exports = moment;
2476     } else if (typeof define === "function" && define.amd) {
2477         define("moment", function (require, exports, module) {
2478             if (module.config && module.config() && module.config().noGlobal === true) {
2479                 // release the global variable
2480                 globalScope.moment = oldGlobalMoment;
2481             }
2483             return moment;
2484         });
2485         makeGlobal(true);
2486     } else {
2487         makeGlobal();
2488     }
2489 }).call(this);