diff --git a/Gruntfile.js b/Gruntfile.js index 0a8813037b18084670b2d200f6a74f28d8e96e44..e6f235e72cdbbae7528d07e2244709ee78697f3a 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -27,6 +27,9 @@ module.exports = function (grunt) { errorsOnly: true } }, + jiodate: { + src: ['src/jio.date/jiodate.js'] + }, tests: { src: ['test/**/*.js'], options: { @@ -82,6 +85,10 @@ module.exports = function (grunt) { src: 'jio.js', // '<%= pkg.name %>.js' dest: 'jio.min.js' }, + jiodate: { + src: 'src/jio.date/jiodate.js', + dest: 'jiodate.min.js' + }, queries: { src: 'complex_queries.js', dest: 'complex_queries.min.js' diff --git a/lib/moment/moment-2.5.0.js b/lib/moment/moment-2.5.0.js new file mode 100644 index 0000000000000000000000000000000000000000..682fdbd9e33a20dd6d36f30fd68a6efe2234e9dc --- /dev/null +++ b/lib/moment/moment-2.5.0.js @@ -0,0 +1,2363 @@ +//! moment.js +//! version : 2.5.0 +//! authors : Tim Wood, Iskren Chernev, Moment.js contributors +//! license : MIT +//! momentjs.com + +(function (undefined) { + + /************************************ + Constants + ************************************/ + + var moment, + VERSION = "2.5.0", + global = this, + round = Math.round, + i, + + YEAR = 0, + MONTH = 1, + DATE = 2, + HOUR = 3, + MINUTE = 4, + SECOND = 5, + MILLISECOND = 6, + + // internal storage for language config files + languages = {}, + + // check for nodeJS + hasModule = (typeof module !== 'undefined' && module.exports && typeof require !== 'undefined'), + + // ASP.NET json date format regex + aspNetJsonRegex = /^\/?Date\((\-?\d+)/i, + aspNetTimeSpanJsonRegex = /(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/, + + // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html + // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere + isoDurationRegex = /^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/, + + // format tokens + formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|X|zz?|ZZ?|.)/g, + localFormattingTokens = /(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g, + + // parsing token regexes + parseTokenOneOrTwoDigits = /\d\d?/, // 0 - 99 + parseTokenOneToThreeDigits = /\d{1,3}/, // 0 - 999 + parseTokenOneToFourDigits = /\d{1,4}/, // 0 - 9999 + parseTokenOneToSixDigits = /[+\-]?\d{1,6}/, // -999,999 - 999,999 + parseTokenDigits = /\d+/, // nonzero number of digits + 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. + parseTokenTimezone = /Z|[\+\-]\d\d:?\d\d/gi, // +00:00 -00:00 +0000 -0000 or Z + parseTokenT = /T/i, // T (ISO separator) + parseTokenTimestampMs = /[\+\-]?\d+(\.\d{1,3})?/, // 123456789 123456789.123 + + //strict parsing regexes + parseTokenOneDigit = /\d/, // 0 - 9 + parseTokenTwoDigits = /\d\d/, // 00 - 99 + parseTokenThreeDigits = /\d{3}/, // 000 - 999 + parseTokenFourDigits = /\d{4}/, // 0000 - 9999 + parseTokenSixDigits = /[+\-]?\d{6}/, // -999,999 - 999,999 + + // iso 8601 regex + // 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) + isoRegex = /^\s*\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)?)?$/, + + isoFormat = 'YYYY-MM-DDTHH:mm:ssZ', + + isoDates = [ + 'YYYY-MM-DD', + 'GGGG-[W]WW', + 'GGGG-[W]WW-E', + 'YYYY-DDD' + ], + + // iso time formats and regexes + isoTimes = [ + ['HH:mm:ss.SSSS', /(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 = 'Date|Hours|Minutes|Seconds|Milliseconds'.split('|'), + unitMillisecondFactors = { + 'Milliseconds' : 1, + 'Seconds' : 1e3, + 'Minutes' : 6e4, + 'Hours' : 36e5, + 'Days' : 864e5, + 'Months' : 2592e6, + 'Years' : 31536e6 + }, + + unitAliases = { + ms : 'millisecond', + s : 'second', + m : 'minute', + h : 'hour', + d : 'day', + D : 'date', + w : 'week', + W : 'isoWeek', + M : 'month', + y : 'year', + DDD : 'dayOfYear', + e : 'weekday', + E : 'isoWeekday', + gg: 'weekYear', + GG: 'isoWeekYear' + }, + + camelFunctions = { + dayofyear : 'dayOfYear', + isoweekday : 'isoWeekday', + isoweek : 'isoWeek', + weekyear : 'weekYear', + isoweekyear : 'isoWeekYear' + }, + + // 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); + }, + YYYYYY : function () { + var y = this.year(), sign = y >= 0 ? '+' : '-'; + return sign + leftZeroFill(Math.abs(y), 6); + }, + gg : function () { + return leftZeroFill(this.weekYear() % 100, 2); + }, + gggg : function () { + return this.weekYear(); + }, + ggggg : function () { + return leftZeroFill(this.weekYear(), 5); + }, + GG : function () { + return leftZeroFill(this.isoWeekYear() % 100, 2); + }, + GGGG : function () { + return this.isoWeekYear(); + }, + GGGGG : function () { + return leftZeroFill(this.isoWeekYear(), 5); + }, + e : function () { + return this.weekday(); + }, + E : function () { + return this.isoWeekday(); + }, + 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 toInt(this.milliseconds() / 100); + }, + SS : function () { + return leftZeroFill(toInt(this.milliseconds() / 10), 2); + }, + SSS : function () { + return leftZeroFill(this.milliseconds(), 3); + }, + SSSS : function () { + return leftZeroFill(this.milliseconds(), 3); + }, + Z : function () { + var a = -this.zone(), + b = "+"; + if (a < 0) { + a = -a; + b = "-"; + } + return b + leftZeroFill(toInt(a / 60), 2) + ":" + leftZeroFill(toInt(a) % 60, 2); + }, + ZZ : function () { + var a = -this.zone(), + b = "+"; + if (a < 0) { + a = -a; + b = "-"; + } + return b + leftZeroFill(toInt(a / 60), 2) + leftZeroFill(toInt(a) % 60, 2); + }, + z : function () { + return this.zoneAbbr(); + }, + zz : function () { + return this.zoneName(); + }, + X : function () { + return this.unix(); + }, + Q : function () { + return this.quarter(); + } + }, + + lists = ['months', 'monthsShort', 'weekdays', 'weekdaysShort', 'weekdaysMin']; + + function padToken(func, count) { + return function (a) { + return leftZeroFill(func.call(this, a), count); + }; + } + function ordinalizeToken(func, period) { + return function (a) { + return this.lang().ordinal(func.call(this, a), period); + }; + } + + while (ordinalizeTokens.length) { + i = ordinalizeTokens.pop(); + formatTokenFunctions[i + 'o'] = ordinalizeToken(formatTokenFunctions[i], 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) { + checkOverflow(config); + extend(this, config); + } + + // Duration Constructor + function Duration(duration) { + var normalizedInput = normalizeObjectUnits(duration), + years = normalizedInput.year || 0, + months = normalizedInput.month || 0, + weeks = normalizedInput.week || 0, + days = normalizedInput.day || 0, + hours = normalizedInput.hour || 0, + minutes = normalizedInput.minute || 0, + seconds = normalizedInput.second || 0, + milliseconds = normalizedInput.millisecond || 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; + + this._data = {}; + + this._bubble(); + } + + /************************************ + Helpers + ************************************/ + + + function extend(a, b) { + for (var i in b) { + if (b.hasOwnProperty(i)) { + a[i] = b[i]; + } + } + + if (b.hasOwnProperty("toString")) { + a.toString = b.toString; + } + + if (b.hasOwnProperty("valueOf")) { + a.valueOf = b.valueOf; + } + + 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, forceSign) { + var output = Math.abs(number) + '', + sign = number >= 0; + + while (output.length < targetLength) { + output = '0' + output; + } + return (sign ? (forceSign ? '+' : '') : '-') + output; + } + + // helper function for _.addTime and _.subtractTime + function addOrSubtractDurationFromMoment(mom, duration, isAdding, ignoreUpdateOffset) { + var milliseconds = duration._milliseconds, + days = duration._days, + months = duration._months, + minutes, + hours; + + if (milliseconds) { + mom._d.setTime(+mom._d + milliseconds * isAdding); + } + // store the minutes and hours so we can restore them + if (days || months) { + minutes = mom.minute(); + hours = mom.hour(); + } + if (days) { + mom.date(mom.date() + days * isAdding); + } + if (months) { + mom.month(mom.month() + months * isAdding); + } + if (milliseconds && !ignoreUpdateOffset) { + moment.updateOffset(mom); + } + // restore the minutes and hours after possibly changing dst + if (days || months) { + mom.minute(minutes); + mom.hour(hours); + } + } + + // check if is an array + function isArray(input) { + return Object.prototype.toString.call(input) === '[object Array]'; + } + + function isDate(input) { + return Object.prototype.toString.call(input) === '[object Date]' || + input instanceof Date; + } + + // compare two arrays, return the number of differences + function compareArrays(array1, array2, dontConvert) { + 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 ((dontConvert && array1[i] !== array2[i]) || + (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) { + diffs++; + } + } + return diffs + lengthDiff; + } + + function normalizeUnits(units) { + if (units) { + var lowered = units.toLowerCase().replace(/(.)s$/, '$1'); + units = unitAliases[units] || camelFunctions[lowered] || lowered; + } + return units; + } + + function normalizeObjectUnits(inputObject) { + var normalizedInput = {}, + normalizedProp, + prop; + + for (prop in inputObject) { + if (inputObject.hasOwnProperty(prop)) { + normalizedProp = normalizeUnits(prop); + if (normalizedProp) { + normalizedInput[normalizedProp] = inputObject[prop]; + } + } + } + + return normalizedInput; + } + + function makeList(field) { + var count, setter; + + if (field.indexOf('week') === 0) { + count = 7; + setter = 'day'; + } + else if (field.indexOf('month') === 0) { + count = 12; + setter = 'month'; + } + else { + return; + } + + moment[field] = function (format, index) { + var i, getter, + method = moment.fn._lang[field], + results = []; + + if (typeof format === 'number') { + index = format; + format = undefined; + } + + getter = function (i) { + var m = moment().utc().set(setter, i); + return method.call(moment.fn._lang, m, format || ''); + }; + + if (index != null) { + return getter(index); + } + else { + for (i = 0; i < count; i++) { + results.push(getter(i)); + } + return results; + } + }; + } + + function toInt(argumentForCoercion) { + var coercedNumber = +argumentForCoercion, + value = 0; + + if (coercedNumber !== 0 && isFinite(coercedNumber)) { + if (coercedNumber >= 0) { + value = Math.floor(coercedNumber); + } else { + value = Math.ceil(coercedNumber); + } + } + + return value; + } + + function daysInMonth(year, month) { + return new Date(Date.UTC(year, month + 1, 0)).getUTCDate(); + } + + function daysInYear(year) { + return isLeapYear(year) ? 366 : 365; + } + + function isLeapYear(year) { + return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; + } + + function checkOverflow(m) { + var overflow; + if (m._a && m._pf.overflow === -2) { + overflow = + m._a[MONTH] < 0 || m._a[MONTH] > 11 ? MONTH : + m._a[DATE] < 1 || m._a[DATE] > daysInMonth(m._a[YEAR], m._a[MONTH]) ? DATE : + m._a[HOUR] < 0 || m._a[HOUR] > 23 ? HOUR : + m._a[MINUTE] < 0 || m._a[MINUTE] > 59 ? MINUTE : + m._a[SECOND] < 0 || m._a[SECOND] > 59 ? SECOND : + m._a[MILLISECOND] < 0 || m._a[MILLISECOND] > 999 ? MILLISECOND : + -1; + + if (m._pf._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) { + overflow = DATE; + } + + m._pf.overflow = overflow; + } + } + + function initializeParsingFlags(config) { + config._pf = { + empty : false, + unusedTokens : [], + unusedInput : [], + overflow : -2, + charsLeftOver : 0, + nullInput : false, + invalidMonth : null, + invalidFormat : false, + userInvalidated : false, + iso: false + }; + } + + function isValid(m) { + if (m._isValid == null) { + m._isValid = !isNaN(m._d.getTime()) && + m._pf.overflow < 0 && + !m._pf.empty && + !m._pf.invalidMonth && + !m._pf.nullInput && + !m._pf.invalidFormat && + !m._pf.userInvalidated; + + if (m._strict) { + m._isValid = m._isValid && + m._pf.charsLeftOver === 0 && + m._pf.unusedTokens.length === 0; + } + } + return m._isValid; + } + + function normalizeLanguage(key) { + return key ? key.toLowerCase().replace('_', '-') : key; + } + + // Return a moment from input, that is local/utc/zone equivalent to model. + function makeAs(input, model) { + return model._isUTC ? moment(input).zone(model._offset || 0) : + moment(input).local(); + } + + /************************************ + Languages + ************************************/ + + + extend(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; + + 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.utc([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()]; + }, + + weekdaysParse : function (weekdayName) { + var i, mom, regex; + + if (!this._weekdaysParse) { + this._weekdaysParse = []; + } + + for (i = 0; i < 7; i++) { + // make the regex if we don't have it already + if (!this._weekdaysParse[i]) { + mom = moment([2000, 1]).day(i); + regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, ''); + this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i'); + } + // test the regex + if (this._weekdaysParse[i].test(weekdayName)) { + return i; + } + } + }, + + _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; + }, + + isPM : function (input) { + // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays + // Using charAt should be more compatible. + return ((input + '').toLowerCase().charAt(0) === 'p'); + }, + + _meridiemParse : /[ap]\.?m?\.?/i, + 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; + }, + + _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. + }, + + _invalidDate: 'Invalid date', + invalidDate: function () { + return this._invalidDate; + } + }); + + // 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]; + } + + // Remove a language from the `languages` cache. Mostly useful in tests. + function unloadLang(key) { + delete 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) { + var i = 0, j, lang, next, split, + get = function (k) { + if (!languages[k] && hasModule) { + try { + require('./lang/' + k); + } catch (e) { } + } + return languages[k]; + }; + + if (!key) { + return moment.fn._lang; + } + + if (!isArray(key)) { + //short-circuit everything else + lang = get(key); + if (lang) { + return lang; + } + key = [key]; + } + + //pick the language from the array + //try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each + //substring from most specific to least, but move to the next array item if it's a more specific variant than the current root + while (i < key.length) { + split = normalizeLanguage(key[i]).split('-'); + j = split.length; + next = normalizeLanguage(key[i + 1]); + next = next ? next.split('-') : null; + while (j > 0) { + lang = get(split.slice(0, j).join('-')); + if (lang) { + return lang; + } + if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) { + //the next array item is better than a shallower substring of this one + break; + } + j--; + } + i++; + } + return moment.fn._lang; + } + + /************************************ + Formatting + ************************************/ + + + function removeFormattingTokens(input) { + if (input.match(/\[[\s\S]/)) { + 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 += array[i] instanceof Function ? array[i].call(mom, format) : array[i]; + } + return output; + }; + } + + // format date using native date object + function formatMoment(m, format) { + + if (!m.isValid()) { + return m.lang().invalidDate(); + } + + format = expandFormat(format, m.lang()); + + if (!formatFunctions[format]) { + formatFunctions[format] = makeFormatFunction(format); + } + + return formatFunctions[format](m); + } + + function expandFormat(format, lang) { + var i = 5; + + function replaceLongDateFormatTokens(input) { + return lang.longDateFormat(input) || input; + } + + localFormattingTokens.lastIndex = 0; + while (i >= 0 && localFormattingTokens.test(format)) { + format = format.replace(localFormattingTokens, replaceLongDateFormatTokens); + localFormattingTokens.lastIndex = 0; + i -= 1; + } + + return format; + } + + + /************************************ + Parsing + ************************************/ + + + // get the regex to find the next token + function getParseRegexForToken(token, config) { + var a, strict = config._strict; + switch (token) { + case 'DDDD': + return parseTokenThreeDigits; + case 'YYYY': + case 'GGGG': + case 'gggg': + return strict ? parseTokenFourDigits : parseTokenOneToFourDigits; + case 'YYYYYY': + case 'YYYYY': + case 'GGGGG': + case 'ggggg': + return strict ? parseTokenSixDigits : parseTokenOneToSixDigits; + case 'S': + if (strict) { return parseTokenOneDigit; } + /* falls through */ + case 'SS': + if (strict) { return parseTokenTwoDigits; } + /* falls through */ + case 'SSS': + case 'DDD': + return strict ? parseTokenThreeDigits : parseTokenOneToThreeDigits; + case 'MMM': + case 'MMMM': + case 'dd': + case 'ddd': + case 'dddd': + return parseTokenWord; + case 'a': + case 'A': + return getLangDefinition(config._l)._meridiemParse; + case 'X': + return parseTokenTimestampMs; + case 'Z': + case 'ZZ': + return parseTokenTimezone; + case 'T': + return parseTokenT; + case 'SSSS': + return parseTokenDigits; + case 'MM': + case 'DD': + case 'YY': + case 'GG': + case 'gg': + case 'HH': + case 'hh': + case 'mm': + case 'ss': + case 'ww': + case 'WW': + return strict ? parseTokenTwoDigits : parseTokenOneOrTwoDigits; + case 'M': + case 'D': + case 'd': + case 'H': + case 'h': + case 'm': + case 's': + case 'w': + case 'W': + case 'e': + case 'E': + return strict ? parseTokenOneDigit : parseTokenOneOrTwoDigits; + default : + a = new RegExp(regexpEscape(unescapeFormat(token.replace('\\', '')), "i")); + return a; + } + } + + function timezoneMinutesFromString(string) { + string = string || ""; + var possibleTzMatches = (string.match(parseTokenTimezone) || []), + tzChunk = possibleTzMatches[possibleTzMatches.length - 1] || [], + parts = (tzChunk + '').match(parseTimezoneChunker) || ['-', 0, 0], + minutes = +(parts[1] * 60) + toInt(parts[2]); + + return parts[0] === '+' ? -minutes : minutes; + } + + // function to convert string input to date + function addTimeToArrayFromToken(token, input, config) { + var a, datePartArray = config._a; + + switch (token) { + // MONTH + case 'M' : // fall through to MM + case 'MM' : + if (input != null) { + datePartArray[MONTH] = toInt(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[MONTH] = a; + } else { + config._pf.invalidMonth = input; + } + break; + // DAY OF MONTH + case 'D' : // fall through to DD + case 'DD' : + if (input != null) { + datePartArray[DATE] = toInt(input); + } + break; + // DAY OF YEAR + case 'DDD' : // fall through to DDDD + case 'DDDD' : + if (input != null) { + config._dayOfYear = toInt(input); + } + + break; + // YEAR + case 'YY' : + datePartArray[YEAR] = toInt(input) + (toInt(input) > 68 ? 1900 : 2000); + break; + case 'YYYY' : + case 'YYYYY' : + case 'YYYYYY' : + datePartArray[YEAR] = toInt(input); + break; + // AM / PM + case 'a' : // fall through to A + case 'A' : + config._isPm = getLangDefinition(config._l).isPM(input); + break; + // 24 HOUR + case 'H' : // fall through to hh + case 'HH' : // fall through to hh + case 'h' : // fall through to hh + case 'hh' : + datePartArray[HOUR] = toInt(input); + break; + // MINUTE + case 'm' : // fall through to mm + case 'mm' : + datePartArray[MINUTE] = toInt(input); + break; + // SECOND + case 's' : // fall through to ss + case 'ss' : + datePartArray[SECOND] = toInt(input); + break; + // MILLISECOND + case 'S' : + case 'SS' : + case 'SSS' : + case 'SSSS' : + datePartArray[MILLISECOND] = toInt(('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; + config._tzm = timezoneMinutesFromString(input); + break; + case 'w': + case 'ww': + case 'W': + case 'WW': + case 'd': + case 'dd': + case 'ddd': + case 'dddd': + case 'e': + case 'E': + token = token.substr(0, 1); + /* falls through */ + case 'gg': + case 'gggg': + case 'GG': + case 'GGGG': + case 'GGGGG': + token = token.substr(0, 2); + if (input) { + config._w = config._w || {}; + config._w[token] = input; + } + break; + } + } + + // 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 dateFromConfig(config) { + var i, date, input = [], currentDate, + yearToUse, fixYear, w, temp, lang, weekday, week; + + if (config._d) { + return; + } + + currentDate = currentDateArray(config); + + //compute day of the year from weeks and weekdays + if (config._w && config._a[DATE] == null && config._a[MONTH] == null) { + fixYear = function (val) { + var int_val = parseInt(val, 10); + return val ? + (val.length < 3 ? (int_val > 68 ? 1900 + int_val : 2000 + int_val) : int_val) : + (config._a[YEAR] == null ? moment().weekYear() : config._a[YEAR]); + }; + + w = config._w; + if (w.GG != null || w.W != null || w.E != null) { + temp = dayOfYearFromWeeks(fixYear(w.GG), w.W || 1, w.E, 4, 1); + } + else { + lang = getLangDefinition(config._l); + weekday = w.d != null ? parseWeekday(w.d, lang) : + (w.e != null ? parseInt(w.e, 10) + lang._week.dow : 0); + + week = parseInt(w.w, 10) || 1; + + //if we're parsing 'd', then the low day numbers may be next week + if (w.d != null && weekday < lang._week.dow) { + week++; + } + + temp = dayOfYearFromWeeks(fixYear(w.gg), week, weekday, lang._week.doy, lang._week.dow); + } + + config._a[YEAR] = temp.year; + config._dayOfYear = temp.dayOfYear; + } + + //if the day of the year is set, figure out what it is + if (config._dayOfYear) { + yearToUse = config._a[YEAR] == null ? currentDate[YEAR] : config._a[YEAR]; + + if (config._dayOfYear > daysInYear(yearToUse)) { + config._pf._overflowDayOfYear = true; + } + + date = makeUTCDate(yearToUse, 0, config._dayOfYear); + config._a[MONTH] = date.getUTCMonth(); + config._a[DATE] = date.getUTCDate(); + } + + // Default to current date. + // * if no year, month, day of month are given, default to today + // * if day of month is given, default month and year + // * if month is given, default only year + // * if year is given, don't default anything + for (i = 0; i < 3 && config._a[i] == null; ++i) { + config._a[i] = input[i] = currentDate[i]; + } + + // Zero out whatever was not defaulted, including time + for (; 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[HOUR] += toInt((config._tzm || 0) / 60); + input[MINUTE] += toInt((config._tzm || 0) % 60); + + config._d = (config._useUTC ? makeUTCDate : makeDate).apply(null, input); + } + + function dateFromObject(config) { + var normalizedInput; + + if (config._d) { + return; + } + + normalizedInput = normalizeObjectUnits(config._i); + config._a = [ + normalizedInput.year, + normalizedInput.month, + normalizedInput.day, + normalizedInput.hour, + normalizedInput.minute, + normalizedInput.second, + normalizedInput.millisecond + ]; + + dateFromConfig(config); + } + + function currentDateArray(config) { + var now = new Date(); + if (config._useUTC) { + return [ + now.getUTCFullYear(), + now.getUTCMonth(), + now.getUTCDate() + ]; + } else { + return [now.getFullYear(), now.getMonth(), now.getDate()]; + } + } + + // date from string and format string + function makeDateFromStringAndFormat(config) { + + config._a = []; + config._pf.empty = true; + + // This array is used to make a Date, either with `new Date` or `Date.UTC` + var lang = getLangDefinition(config._l), + string = '' + config._i, + i, parsedInput, tokens, token, skipped, + stringLength = string.length, + totalParsedInputLength = 0; + + tokens = expandFormat(config._f, lang).match(formattingTokens) || []; + + for (i = 0; i < tokens.length; i++) { + token = tokens[i]; + parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0]; + if (parsedInput) { + skipped = string.substr(0, string.indexOf(parsedInput)); + if (skipped.length > 0) { + config._pf.unusedInput.push(skipped); + } + string = string.slice(string.indexOf(parsedInput) + parsedInput.length); + totalParsedInputLength += parsedInput.length; + } + // don't parse if it's not a known token + if (formatTokenFunctions[token]) { + if (parsedInput) { + config._pf.empty = false; + } + else { + config._pf.unusedTokens.push(token); + } + addTimeToArrayFromToken(token, parsedInput, config); + } + else if (config._strict && !parsedInput) { + config._pf.unusedTokens.push(token); + } + } + + // add remaining unparsed input length to the string + config._pf.charsLeftOver = stringLength - totalParsedInputLength; + if (string.length > 0) { + config._pf.unusedInput.push(string); + } + + // handle am pm + if (config._isPm && config._a[HOUR] < 12) { + config._a[HOUR] += 12; + } + // if is 12 am, change hours to 0 + if (config._isPm === false && config._a[HOUR] === 12) { + config._a[HOUR] = 0; + } + + dateFromConfig(config); + checkOverflow(config); + } + + function unescapeFormat(s) { + return s.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) { + return p1 || p2 || p3 || p4; + }); + } + + // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript + function regexpEscape(s) { + return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); + } + + // date from string and array of format strings + function makeDateFromStringAndArray(config) { + var tempConfig, + bestMoment, + + scoreToBeat, + i, + currentScore; + + if (config._f.length === 0) { + config._pf.invalidFormat = true; + config._d = new Date(NaN); + return; + } + + for (i = 0; i < config._f.length; i++) { + currentScore = 0; + tempConfig = extend({}, config); + initializeParsingFlags(tempConfig); + tempConfig._f = config._f[i]; + makeDateFromStringAndFormat(tempConfig); + + if (!isValid(tempConfig)) { + continue; + } + + // if there is any input that was not parsed add a penalty for that format + currentScore += tempConfig._pf.charsLeftOver; + + //or tokens + currentScore += tempConfig._pf.unusedTokens.length * 10; + + tempConfig._pf.score = currentScore; + + if (scoreToBeat == null || currentScore < scoreToBeat) { + scoreToBeat = currentScore; + bestMoment = tempConfig; + } + } + + extend(config, bestMoment || tempConfig); + } + + // date from iso format + function makeDateFromString(config) { + var i, + string = config._i, + match = isoRegex.exec(string); + + if (match) { + config._pf.iso = true; + for (i = 4; i > 0; i--) { + if (match[i]) { + // match[5] should be "T" or undefined + config._f = isoDates[i - 1] + (match[6] || " "); + break; + } + } + for (i = 0; i < 4; i++) { + if (isoTimes[i][1].exec(string)) { + config._f += isoTimes[i][0]; + break; + } + } + if (string.match(parseTokenTimezone)) { + 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); + dateFromConfig(config); + } else if (isDate(input)) { + config._d = new Date(+input); + } else if (typeof(input) === 'object') { + dateFromObject(config); + } else { + config._d = new Date(input); + } + } + + function makeDate(y, m, d, h, M, s, ms) { + //can't just apply() to create a date: + //http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply + var date = new Date(y, m, d, h, M, s, ms); + + //the date constructor doesn't accept years < 1970 + if (y < 1970) { + date.setFullYear(y); + } + return date; + } + + function makeUTCDate(y) { + var date = new Date(Date.UTC.apply(null, arguments)); + if (y < 1970) { + date.setUTCFullYear(y); + } + return date; + } + + function parseWeekday(input, language) { + if (typeof input === 'string') { + if (!isNaN(input)) { + input = parseInt(input, 10); + } + else { + input = language.weekdaysParse(input); + if (typeof input !== 'number') { + return null; + } + } + } + return 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(), + adjustedMoment; + + + if (daysToDayOfWeek > end) { + daysToDayOfWeek -= 7; + } + + if (daysToDayOfWeek < end - 7) { + daysToDayOfWeek += 7; + } + + adjustedMoment = moment(mom).add('d', daysToDayOfWeek); + return { + week: Math.ceil(adjustedMoment.dayOfYear() / 7), + year: adjustedMoment.year() + }; + } + + //http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday + function dayOfYearFromWeeks(year, week, weekday, firstDayOfWeekOfYear, firstDayOfWeek) { + // The only solid way to create an iso date from year is to use + // a string format (Date.UTC handles only years > 1900). Don't ask why + // it doesn't need Z at the end. + var d = new Date(leftZeroFill(year, 6, true) + '-01-01').getUTCDay(), + daysToAdd, dayOfYear; + + weekday = weekday != null ? weekday : firstDayOfWeek; + daysToAdd = firstDayOfWeek - d + (d > firstDayOfWeekOfYear ? 7 : 0); + dayOfYear = 7 * (week - 1) + (weekday - firstDayOfWeek) + daysToAdd + 1; + + return { + year: dayOfYear > 0 ? year : year - 1, + dayOfYear: dayOfYear > 0 ? dayOfYear : daysInYear(year - 1) + dayOfYear + }; + } + + /************************************ + Top Level Functions + ************************************/ + + function makeMoment(config) { + var input = config._i, + format = config._f; + + if (typeof config._pf === 'undefined') { + initializeParsingFlags(config); + } + + if (input === null) { + return moment.invalid({nullInput: true}); + } + + 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, strict) { + if (typeof(lang) === "boolean") { + strict = lang; + lang = undefined; + } + return makeMoment({ + _i : input, + _f : format, + _l : lang, + _strict : strict, + _isUTC : false + }); + }; + + // creating with utc + moment.utc = function (input, format, lang, strict) { + var m; + + if (typeof(lang) === "boolean") { + strict = lang; + lang = undefined; + } + m = makeMoment({ + _useUTC : true, + _isUTC : true, + _l : lang, + _i : input, + _f : format, + _strict : strict + }).utc(); + + return m; + }; + + // creating with unix timestamp (in seconds) + moment.unix = function (input) { + return moment(input * 1000); + }; + + // duration + moment.duration = function (input, key) { + var duration = input, + // matching against regexp is expensive, do it on demand + match = null, + sign, + ret, + parseIso; + + if (moment.isDuration(input)) { + duration = { + ms: input._milliseconds, + d: input._days, + M: input._months + }; + } else if (typeof input === 'number') { + duration = {}; + if (key) { + duration[key] = input; + } else { + duration.milliseconds = input; + } + } else if (!!(match = aspNetTimeSpanJsonRegex.exec(input))) { + sign = (match[1] === "-") ? -1 : 1; + duration = { + y: 0, + d: toInt(match[DATE]) * sign, + h: toInt(match[HOUR]) * sign, + m: toInt(match[MINUTE]) * sign, + s: toInt(match[SECOND]) * sign, + ms: toInt(match[MILLISECOND]) * sign + }; + } else if (!!(match = isoDurationRegex.exec(input))) { + sign = (match[1] === "-") ? -1 : 1; + parseIso = function (inp) { + // We'd normally use ~~inp for this, but unfortunately it also + // converts floats to ints. + // inp may be undefined, so careful calling replace on it. + var res = inp && parseFloat(inp.replace(',', '.')); + // apply sign while we're at it + return (isNaN(res) ? 0 : res) * sign; + }; + duration = { + y: parseIso(match[2]), + M: parseIso(match[3]), + d: parseIso(match[4]), + h: parseIso(match[5]), + m: parseIso(match[6]), + s: parseIso(match[7]), + w: parseIso(match[8]) + }; + } + + ret = new Duration(duration); + + if (moment.isDuration(input) && input.hasOwnProperty('_lang')) { + ret._lang = input._lang; + } + + return ret; + }; + + // version number + moment.version = VERSION; + + // default format + moment.defaultFormat = isoFormat; + + // This function will be called whenever a moment is mutated. + // It is intended to keep the offset in sync with the timezone. + moment.updateOffset = function () {}; + + // 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 r; + if (!key) { + return moment.fn._lang._abbr; + } + if (values) { + loadLang(normalizeLanguage(key), values); + } else if (values === null) { + unloadLang(key); + key = 'en'; + } else if (!languages[key]) { + getLangDefinition(key); + } + r = moment.duration.fn._lang = moment.fn._lang = getLangDefinition(key); + return r._abbr; + }; + + // 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; + }; + + for (i = lists.length - 1; i >= 0; --i) { + makeList(lists[i]); + } + + moment.normalizeUnits = function (units) { + return normalizeUnits(units); + }; + + moment.invalid = function (flags) { + var m = moment.utc(NaN); + if (flags != null) { + extend(m._pf, flags); + } + else { + m._pf.userInvalidated = true; + } + + return m; + }; + + moment.parseZone = function (input) { + return moment(input).parseZone(); + }; + + /************************************ + Moment Prototype + ************************************/ + + + extend(moment.fn = Moment.prototype, { + + clone : function () { + return moment(this); + }, + + valueOf : function () { + return +this._d + ((this._offset || 0) * 60000); + }, + + unix : function () { + return Math.floor(+this / 1000); + }, + + toString : function () { + return this.clone().lang('en').format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ"); + }, + + toDate : function () { + return this._offset ? new Date(+this) : this._d; + }, + + toISOString : function () { + var m = moment(this).utc(); + if (0 < m.year() && m.year() <= 9999) { + return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); + } else { + return formatMoment(m, 'YYYYYY-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 () { + return isValid(this); + }, + + isDSTShifted : function () { + + if (this._a) { + return this.isValid() && compareArrays(this._a, (this._isUTC ? moment.utc(this._a) : moment(this._a)).toArray()) > 0; + } + + return false; + }, + + parsingFlags : function () { + return extend({}, this._pf); + }, + + invalidAt: function () { + return this._pf.overflow; + }, + + utc : function () { + return this.zone(0); + }, + + local : function () { + this.zone(0); + 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 = makeAs(input, this), + zoneDiff = (this.zone() - that.zone()) * 6e4, + diff, output; + + units = normalizeUnits(units); + + if (units === 'year' || units === 'month') { + // average number of days in the months in the given dates + diff = (this.daysInMonth() + that.daysInMonth()) * 432e5; // 24 * 60 * 60 * 1000 / 2 + // difference in months + output = ((this.year() - that.year()) * 12) + (this.month() - that.month()); + // adjust by taking difference in days, average number of days + // and dst in the given months. + output += ((this - moment(this).startOf('month')) - + (that - moment(that).startOf('month'))) / diff; + // same as above but with zones, to negate all dst + output -= ((this.zone() - moment(this).startOf('month').zone()) - + (that.zone() - moment(that).startOf('month').zone())) * 6e4 / diff; + if (units === 'year') { + output = output / 12; + } + } else { + diff = (this - that); + output = units === 'second' ? diff / 1e3 : // 1000 + units === 'minute' ? diff / 6e4 : // 1000 * 60 + units === 'hour' ? diff / 36e5 : // 1000 * 60 * 60 + units === 'day' ? (diff - zoneDiff) / 864e5 : // 1000 * 60 * 60 * 24, negate dst + units === 'week' ? (diff - zoneDiff) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst + 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 () { + // We want to compare the start of today, vs this. + // Getting start-of-today depends on whether we're zone'd or not. + var sod = makeAs(moment(), this).startOf('day'), + diff = this.diff(sod, '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 () { + return isLeapYear(this.year()); + }, + + isDST : function () { + return (this.zone() < this.clone().month(0).zone() || + this.zone() < this.clone().month(5).zone()); + }, + + day : function (input) { + var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay(); + if (input != null) { + input = parseWeekday(input, this.lang()); + return this.add({ d : input - day }); + } else { + return day; + } + }, + + month : function (input) { + var utc = this._isUTC ? 'UTC' : '', + dayOfMonth; + + if (input != null) { + if (typeof input === 'string') { + input = this.lang().monthsParse(input); + if (typeof input !== 'number') { + return this; + } + } + + dayOfMonth = this.date(); + this.date(1); + this._d['set' + utc + 'Month'](input); + this.date(Math.min(dayOfMonth, this.daysInMonth())); + + moment.updateOffset(this); + return this; + } else { + return this._d['get' + utc + 'Month'](); + } + }, + + startOf: function (units) { + units = normalizeUnits(units); + // 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 'isoWeek': + 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.weekday(0); + } else if (units === 'isoWeek') { + this.isoWeekday(1); + } + + return this; + }, + + endOf: function (units) { + units = normalizeUnits(units); + return this.startOf(units).add((units === 'isoWeek' ? 'week' : units), 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 = units || 'ms'; + return +this.clone().startOf(units) === +makeAs(input, this).startOf(units); + }, + + min: function (other) { + other = moment.apply(null, arguments); + return other < this ? this : other; + }, + + max: function (other) { + other = moment.apply(null, arguments); + return other > this ? this : other; + }, + + zone : function (input) { + var offset = this._offset || 0; + if (input != null) { + if (typeof input === "string") { + input = timezoneMinutesFromString(input); + } + if (Math.abs(input) < 16) { + input = input * 60; + } + this._offset = input; + this._isUTC = true; + if (offset !== input) { + addOrSubtractDurationFromMoment(this, moment.duration(offset - input, 'm'), 1, true); + } + } else { + return this._isUTC ? offset : this._d.getTimezoneOffset(); + } + return this; + }, + + zoneAbbr : function () { + return this._isUTC ? "UTC" : ""; + }, + + zoneName : function () { + return this._isUTC ? "Coordinated Universal Time" : ""; + }, + + parseZone : function () { + if (this._tzm) { + this.zone(this._tzm); + } else if (typeof this._i === 'string') { + this.zone(this._i); + } + return this; + }, + + hasAlignedHourOffset : function (input) { + if (!input) { + input = 0; + } + else { + input = moment(input).zone(); + } + + return (this.zone() - input) % 60 === 0; + }, + + daysInMonth : function () { + return daysInMonth(this.year(), this.month()); + }, + + 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)); + }, + + quarter : function () { + return Math.ceil((this.month() + 1.0) / 3.0); + }, + + weekYear : function (input) { + var year = weekOfYear(this, this.lang()._week.dow, this.lang()._week.doy).year; + return input == null ? year : this.add("y", (input - year)); + }, + + isoWeekYear : function (input) { + var year = weekOfYear(this, 1, 4).year; + return input == null ? year : this.add("y", (input - year)); + }, + + week : function (input) { + var week = this.lang().week(this); + return input == null ? week : this.add("d", (input - week) * 7); + }, + + isoWeek : function (input) { + var week = weekOfYear(this, 1, 4).week; + return input == null ? week : this.add("d", (input - week) * 7); + }, + + weekday : function (input) { + var weekday = (this.day() + 7 - this.lang()._week.dow) % 7; + return input == null ? weekday : this.add("d", input - weekday); + }, + + isoWeekday : function (input) { + // behaves the same as moment#day except + // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6) + // as a setter, sunday should belong to the previous week. + return input == null ? this.day() || 7 : this.day(this.day() % 7 ? input : input - 7); + }, + + get : function (units) { + units = normalizeUnits(units); + return this[units](); + }, + + set : function (units, value) { + units = normalizeUnits(units); + if (typeof this[units] === 'function') { + this[units](value); + } + return this; + }, + + // 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); + moment.updateOffset(this); + 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.months = moment.fn.month; + moment.fn.weeks = moment.fn.week; + moment.fn.isoWeeks = moment.fn.isoWeek; + + // add aliased format methods + moment.fn.toJSON = moment.fn.toISOString; + + /************************************ + Duration Prototype + ************************************/ + + + extend(moment.duration.fn = Duration.prototype, { + + _bubble : function () { + var milliseconds = this._milliseconds, + days = this._days, + months = this._months, + data = this._data, + seconds, minutes, hours, years; + + // 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); + data.days = days % 30; + + months += absRound(days / 30); + data.months = months % 12; + + years = absRound(months / 12); + data.years = years; + }, + + weeks : function () { + return absRound(this.days() / 7); + }, + + valueOf : function () { + return this._milliseconds + + this._days * 864e5 + + (this._months % 12) * 2592e6 + + toInt(this._months / 12) * 31536e6; + }, + + 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); + }, + + add : function (input, val) { + // supports only 2.0-style add(1, 's') or add(moment) + var dur = moment.duration(input, val); + + this._milliseconds += dur._milliseconds; + this._days += dur._days; + this._months += dur._months; + + this._bubble(); + + return this; + }, + + subtract : function (input, val) { + var dur = moment.duration(input, val); + + this._milliseconds -= dur._milliseconds; + this._days -= dur._days; + this._months -= dur._months; + + this._bubble(); + + return this; + }, + + get : function (units) { + units = normalizeUnits(units); + return this[units.toLowerCase() + 's'](); + }, + + as : function (units) { + units = normalizeUnits(units); + return this['as' + units.charAt(0).toUpperCase() + units.slice(1) + 's'](); + }, + + lang : moment.fn.lang, + + toIsoString : function () { + // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js + var years = Math.abs(this.years()), + months = Math.abs(this.months()), + days = Math.abs(this.days()), + hours = Math.abs(this.hours()), + minutes = Math.abs(this.minutes()), + seconds = Math.abs(this.seconds() + this.milliseconds() / 1000); + + if (!this.asSeconds()) { + // this is the same as C#'s (Noda) and python (isodate)... + // but not other JS (goog.date) + return 'P0D'; + } + + return (this.asSeconds() < 0 ? '-' : '') + + 'P' + + (years ? years + 'Y' : '') + + (months ? months + 'M' : '') + + (days ? days + 'D' : '') + + ((hours || minutes || seconds) ? 'T' : '') + + (hours ? hours + 'H' : '') + + (minutes ? minutes + 'M' : '') + + (seconds ? seconds + 'S' : ''); + } + }); + + 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); + moment.duration.fn.asMonths = function () { + return (+this - this.years() * 31536e6) / 2592e6 + this.years() * 12; + }; + + + /************************************ + Default Lang + ************************************/ + + + // Set default language, other languages will inherit from English. + moment.lang('en', { + ordinal : function (number) { + var b = number % 10, + output = (toInt(number % 100 / 10) === 1) ? 'th' : + (b === 1) ? 'st' : + (b === 2) ? 'nd' : + (b === 3) ? 'rd' : 'th'; + return number + output; + } + }); + + /* EMBED_LANGUAGES */ + + /************************************ + Exposing Moment + ************************************/ + + function makeGlobal(deprecate) { + var warned = false, local_moment = moment; + /*global ender:false */ + if (typeof ender !== 'undefined') { + return; + } + // 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 + if (deprecate) { + global.moment = function () { + if (!warned && console && console.warn) { + warned = true; + console.warn( + "Accessing Moment through the global scope is " + + "deprecated, and will be removed in an upcoming " + + "release."); + } + return local_moment.apply(null, arguments); + }; + extend(global.moment, local_moment); + } else { + global['moment'] = moment; + } + } + + // CommonJS module is defined + if (hasModule) { + module.exports = moment; + makeGlobal(true); + } else if (typeof define === "function" && define.amd) { + define("moment", function (require, exports, module) { + if (module.config && module.config() && module.config().noGlobal !== true) { + // If user provided noGlobal, he is aware of global + makeGlobal(module.config().noGlobal === undefined); + } + + return moment; + }); + } else { + makeGlobal(); + } +}).call(this); diff --git a/lib/moment/moment-2.5.0.min.js b/lib/moment/moment-2.5.0.min.js new file mode 100644 index 0000000000000000000000000000000000000000..f253488600c70d8e078bd8295d1923c732936d23 --- /dev/null +++ b/lib/moment/moment-2.5.0.min.js @@ -0,0 +1,6 @@ +//! moment.js +//! version : 2.5.0 +//! authors : Tim Wood, Iskren Chernev, Moment.js contributors +//! license : MIT +//! momentjs.com +(function(a){function b(a,b){return function(c){return i(a.call(this,c),b)}}function c(a,b){return function(c){return this.lang().ordinal(a.call(this,c),b)}}function d(){}function e(a){u(a),g(this,a)}function f(a){var b=o(a),c=b.year||0,d=b.month||0,e=b.week||0,f=b.day||0,g=b.hour||0,h=b.minute||0,i=b.second||0,j=b.millisecond||0;this._milliseconds=+j+1e3*i+6e4*h+36e5*g,this._days=+f+7*e,this._months=+d+12*c,this._data={},this._bubble()}function g(a,b){for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c]);return b.hasOwnProperty("toString")&&(a.toString=b.toString),b.hasOwnProperty("valueOf")&&(a.valueOf=b.valueOf),a}function h(a){return 0>a?Math.ceil(a):Math.floor(a)}function i(a,b,c){for(var d=Math.abs(a)+"",e=a>=0;d.length<b;)d="0"+d;return(e?c?"+":"":"-")+d}function j(a,b,c,d){var e,f,g=b._milliseconds,h=b._days,i=b._months;g&&a._d.setTime(+a._d+g*c),(h||i)&&(e=a.minute(),f=a.hour()),h&&a.date(a.date()+h*c),i&&a.month(a.month()+i*c),g&&!d&&cb.updateOffset(a),(h||i)&&(a.minute(e),a.hour(f))}function k(a){return"[object Array]"===Object.prototype.toString.call(a)}function l(a){return"[object Date]"===Object.prototype.toString.call(a)||a instanceof Date}function m(a,b,c){var d,e=Math.min(a.length,b.length),f=Math.abs(a.length-b.length),g=0;for(d=0;e>d;d++)(c&&a[d]!==b[d]||!c&&q(a[d])!==q(b[d]))&&g++;return g+f}function n(a){if(a){var b=a.toLowerCase().replace(/(.)s$/,"$1");a=Qb[a]||Rb[b]||b}return a}function o(a){var b,c,d={};for(c in a)a.hasOwnProperty(c)&&(b=n(c),b&&(d[b]=a[c]));return d}function p(b){var c,d;if(0===b.indexOf("week"))c=7,d="day";else{if(0!==b.indexOf("month"))return;c=12,d="month"}cb[b]=function(e,f){var g,h,i=cb.fn._lang[b],j=[];if("number"==typeof e&&(f=e,e=a),h=function(a){var b=cb().utc().set(d,a);return i.call(cb.fn._lang,b,e||"")},null!=f)return h(f);for(g=0;c>g;g++)j.push(h(g));return j}}function q(a){var b=+a,c=0;return 0!==b&&isFinite(b)&&(c=b>=0?Math.floor(b):Math.ceil(b)),c}function r(a,b){return new Date(Date.UTC(a,b+1,0)).getUTCDate()}function s(a){return t(a)?366:365}function t(a){return a%4===0&&a%100!==0||a%400===0}function u(a){var b;a._a&&-2===a._pf.overflow&&(b=a._a[ib]<0||a._a[ib]>11?ib:a._a[jb]<1||a._a[jb]>r(a._a[hb],a._a[ib])?jb:a._a[kb]<0||a._a[kb]>23?kb:a._a[lb]<0||a._a[lb]>59?lb:a._a[mb]<0||a._a[mb]>59?mb:a._a[nb]<0||a._a[nb]>999?nb:-1,a._pf._overflowDayOfYear&&(hb>b||b>jb)&&(b=jb),a._pf.overflow=b)}function v(a){a._pf={empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1}}function w(a){return null==a._isValid&&(a._isValid=!isNaN(a._d.getTime())&&a._pf.overflow<0&&!a._pf.empty&&!a._pf.invalidMonth&&!a._pf.nullInput&&!a._pf.invalidFormat&&!a._pf.userInvalidated,a._strict&&(a._isValid=a._isValid&&0===a._pf.charsLeftOver&&0===a._pf.unusedTokens.length)),a._isValid}function x(a){return a?a.toLowerCase().replace("_","-"):a}function y(a,b){return b._isUTC?cb(a).zone(b._offset||0):cb(a).local()}function z(a,b){return b.abbr=a,ob[a]||(ob[a]=new d),ob[a].set(b),ob[a]}function A(a){delete ob[a]}function B(a){var b,c,d,e,f=0,g=function(a){if(!ob[a]&&pb)try{require("./lang/"+a)}catch(b){}return ob[a]};if(!a)return cb.fn._lang;if(!k(a)){if(c=g(a))return c;a=[a]}for(;f<a.length;){for(e=x(a[f]).split("-"),b=e.length,d=x(a[f+1]),d=d?d.split("-"):null;b>0;){if(c=g(e.slice(0,b).join("-")))return c;if(d&&d.length>=b&&m(e,d,!0)>=b-1)break;b--}f++}return cb.fn._lang}function C(a){return a.match(/\[[\s\S]/)?a.replace(/^\[|\]$/g,""):a.replace(/\\/g,"")}function D(a){var b,c,d=a.match(tb);for(b=0,c=d.length;c>b;b++)d[b]=Vb[d[b]]?Vb[d[b]]:C(d[b]);return function(e){var f="";for(b=0;c>b;b++)f+=d[b]instanceof Function?d[b].call(e,a):d[b];return f}}function E(a,b){return a.isValid()?(b=F(b,a.lang()),Sb[b]||(Sb[b]=D(b)),Sb[b](a)):a.lang().invalidDate()}function F(a,b){function c(a){return b.longDateFormat(a)||a}var d=5;for(ub.lastIndex=0;d>=0&&ub.test(a);)a=a.replace(ub,c),ub.lastIndex=0,d-=1;return a}function G(a,b){var c,d=b._strict;switch(a){case"DDDD":return Gb;case"YYYY":case"GGGG":case"gggg":return d?Hb:xb;case"YYYYYY":case"YYYYY":case"GGGGG":case"ggggg":return d?Ib:yb;case"S":if(d)return Eb;case"SS":if(d)return Fb;case"SSS":case"DDD":return d?Gb:wb;case"MMM":case"MMMM":case"dd":case"ddd":case"dddd":return Ab;case"a":case"A":return B(b._l)._meridiemParse;case"X":return Db;case"Z":case"ZZ":return Bb;case"T":return Cb;case"SSSS":return zb;case"MM":case"DD":case"YY":case"GG":case"gg":case"HH":case"hh":case"mm":case"ss":case"ww":case"WW":return d?Fb:vb;case"M":case"D":case"d":case"H":case"h":case"m":case"s":case"w":case"W":case"e":case"E":return d?Eb:vb;default:return c=new RegExp(O(N(a.replace("\\","")),"i"))}}function H(a){a=a||"";var b=a.match(Bb)||[],c=b[b.length-1]||[],d=(c+"").match(Nb)||["-",0,0],e=+(60*d[1])+q(d[2]);return"+"===d[0]?-e:e}function I(a,b,c){var d,e=c._a;switch(a){case"M":case"MM":null!=b&&(e[ib]=q(b)-1);break;case"MMM":case"MMMM":d=B(c._l).monthsParse(b),null!=d?e[ib]=d:c._pf.invalidMonth=b;break;case"D":case"DD":null!=b&&(e[jb]=q(b));break;case"DDD":case"DDDD":null!=b&&(c._dayOfYear=q(b));break;case"YY":e[hb]=q(b)+(q(b)>68?1900:2e3);break;case"YYYY":case"YYYYY":case"YYYYYY":e[hb]=q(b);break;case"a":case"A":c._isPm=B(c._l).isPM(b);break;case"H":case"HH":case"h":case"hh":e[kb]=q(b);break;case"m":case"mm":e[lb]=q(b);break;case"s":case"ss":e[mb]=q(b);break;case"S":case"SS":case"SSS":case"SSSS":e[nb]=q(1e3*("0."+b));break;case"X":c._d=new Date(1e3*parseFloat(b));break;case"Z":case"ZZ":c._useUTC=!0,c._tzm=H(b);break;case"w":case"ww":case"W":case"WW":case"d":case"dd":case"ddd":case"dddd":case"e":case"E":a=a.substr(0,1);case"gg":case"gggg":case"GG":case"GGGG":case"GGGGG":a=a.substr(0,2),b&&(c._w=c._w||{},c._w[a]=b)}}function J(a){var b,c,d,e,f,g,h,i,j,k,l=[];if(!a._d){for(d=L(a),a._w&&null==a._a[jb]&&null==a._a[ib]&&(f=function(b){var c=parseInt(b,10);return b?b.length<3?c>68?1900+c:2e3+c:c:null==a._a[hb]?cb().weekYear():a._a[hb]},g=a._w,null!=g.GG||null!=g.W||null!=g.E?h=Y(f(g.GG),g.W||1,g.E,4,1):(i=B(a._l),j=null!=g.d?U(g.d,i):null!=g.e?parseInt(g.e,10)+i._week.dow:0,k=parseInt(g.w,10)||1,null!=g.d&&j<i._week.dow&&k++,h=Y(f(g.gg),k,j,i._week.doy,i._week.dow)),a._a[hb]=h.year,a._dayOfYear=h.dayOfYear),a._dayOfYear&&(e=null==a._a[hb]?d[hb]:a._a[hb],a._dayOfYear>s(e)&&(a._pf._overflowDayOfYear=!0),c=T(e,0,a._dayOfYear),a._a[ib]=c.getUTCMonth(),a._a[jb]=c.getUTCDate()),b=0;3>b&&null==a._a[b];++b)a._a[b]=l[b]=d[b];for(;7>b;b++)a._a[b]=l[b]=null==a._a[b]?2===b?1:0:a._a[b];l[kb]+=q((a._tzm||0)/60),l[lb]+=q((a._tzm||0)%60),a._d=(a._useUTC?T:S).apply(null,l)}}function K(a){var b;a._d||(b=o(a._i),a._a=[b.year,b.month,b.day,b.hour,b.minute,b.second,b.millisecond],J(a))}function L(a){var b=new Date;return a._useUTC?[b.getUTCFullYear(),b.getUTCMonth(),b.getUTCDate()]:[b.getFullYear(),b.getMonth(),b.getDate()]}function M(a){a._a=[],a._pf.empty=!0;var b,c,d,e,f,g=B(a._l),h=""+a._i,i=h.length,j=0;for(d=F(a._f,g).match(tb)||[],b=0;b<d.length;b++)e=d[b],c=(h.match(G(e,a))||[])[0],c&&(f=h.substr(0,h.indexOf(c)),f.length>0&&a._pf.unusedInput.push(f),h=h.slice(h.indexOf(c)+c.length),j+=c.length),Vb[e]?(c?a._pf.empty=!1:a._pf.unusedTokens.push(e),I(e,c,a)):a._strict&&!c&&a._pf.unusedTokens.push(e);a._pf.charsLeftOver=i-j,h.length>0&&a._pf.unusedInput.push(h),a._isPm&&a._a[kb]<12&&(a._a[kb]+=12),a._isPm===!1&&12===a._a[kb]&&(a._a[kb]=0),J(a),u(a)}function N(a){return a.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(a,b,c,d,e){return b||c||d||e})}function O(a){return a.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function P(a){var b,c,d,e,f;if(0===a._f.length)return a._pf.invalidFormat=!0,a._d=new Date(0/0),void 0;for(e=0;e<a._f.length;e++)f=0,b=g({},a),v(b),b._f=a._f[e],M(b),w(b)&&(f+=b._pf.charsLeftOver,f+=10*b._pf.unusedTokens.length,b._pf.score=f,(null==d||d>f)&&(d=f,c=b));g(a,c||b)}function Q(a){var b,c=a._i,d=Jb.exec(c);if(d){for(a._pf.iso=!0,b=4;b>0;b--)if(d[b]){a._f=Lb[b-1]+(d[6]||" ");break}for(b=0;4>b;b++)if(Mb[b][1].exec(c)){a._f+=Mb[b][0];break}c.match(Bb)&&(a._f+="Z"),M(a)}else a._d=new Date(c)}function R(b){var c=b._i,d=qb.exec(c);c===a?b._d=new Date:d?b._d=new Date(+d[1]):"string"==typeof c?Q(b):k(c)?(b._a=c.slice(0),J(b)):l(c)?b._d=new Date(+c):"object"==typeof c?K(b):b._d=new Date(c)}function S(a,b,c,d,e,f,g){var h=new Date(a,b,c,d,e,f,g);return 1970>a&&h.setFullYear(a),h}function T(a){var b=new Date(Date.UTC.apply(null,arguments));return 1970>a&&b.setUTCFullYear(a),b}function U(a,b){if("string"==typeof a)if(isNaN(a)){if(a=b.weekdaysParse(a),"number"!=typeof a)return null}else a=parseInt(a,10);return a}function V(a,b,c,d,e){return e.relativeTime(b||1,!!c,a,d)}function W(a,b,c){var d=gb(Math.abs(a)/1e3),e=gb(d/60),f=gb(e/60),g=gb(f/24),h=gb(g/365),i=45>d&&["s",d]||1===e&&["m"]||45>e&&["mm",e]||1===f&&["h"]||22>f&&["hh",f]||1===g&&["d"]||25>=g&&["dd",g]||45>=g&&["M"]||345>g&&["MM",gb(g/30)]||1===h&&["y"]||["yy",h];return i[2]=b,i[3]=a>0,i[4]=c,V.apply({},i)}function X(a,b,c){var d,e=c-b,f=c-a.day();return f>e&&(f-=7),e-7>f&&(f+=7),d=cb(a).add("d",f),{week:Math.ceil(d.dayOfYear()/7),year:d.year()}}function Y(a,b,c,d,e){var f,g,h=new Date(i(a,6,!0)+"-01-01").getUTCDay();return c=null!=c?c:e,f=e-h+(h>d?7:0),g=7*(b-1)+(c-e)+f+1,{year:g>0?a:a-1,dayOfYear:g>0?g:s(a-1)+g}}function Z(a){var b=a._i,c=a._f;return"undefined"==typeof a._pf&&v(a),null===b?cb.invalid({nullInput:!0}):("string"==typeof b&&(a._i=b=B().preparse(b)),cb.isMoment(b)?(a=g({},b),a._d=new Date(+b._d)):c?k(c)?P(a):M(a):R(a),new e(a))}function $(a,b){cb.fn[a]=cb.fn[a+"s"]=function(a){var c=this._isUTC?"UTC":"";return null!=a?(this._d["set"+c+b](a),cb.updateOffset(this),this):this._d["get"+c+b]()}}function _(a){cb.duration.fn[a]=function(){return this._data[a]}}function ab(a,b){cb.duration.fn["as"+a]=function(){return+this/b}}function bb(a){var b=!1,c=cb;"undefined"==typeof ender&&(a?(fb.moment=function(){return!b&&console&&console.warn&&(b=!0,console.warn("Accessing Moment through the global scope is deprecated, and will be removed in an upcoming release.")),c.apply(null,arguments)},g(fb.moment,c)):fb.moment=cb)}for(var cb,db,eb="2.5.0",fb=this,gb=Math.round,hb=0,ib=1,jb=2,kb=3,lb=4,mb=5,nb=6,ob={},pb="undefined"!=typeof module&&module.exports&&"undefined"!=typeof require,qb=/^\/?Date\((\-?\d+)/i,rb=/(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/,sb=/^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/,tb=/(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|X|zz?|ZZ?|.)/g,ub=/(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g,vb=/\d\d?/,wb=/\d{1,3}/,xb=/\d{1,4}/,yb=/[+\-]?\d{1,6}/,zb=/\d+/,Ab=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,Bb=/Z|[\+\-]\d\d:?\d\d/gi,Cb=/T/i,Db=/[\+\-]?\d+(\.\d{1,3})?/,Eb=/\d/,Fb=/\d\d/,Gb=/\d{3}/,Hb=/\d{4}/,Ib=/[+\-]?\d{6}/,Jb=/^\s*\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)?)?$/,Kb="YYYY-MM-DDTHH:mm:ssZ",Lb=["YYYY-MM-DD","GGGG-[W]WW","GGGG-[W]WW-E","YYYY-DDD"],Mb=[["HH:mm:ss.SSSS",/(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/]],Nb=/([\+\-]|\d\d)/gi,Ob="Date|Hours|Minutes|Seconds|Milliseconds".split("|"),Pb={Milliseconds:1,Seconds:1e3,Minutes:6e4,Hours:36e5,Days:864e5,Months:2592e6,Years:31536e6},Qb={ms:"millisecond",s:"second",m:"minute",h:"hour",d:"day",D:"date",w:"week",W:"isoWeek",M:"month",y:"year",DDD:"dayOfYear",e:"weekday",E:"isoWeekday",gg:"weekYear",GG:"isoWeekYear"},Rb={dayofyear:"dayOfYear",isoweekday:"isoWeekday",isoweek:"isoWeek",weekyear:"weekYear",isoweekyear:"isoWeekYear"},Sb={},Tb="DDD w W M D d".split(" "),Ub="M D H h m s w W".split(" "),Vb={M:function(){return this.month()+1},MMM:function(a){return this.lang().monthsShort(this,a)},MMMM:function(a){return this.lang().months(this,a)},D:function(){return this.date()},DDD:function(){return this.dayOfYear()},d:function(){return this.day()},dd:function(a){return this.lang().weekdaysMin(this,a)},ddd:function(a){return this.lang().weekdaysShort(this,a)},dddd:function(a){return this.lang().weekdays(this,a)},w:function(){return this.week()},W:function(){return this.isoWeek()},YY:function(){return i(this.year()%100,2)},YYYY:function(){return i(this.year(),4)},YYYYY:function(){return i(this.year(),5)},YYYYYY:function(){var a=this.year(),b=a>=0?"+":"-";return b+i(Math.abs(a),6)},gg:function(){return i(this.weekYear()%100,2)},gggg:function(){return this.weekYear()},ggggg:function(){return i(this.weekYear(),5)},GG:function(){return i(this.isoWeekYear()%100,2)},GGGG:function(){return this.isoWeekYear()},GGGGG:function(){return i(this.isoWeekYear(),5)},e:function(){return this.weekday()},E:function(){return this.isoWeekday()},a:function(){return this.lang().meridiem(this.hours(),this.minutes(),!0)},A:function(){return this.lang().meridiem(this.hours(),this.minutes(),!1)},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 q(this.milliseconds()/100)},SS:function(){return i(q(this.milliseconds()/10),2)},SSS:function(){return i(this.milliseconds(),3)},SSSS:function(){return i(this.milliseconds(),3)},Z:function(){var a=-this.zone(),b="+";return 0>a&&(a=-a,b="-"),b+i(q(a/60),2)+":"+i(q(a)%60,2)},ZZ:function(){var a=-this.zone(),b="+";return 0>a&&(a=-a,b="-"),b+i(q(a/60),2)+i(q(a)%60,2)},z:function(){return this.zoneAbbr()},zz:function(){return this.zoneName()},X:function(){return this.unix()},Q:function(){return this.quarter()}},Wb=["months","monthsShort","weekdays","weekdaysShort","weekdaysMin"];Tb.length;)db=Tb.pop(),Vb[db+"o"]=c(Vb[db],db);for(;Ub.length;)db=Ub.pop(),Vb[db+db]=b(Vb[db],2);for(Vb.DDDD=b(Vb.DDD,3),g(d.prototype,{set:function(a){var b,c;for(c in a)b=a[c],"function"==typeof b?this[c]=b:this["_"+c]=b},_months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),months:function(a){return this._months[a.month()]},_monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),monthsShort:function(a){return this._monthsShort[a.month()]},monthsParse:function(a){var b,c,d;for(this._monthsParse||(this._monthsParse=[]),b=0;12>b;b++)if(this._monthsParse[b]||(c=cb.utc([2e3,b]),d="^"+this.months(c,"")+"|^"+this.monthsShort(c,""),this._monthsParse[b]=new RegExp(d.replace(".",""),"i")),this._monthsParse[b].test(a))return b},_weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdays:function(a){return this._weekdays[a.day()]},_weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysShort:function(a){return this._weekdaysShort[a.day()]},_weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),weekdaysMin:function(a){return this._weekdaysMin[a.day()]},weekdaysParse:function(a){var b,c,d;for(this._weekdaysParse||(this._weekdaysParse=[]),b=0;7>b;b++)if(this._weekdaysParse[b]||(c=cb([2e3,1]).day(b),d="^"+this.weekdays(c,"")+"|^"+this.weekdaysShort(c,"")+"|^"+this.weekdaysMin(c,""),this._weekdaysParse[b]=new RegExp(d.replace(".",""),"i")),this._weekdaysParse[b].test(a))return b},_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(a){var b=this._longDateFormat[a];return!b&&this._longDateFormat[a.toUpperCase()]&&(b=this._longDateFormat[a.toUpperCase()].replace(/MMMM|MM|DD|dddd/g,function(a){return a.slice(1)}),this._longDateFormat[a]=b),b},isPM:function(a){return"p"===(a+"").toLowerCase().charAt(0)},_meridiemParse:/[ap]\.?m?\.?/i,meridiem:function(a,b,c){return a>11?c?"pm":"PM":c?"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(a,b){var c=this._calendar[a];return"function"==typeof c?c.apply(b):c},_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(a,b,c,d){var e=this._relativeTime[c];return"function"==typeof e?e(a,b,c,d):e.replace(/%d/i,a)},pastFuture:function(a,b){var c=this._relativeTime[a>0?"future":"past"];return"function"==typeof c?c(b):c.replace(/%s/i,b)},ordinal:function(a){return this._ordinal.replace("%d",a)},_ordinal:"%d",preparse:function(a){return a},postformat:function(a){return a},week:function(a){return X(a,this._week.dow,this._week.doy).week},_week:{dow:0,doy:6},_invalidDate:"Invalid date",invalidDate:function(){return this._invalidDate}}),cb=function(b,c,d,e){return"boolean"==typeof d&&(e=d,d=a),Z({_i:b,_f:c,_l:d,_strict:e,_isUTC:!1})},cb.utc=function(b,c,d,e){var f;return"boolean"==typeof d&&(e=d,d=a),f=Z({_useUTC:!0,_isUTC:!0,_l:d,_i:b,_f:c,_strict:e}).utc()},cb.unix=function(a){return cb(1e3*a)},cb.duration=function(a,b){var c,d,e,g=a,h=null;return cb.isDuration(a)?g={ms:a._milliseconds,d:a._days,M:a._months}:"number"==typeof a?(g={},b?g[b]=a:g.milliseconds=a):(h=rb.exec(a))?(c="-"===h[1]?-1:1,g={y:0,d:q(h[jb])*c,h:q(h[kb])*c,m:q(h[lb])*c,s:q(h[mb])*c,ms:q(h[nb])*c}):(h=sb.exec(a))&&(c="-"===h[1]?-1:1,e=function(a){var b=a&&parseFloat(a.replace(",","."));return(isNaN(b)?0:b)*c},g={y:e(h[2]),M:e(h[3]),d:e(h[4]),h:e(h[5]),m:e(h[6]),s:e(h[7]),w:e(h[8])}),d=new f(g),cb.isDuration(a)&&a.hasOwnProperty("_lang")&&(d._lang=a._lang),d},cb.version=eb,cb.defaultFormat=Kb,cb.updateOffset=function(){},cb.lang=function(a,b){var c;return a?(b?z(x(a),b):null===b?(A(a),a="en"):ob[a]||B(a),c=cb.duration.fn._lang=cb.fn._lang=B(a),c._abbr):cb.fn._lang._abbr},cb.langData=function(a){return a&&a._lang&&a._lang._abbr&&(a=a._lang._abbr),B(a)},cb.isMoment=function(a){return a instanceof e},cb.isDuration=function(a){return a instanceof f},db=Wb.length-1;db>=0;--db)p(Wb[db]);for(cb.normalizeUnits=function(a){return n(a)},cb.invalid=function(a){var b=cb.utc(0/0);return null!=a?g(b._pf,a):b._pf.userInvalidated=!0,b},cb.parseZone=function(a){return cb(a).parseZone()},g(cb.fn=e.prototype,{clone:function(){return cb(this)},valueOf:function(){return+this._d+6e4*(this._offset||0)},unix:function(){return Math.floor(+this/1e3)},toString:function(){return this.clone().lang("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},toDate:function(){return this._offset?new Date(+this):this._d},toISOString:function(){var a=cb(this).utc();return 0<a.year()&&a.year()<=9999?E(a,"YYYY-MM-DD[T]HH:mm:ss.SSS[Z]"):E(a,"YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]")},toArray:function(){var a=this;return[a.year(),a.month(),a.date(),a.hours(),a.minutes(),a.seconds(),a.milliseconds()]},isValid:function(){return w(this)},isDSTShifted:function(){return this._a?this.isValid()&&m(this._a,(this._isUTC?cb.utc(this._a):cb(this._a)).toArray())>0:!1},parsingFlags:function(){return g({},this._pf)},invalidAt:function(){return this._pf.overflow},utc:function(){return this.zone(0)},local:function(){return this.zone(0),this._isUTC=!1,this},format:function(a){var b=E(this,a||cb.defaultFormat);return this.lang().postformat(b)},add:function(a,b){var c;return c="string"==typeof a?cb.duration(+b,a):cb.duration(a,b),j(this,c,1),this},subtract:function(a,b){var c;return c="string"==typeof a?cb.duration(+b,a):cb.duration(a,b),j(this,c,-1),this},diff:function(a,b,c){var d,e,f=y(a,this),g=6e4*(this.zone()-f.zone());return b=n(b),"year"===b||"month"===b?(d=432e5*(this.daysInMonth()+f.daysInMonth()),e=12*(this.year()-f.year())+(this.month()-f.month()),e+=(this-cb(this).startOf("month")-(f-cb(f).startOf("month")))/d,e-=6e4*(this.zone()-cb(this).startOf("month").zone()-(f.zone()-cb(f).startOf("month").zone()))/d,"year"===b&&(e/=12)):(d=this-f,e="second"===b?d/1e3:"minute"===b?d/6e4:"hour"===b?d/36e5:"day"===b?(d-g)/864e5:"week"===b?(d-g)/6048e5:d),c?e:h(e)},from:function(a,b){return cb.duration(this.diff(a)).lang(this.lang()._abbr).humanize(!b)},fromNow:function(a){return this.from(cb(),a)},calendar:function(){var a=y(cb(),this).startOf("day"),b=this.diff(a,"days",!0),c=-6>b?"sameElse":-1>b?"lastWeek":0>b?"lastDay":1>b?"sameDay":2>b?"nextDay":7>b?"nextWeek":"sameElse";return this.format(this.lang().calendar(c,this))},isLeapYear:function(){return t(this.year())},isDST:function(){return this.zone()<this.clone().month(0).zone()||this.zone()<this.clone().month(5).zone()},day:function(a){var b=this._isUTC?this._d.getUTCDay():this._d.getDay();return null!=a?(a=U(a,this.lang()),this.add({d:a-b})):b},month:function(a){var b,c=this._isUTC?"UTC":"";return null!=a?"string"==typeof a&&(a=this.lang().monthsParse(a),"number"!=typeof a)?this:(b=this.date(),this.date(1),this._d["set"+c+"Month"](a),this.date(Math.min(b,this.daysInMonth())),cb.updateOffset(this),this):this._d["get"+c+"Month"]()},startOf:function(a){switch(a=n(a)){case"year":this.month(0);case"month":this.date(1);case"week":case"isoWeek":case"day":this.hours(0);case"hour":this.minutes(0);case"minute":this.seconds(0);case"second":this.milliseconds(0)}return"week"===a?this.weekday(0):"isoWeek"===a&&this.isoWeekday(1),this},endOf:function(a){return a=n(a),this.startOf(a).add("isoWeek"===a?"week":a,1).subtract("ms",1)},isAfter:function(a,b){return b="undefined"!=typeof b?b:"millisecond",+this.clone().startOf(b)>+cb(a).startOf(b)},isBefore:function(a,b){return b="undefined"!=typeof b?b:"millisecond",+this.clone().startOf(b)<+cb(a).startOf(b)},isSame:function(a,b){return b=b||"ms",+this.clone().startOf(b)===+y(a,this).startOf(b)},min:function(a){return a=cb.apply(null,arguments),this>a?this:a},max:function(a){return a=cb.apply(null,arguments),a>this?this:a},zone:function(a){var b=this._offset||0;return null==a?this._isUTC?b:this._d.getTimezoneOffset():("string"==typeof a&&(a=H(a)),Math.abs(a)<16&&(a=60*a),this._offset=a,this._isUTC=!0,b!==a&&j(this,cb.duration(b-a,"m"),1,!0),this)},zoneAbbr:function(){return this._isUTC?"UTC":""},zoneName:function(){return this._isUTC?"Coordinated Universal Time":""},parseZone:function(){return this._tzm?this.zone(this._tzm):"string"==typeof this._i&&this.zone(this._i),this},hasAlignedHourOffset:function(a){return a=a?cb(a).zone():0,(this.zone()-a)%60===0},daysInMonth:function(){return r(this.year(),this.month())},dayOfYear:function(a){var b=gb((cb(this).startOf("day")-cb(this).startOf("year"))/864e5)+1;return null==a?b:this.add("d",a-b)},quarter:function(){return Math.ceil((this.month()+1)/3)},weekYear:function(a){var b=X(this,this.lang()._week.dow,this.lang()._week.doy).year;return null==a?b:this.add("y",a-b)},isoWeekYear:function(a){var b=X(this,1,4).year;return null==a?b:this.add("y",a-b)},week:function(a){var b=this.lang().week(this);return null==a?b:this.add("d",7*(a-b))},isoWeek:function(a){var b=X(this,1,4).week;return null==a?b:this.add("d",7*(a-b))},weekday:function(a){var b=(this.day()+7-this.lang()._week.dow)%7;return null==a?b:this.add("d",a-b)},isoWeekday:function(a){return null==a?this.day()||7:this.day(this.day()%7?a:a-7)},get:function(a){return a=n(a),this[a]()},set:function(a,b){return a=n(a),"function"==typeof this[a]&&this[a](b),this},lang:function(b){return b===a?this._lang:(this._lang=B(b),this)}}),db=0;db<Ob.length;db++)$(Ob[db].toLowerCase().replace(/s$/,""),Ob[db]);$("year","FullYear"),cb.fn.days=cb.fn.day,cb.fn.months=cb.fn.month,cb.fn.weeks=cb.fn.week,cb.fn.isoWeeks=cb.fn.isoWeek,cb.fn.toJSON=cb.fn.toISOString,g(cb.duration.fn=f.prototype,{_bubble:function(){var a,b,c,d,e=this._milliseconds,f=this._days,g=this._months,i=this._data;i.milliseconds=e%1e3,a=h(e/1e3),i.seconds=a%60,b=h(a/60),i.minutes=b%60,c=h(b/60),i.hours=c%24,f+=h(c/24),i.days=f%30,g+=h(f/30),i.months=g%12,d=h(g/12),i.years=d},weeks:function(){return h(this.days()/7)},valueOf:function(){return this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*q(this._months/12)},humanize:function(a){var b=+this,c=W(b,!a,this.lang());return a&&(c=this.lang().pastFuture(b,c)),this.lang().postformat(c)},add:function(a,b){var c=cb.duration(a,b);return this._milliseconds+=c._milliseconds,this._days+=c._days,this._months+=c._months,this._bubble(),this},subtract:function(a,b){var c=cb.duration(a,b);return this._milliseconds-=c._milliseconds,this._days-=c._days,this._months-=c._months,this._bubble(),this},get:function(a){return a=n(a),this[a.toLowerCase()+"s"]()},as:function(a){return a=n(a),this["as"+a.charAt(0).toUpperCase()+a.slice(1)+"s"]()},lang:cb.fn.lang,toIsoString:function(){var a=Math.abs(this.years()),b=Math.abs(this.months()),c=Math.abs(this.days()),d=Math.abs(this.hours()),e=Math.abs(this.minutes()),f=Math.abs(this.seconds()+this.milliseconds()/1e3);return this.asSeconds()?(this.asSeconds()<0?"-":"")+"P"+(a?a+"Y":"")+(b?b+"M":"")+(c?c+"D":"")+(d||e||f?"T":"")+(d?d+"H":"")+(e?e+"M":"")+(f?f+"S":""):"P0D"}});for(db in Pb)Pb.hasOwnProperty(db)&&(ab(db,Pb[db]),_(db.toLowerCase()));ab("Weeks",6048e5),cb.duration.fn.asMonths=function(){return(+this-31536e6*this.years())/2592e6+12*this.years()},cb.lang("en",{ordinal:function(a){var b=a%10,c=1===q(a%100/10)?"th":1===b?"st":2===b?"nd":3===b?"rd":"th";return a+c}}),pb?(module.exports=cb,bb(!0)):"function"==typeof define&&define.amd?define("moment",function(b,c,d){return d.config&&d.config()&&d.config().noGlobal!==!0&&bb(d.config().noGlobal===a),cb}):bb()}).call(this); \ No newline at end of file diff --git a/src/jio.date/jiodate.js b/src/jio.date/jiodate.js new file mode 100644 index 0000000000000000000000000000000000000000..3e19a39e59eabe945e87541f2db5ddf9036986f3 --- /dev/null +++ b/src/jio.date/jiodate.js @@ -0,0 +1,212 @@ +/*jslint indent: 2, nomen: true */ +/*global module, define, exports, window, moment */ + +// define([module_name], [dependencies], module); +(function (dependencies, module) { + "use strict"; + if (typeof define === 'function' && define.amd) { + return define(dependencies, module); + } + if (typeof exports === 'object') { + return module(exports, moment); + } + window.jiodate = {}; + module(window.jiodate, moment); +}(['exports', 'moment'], function (to_export, moment) { + "use strict"; + + /** + * Add a secured (write permission denied) property to an object. + * + * @param {Object} object The object to fill + * @param {String} key The object key where to store the property + * @param {Any} value The value to store + */ + function _export(key, value) { + Object.defineProperty(to_export, key, { + "configurable": false, + "enumerable": true, + "writable": false, + "value": value + }); + } + + var YEAR = 'year', + MONTH = 'month', + DAY = 'day', + HOUR = 'hour', + MIN = 'minute', + SEC = 'second', + MSEC = 'millisecond', + precision_grade = { + 'year': 0, + 'month': 1, + 'day': 2, + 'hour': 3, + 'minute': 4, + 'second': 5, + 'millisecond': 6 + }, + lesserPrecision = function (p1, p2) { + return (precision_grade[p1] < precision_grade[p2]) ? p1 : p2; + }, + JIODate = null; + + + JIODate = function (str) { + // in case of forgotten 'new' + if (!(this instanceof JIODate)) { + return new JIODate(str); + } + + if (str instanceof JIODate) { + this.mom = str.mom.clone(); + this._precision = str._precision; + return; + } + + if (str === undefined) { + this.mom = moment(); + this.setPrecision(MSEC); + return; + } + + this.mom = null; + + // http://www.w3.org/TR/NOTE-datetime + // http://dotat.at/tmp/ISO_8601-2004_E.pdf + + // XXX these regexps fail to detect many invalid dates. + + if (str.match(/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+\-][0-2]\d:[0-5]\d|Z)/) + || str.match(/\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d\.\d\d\d/)) { + // ISO, milliseconds + this.mom = moment(str); + this.setPrecision(MSEC); + } else if (str.match(/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+\-][0-2]\d:[0-5]\d|Z)/) + || str.match(/\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d/)) { + // ISO, seconds + this.mom = moment(str); + this.setPrecision(SEC); + } else if (str.match(/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+\-][0-2]\d:[0-5]\d|Z)/) + || str.match(/\d\d\d\d-\d\d-\d\d \d\d:\d\d/)) { + // ISO, minutes + this.mom = moment(str); + this.setPrecision(MIN); + } else if (str.match(/\d\d\d\d-\d\d-\d\d \d\d/)) { + this.mom = moment(str); + this.setPrecision(HOUR); + } else if (str.match(/\d\d\d\d-\d\d-\d\d/)) { + this.mom = moment(str); + this.setPrecision(DAY); + } else if (str.match(/\d\d\d\d-\d\d/)) { + this.mom = moment(str); + this.setPrecision(MONTH); + } else if (str.match(/\d\d\d\d/)) { + this.mom = moment(str); + this.setPrecision(YEAR); + } + + if (!this.mom) { + throw new Error("Cannot parse: " + str); + } + + }; + + + JIODate.prototype.setPrecision = function (prec) { + this._precision = prec; + }; + + + JIODate.prototype.getPrecision = function () { + return this._precision; + }; + + + JIODate.prototype.eq = function (other) { + var p = lesserPrecision(this._precision, other._precision); + return this.mom.isSame(other.mom, p); + }; + + + JIODate.prototype.ne = function (other) { + return (!this.eq(other)); + }; + + + JIODate.prototype.gt = function (other) { + var p = lesserPrecision(this._precision, other._precision); + return this.mom.isAfter(other.mom, p); + }; + + + JIODate.prototype.lt = function (other) { + // XXX using the lesser precision cannot change the result (but check with business calendar) + var p = lesserPrecision(this._precision, other._precision); + return this.mom.isBefore(other.mom, p); + }; + + + JIODate.prototype.ge = function (other) { + // XXX using the lesser precision cannot change the result (but check with business calendar) + var m1 = this.mom, + m2 = other.mom, + p = lesserPrecision(this._precision, other._precision); + return m1.isAfter(m2, p) || m1.isSame(m2, p); + }; + + + JIODate.prototype.le = function (other) { + var m1 = this.mom, + m2 = other.mom, + p = lesserPrecision(this._precision, other._precision); + return m1.isBefore(m2, p) || m1.isSame(m2, p); + }; + + + JIODate.prototype.cmp = function (other) { + var m1 = this.mom, + m2 = other.mom, + p = lesserPrecision(this._precision, other._precision); + return m1.isBefore(m2, p) ? -1 : (m1.isSame(m2, p) ? 0 : +1); + }; + + + JIODate.prototype.toPrecisionString = function (precision) { + var fmt; + + precision = precision || this._precision; + + fmt = { + 'millisecond': 'YYYY-MM-DD HH:mm:ss.SSS', + 'second': 'YYYY-MM-DD HH:mm:ss', + 'minute': 'YYYY-MM-DD HH:mm', + 'hour': 'YYYY-MM-DD HH', + 'day': 'YYYY-MM-DD', + 'month': 'YYYY-MM', + 'year': 'YYYY' + }[precision]; + + if (!fmt) { + throw new TypeError("Unsupported precision value '" + precision + "'"); + } + + return this.mom.format(fmt); + }; + + + _export('JIODate', JIODate); + + _export('YEAR', YEAR); + _export('MONTH', MONTH); + _export('DAY', DAY); + _export('HOUR', HOUR); + _export('MIN', MIN); + _export('SEC', SEC); + _export('MSEC', MSEC); + + return to_export; + +})); + diff --git a/src/queries/core/simplequery.js b/src/queries/core/simplequery.js index 3fb4017069a727db6c67058caa128267e2716159..1a4926fa43ff9cc35c88373d0d6d43ea8dfb2371 100644 --- a/src/queries/core/simplequery.js +++ b/src/queries/core/simplequery.js @@ -208,6 +208,9 @@ SimpleQuery.prototype["="] = function (object_value, comparison_value, if (value === undefined) { return false; } + if (value.eq !== undefined) { + return value.eq(comparison_value); + } if ( convertStringToRegExp( comparison_value.toString(), @@ -249,6 +252,9 @@ SimpleQuery.prototype["!="] = function (object_value, comparison_value, if (value === undefined) { return true; } + if (value.ne !== undefined) { + return value.ne(comparison_value); + } if ( convertStringToRegExp( comparison_value.toString(), @@ -278,6 +284,9 @@ SimpleQuery.prototype["<"] = function (object_value, comparison_value) { if (typeof value === 'object' && value.hasOwnProperty('content')) { value = value.content; } + if (value.lt !== undefined) { + return value.lt(comparison_value); + } return value < comparison_value; }; @@ -299,6 +308,9 @@ SimpleQuery.prototype["<="] = function (object_value, comparison_value) { if (typeof value === 'object' && value.hasOwnProperty('content')) { value = value.content; } + if (value.le !== undefined) { + return value.le(comparison_value); + } return value <= comparison_value; }; @@ -320,6 +332,9 @@ SimpleQuery.prototype[">"] = function (object_value, comparison_value) { if (typeof value === 'object' && value.hasOwnProperty('content')) { value = value.content; } + if (value.gt !== undefined) { + return value.gt(comparison_value); + } return value > comparison_value; }; @@ -341,6 +356,9 @@ SimpleQuery.prototype[">="] = function (object_value, comparison_value) { if (typeof value === 'object' && value.hasOwnProperty('content')) { value = value.content; } + if (value.ge !== undefined) { + return value.ge(comparison_value); + } return value >= comparison_value; }; diff --git a/test/queries/jiodate.key.tests.js b/test/queries/jiodate.key.tests.js new file mode 100644 index 0000000000000000000000000000000000000000..28d6b08ec7139cd7182dc588de2a6dfa31502bcd --- /dev/null +++ b/test/queries/jiodate.key.tests.js @@ -0,0 +1,108 @@ +/*jslint indent: 2, maxlen: 120, nomen: true, vars: true */ +/*global define, exports, require, module, complex_queries, jiodate, window, test, ok, + equal, deepEqual, sinon */ + +// define([module_name], [dependencies], module); +(function (dependencies, module) { + "use strict"; + if (typeof define === 'function' && define.amd) { + return define(dependencies, module); + } + if (typeof exports === 'object') { + return module(require('complex_queries'), require('jiodate')); + } + module(complex_queries, jiodate); +}(['complex_queries', 'jiodate', 'qunit'], function (complex_queries, jiodate) { + "use strict"; + + module('JIODate with custom keys'); + + test('Stock comparison operators with year precision', function () { + var doc_list, docList = function () { + return [ + {'identifier': 'twenty ten', 'date': '2010-03-04T08:52:13.746Z'}, + {'identifier': 'twenty eleven', 'date': '2011-03-04T08:52:13.746Z'}, + {'identifier': 'twenty twelve', 'date': '2012-03-04T08:52:13.746Z'} + ]; + }, key_schema = { + key_set: { + date: { + read_from: 'date', + cast_to: jiodate.JIODate + } + } + }; + + doc_list = docList(); + complex_queries.QueryFactory.create({ + type: 'simple', + key: 'date', + value: '2011' + }, key_schema).exec(doc_list); + deepEqual(doc_list, [ + {'date': '2011-03-04T08:52:13.746Z', 'identifier': 'twenty eleven'} + ], 'Match with "date = 2011" (query tree form)'); + + doc_list = docList(); + complex_queries.QueryFactory.create({ + type: 'simple', + key: 'date', + operator: '!=', + value: '2011' + }, key_schema).exec(doc_list); + deepEqual(doc_list, [ + {'date': '2010-03-04T08:52:13.746Z', 'identifier': 'twenty ten'}, + {'date': '2012-03-04T08:52:13.746Z', 'identifier': 'twenty twelve'} + ], 'Match with "date != 2011" (query tree form)'); + + doc_list = docList(); + complex_queries.QueryFactory.create({ + type: 'simple', + key: 'date', + operator: '<', + value: '2011' + }, key_schema).exec(doc_list); + deepEqual(doc_list, [ + {'date': '2010-03-04T08:52:13.746Z', 'identifier': 'twenty ten'} + ], 'Match with "date < 2011" (query tree form)'); + + doc_list = docList(); + complex_queries.QueryFactory.create({ + type: 'simple', + key: 'date', + operator: '<=', + value: '2011' + }, key_schema).exec(doc_list); + deepEqual(doc_list, [ + {'date': '2010-03-04T08:52:13.746Z', 'identifier': 'twenty ten'}, + {'date': '2011-03-04T08:52:13.746Z', 'identifier': 'twenty eleven'} + ], 'Match with "date <= 2011" (query tree form)'); + + doc_list = docList(); + complex_queries.QueryFactory.create({ + type: 'simple', + key: 'date', + operator: '>', + value: '2011' + }, key_schema).exec(doc_list); + deepEqual(doc_list, [ + {'date': '2012-03-04T08:52:13.746Z', 'identifier': 'twenty twelve'} + ], 'Match with "date > 2011" (query tree form)'); + + doc_list = docList(); + complex_queries.QueryFactory.create({ + type: 'simple', + key: 'date', + operator: '>=', + value: '2011' + }, key_schema).exec(doc_list); + deepEqual(doc_list, [ + {'date': '2011-03-04T08:52:13.746Z', 'identifier': 'twenty eleven'}, + {'date': '2012-03-04T08:52:13.746Z', 'identifier': 'twenty twelve'} + ], 'Match with "date >= 2011" (query tree form)'); + + + }); + + +})); diff --git a/test/queries/jiodate.tests.js b/test/queries/jiodate.tests.js new file mode 100644 index 0000000000000000000000000000000000000000..a4bcfd5f36fe5292d75313e3b2a7dfe14304382e --- /dev/null +++ b/test/queries/jiodate.tests.js @@ -0,0 +1,334 @@ +/*jslint indent: 2, newcap: true */ +/*global define, exports, require, test, ok, strictEqual, equal, throws, jiodate, moment, module */ + + +// define([module_name], [dependencies], module); +(function (dependencies, module) { + "use strict"; + if (typeof define === 'function' && define.amd) { + return define(dependencies, module); + } + if (typeof exports === 'object') { + return module(require('jiodate'), require('moment')); + } + module(jiodate, moment); +}(['jiodate', 'moment', 'qunit'], function (jiodate, moment) { + "use strict"; + + module('JIODate'); + + var JIODate = jiodate.JIODate; + + test("A JIODate can be instantiated without parameters (=now)", function () { + ok((new JIODate()) instanceof JIODate); + ok(JIODate() instanceof JIODate); + }); + + + test("Parsing from ISO string and exposing Moment/Date objects", function () { + var d = JIODate('2012-03-04T08:52:13.746Z'); + ok(moment.isMoment(d.mom)); + strictEqual(d.mom.toISOString(), '2012-03-04T08:52:13.746Z'); + strictEqual(d.mom.year(), 2012); + strictEqual(d.mom.month(), 2); + strictEqual(d.mom.date(), 4); + // and so on.. + strictEqual(d.mom.isoWeekday(), 7); + strictEqual(d.mom.dayOfYear(), 64); + strictEqual(d.mom.week(), 10); + strictEqual(d.mom.isoWeek(), 9); + strictEqual(d.mom.day(), 0); + strictEqual(d.mom.hours(), 9); + strictEqual(d.mom.minutes(), 52); + strictEqual(d.mom.seconds(), 13); + strictEqual(d.mom.milliseconds(), 746); + // careful: changing the Date object changes the moment as well + ok(d.mom.toDate() instanceof Date); + }); + + + test("By default, maximum precision is kept, but it can be changed later", function () { + var d = new JIODate(); + + equal(d.getPrecision(), jiodate.MSEC); + d.setPrecision(jiodate.SEC); + equal(d.getPrecision(), jiodate.SEC); + d.setPrecision(jiodate.DAY); + equal(d.getPrecision(), jiodate.DAY); + d.setPrecision(jiodate.MONTH); + equal(d.getPrecision(), jiodate.MONTH); + }); + + + test("Passing a JIODate object to the constructor clones it", function () { + var d = JIODate('2012-05-06'); + ok(d.eq(JIODate(d))); + }); + + + test("Comparison with eq/ne/gt/lt/ge/le/cmp - any precision", function () { + var data = [ + [ + jiodate.MSEC, + '2012-03-04T08:52:13.746Z', + '2012-03-04T08:52:13.746Z', + '2012-03-04T08:52:13.747Z' + ], [ + jiodate.SEC, + '2012-03-04T08:52:13.746Z', + '2012-03-04T08:52:13.999Z', + '2012-03-04T08:52:14.746Z' + ], [ + jiodate.MIN, + '2012-03-04T08:52:13.746Z', + '2012-03-04T08:52:59.999Z', + '2012-03-04T08:53:13.746Z' + ], [ + jiodate.HOUR, + '2012-03-04T08:52:13.746Z', + '2012-03-04T08:59:59.999Z', + '2012-03-04T09:52:13.746Z' + ], [ + jiodate.DAY, + '2012-03-04T08:52:13.746Z', + '2012-03-04T20:59:59.999Z', + '2012-03-05T08:52:13.746Z' + ], [ + jiodate.MONTH, + '2012-03-04T08:52:13.746Z', + '2012-03-31T20:59:59.999Z', + '2012-04-04T08:53:13.746Z' + ], [ + jiodate.YEAR, + '2012-03-04T08:52:13.746Z', + '2012-12-31T20:59:59.999Z', + '2013-03-04T08:53:13.746Z' + ] + ], i = 0, precision, d1, d2, d3, s1, s2, s3, mp; + + for (i = 0; i < data.length; i += 1) { + precision = data[i][0]; + d1 = JIODate(data[i][1]); + d2 = JIODate(data[i][2]); + d3 = JIODate(data[i][3]); + + d1.setPrecision(precision); + d2.setPrecision(precision); + d3.setPrecision(precision); + + s1 = d1.mom.format(); + s2 = d2.mom.format(); + s3 = d3.mom.format(); + + mp = ' - ' + precision; + + // 1 vs 2 + ok(d1.eq(d2), s1 + ' == ' + s2 + mp); + ok(!d1.ne(d2), 'not (' + s1 + ' != ' + s2 + ')' + mp); + ok(!d1.gt(d2), 'not (' + s1 + ' > ' + s2 + ')' + mp); + ok(d1.ge(d2), s1 + ' >= ' + s2 + mp); + ok(!d1.lt(d2), 'not (' + s1 + ' < ' + s2 + ')' + mp); + ok(d1.le(d2), s1 + ' <= ' + s2 + mp); + strictEqual(d1.cmp(d2), 0, s1 + ' cmp ' + s2 + mp); + + // 1 vs 3 + ok(!d1.eq(d3), 'not (' + s1 + ' == ' + s3 + ')' + mp); + ok(d1.ne(d3), s1 + ' != ' + s3 + mp); + ok(!d1.gt(d3), 'not (' + s1 + ' > ' + s3 + ')' + mp); + ok(!d1.ge(d3), 'not (' + s1 + ' >= ' + s3 + ')' + mp); + ok(d1.lt(d3), s1 + ' < ' + s3 + mp); + ok(d1.le(d3), s1 + ' <= ' + s3 + mp); + strictEqual(d1.cmp(d3), -1, s1 + ' cmp ' + s3 + mp); + + // 2 vs 1 + ok(d2.eq(d1), s2 + ' == ' + s1 + mp); + ok(!d2.ne(d1), 'not (' + s2 + ' != ' + s1 + ')' + mp); + ok(!d2.gt(d1), 'not (' + s2 + ' > ' + s1 + ')' + mp); + ok(d2.ge(d1), s2 + ' >= ' + s1 + mp); + ok(!d2.lt(d1), 'not (' + s2 + ' < ' + s1 + ')' + mp); + ok(d2.le(d1), s2 + ' <= ' + s1 + mp); + strictEqual(d2.cmp(d1), 0, s2 + ' cmp ' + s1 + mp); + + // 2 vs 3 + ok(!d2.eq(d3), 'not (' + s2 + ' == ' + s3 + ')' + mp); + ok(d2.ne(d3), s2 + ' != ' + s3 + mp); + ok(!d2.gt(d3), 'not (' + s2 + ' > ' + s3 + ')' + mp); + ok(!d2.ge(d3), 'not (' + s2 + ' >= ' + s3 + ')' + mp); + ok(d2.lt(d3), s2 + ' < ' + s3 + mp); + ok(d2.le(d3), s2 + ' <= ' + s3 + mp); + strictEqual(d2.cmp(d3), -1, s2 + ' cmp ' + s3 + mp); + + // 3 vs 1 + ok(!d3.eq(d1), 'not (' + s3 + ' == ' + s1 + ')' + mp); + ok(d3.ne(d1), s3 + ' != ' + s1 + mp); + ok(d3.gt(d1), s3 + ' > ' + s1 + mp); + ok(d3.ge(d1), s3 + ' >= ' + s1 + mp); + ok(!d3.lt(d1), 'not (' + s3 + ' < ' + s1 + ')' + mp); + ok(!d3.le(d1), 'not (' + s3 + ' <= ' + s1 + ')' + mp); + strictEqual(d3.cmp(d1), 1, s3 + ' cmp ' + s1 + mp); + + // 3 vs 2 + ok(!d3.eq(d2), 'not (' + s3 + ' == ' + s2 + ')' + mp); + ok(d3.ne(d2), s3 + ' != ' + s2 + mp); + ok(d3.gt(d2), s3 + ' > ' + s2 + mp); + ok(d3.ge(d2), s3 + ' >= ' + s2 + mp); + ok(!d3.lt(d2), 'not (' + s3 + ' < ' + s2 + ')' + mp); + ok(!d3.le(d2), 'not (' + s3 + ' <= ' + s2 + ')' + mp); + strictEqual(d3.cmp(d2), 1, s1 + ' cmp ' + s2 + mp); + } + + }); + + + test("Display timestamp value trucated to precision", function () { + var d = JIODate('2012-03-04T08:52:13.746Z'); + + // XXX No timezone + + strictEqual(d.toPrecisionString(jiodate.MSEC), '2012-03-04 09:52:13.746'); + strictEqual(d.toPrecisionString(jiodate.SEC), '2012-03-04 09:52:13'); + strictEqual(d.toPrecisionString(jiodate.MIN), '2012-03-04 09:52'); + strictEqual(d.toPrecisionString(jiodate.HOUR), '2012-03-04 09'); + strictEqual(d.toPrecisionString(jiodate.DAY), '2012-03-04'); + strictEqual(d.toPrecisionString(jiodate.MONTH), '2012-03'); + strictEqual(d.toPrecisionString(jiodate.YEAR), '2012'); + + throws( + function () { + d.toPrecisionString('something'); + }, + /Unsupported precision value 'something'/, + "Precision parameter must be a valid value" + ); + + d.setPrecision(jiodate.HOUR); + strictEqual(d.toPrecisionString(), '2012-03-04 09'); + }); + + + test("Parsing of invalid input", function () { + throws( + function () { + JIODate('foobar'); + }, + /Cannot parse: foobar/, + "Invalid strings raise exceptions" + ); + }); + + + test("Parsing of partial timestamp values with any precision", function () { + var d; + + d = JIODate('2012-05-02 06:07:08.989'); + strictEqual(d.getPrecision(), 'millisecond'); + strictEqual(d.toPrecisionString(), '2012-05-02 06:07:08.989'); + strictEqual(d.mom.toISOString(), '2012-05-02T04:07:08.989Z'); + + d = JIODate('2012-05-02 06:07:08'); + strictEqual(d.getPrecision(), 'second'); + strictEqual(d.toPrecisionString(), '2012-05-02 06:07:08'); + strictEqual(d.mom.toISOString(), '2012-05-02T04:07:08.000Z'); + + d = JIODate('2012-05-02 06:07'); + strictEqual(d.getPrecision(), 'minute'); + strictEqual(d.toPrecisionString(), '2012-05-02 06:07'); + strictEqual(d.mom.toISOString(), '2012-05-02T04:07:00.000Z'); + + d = JIODate('2012-05-02 06'); + strictEqual(d.getPrecision(), 'hour'); + strictEqual(d.toPrecisionString(), '2012-05-02 06'); + strictEqual(d.mom.toISOString(), '2012-05-02T04:00:00.000Z'); + + d = JIODate('2012-05-02'); + strictEqual(d.getPrecision(), 'day'); + strictEqual(d.toPrecisionString(), '2012-05-02'); + strictEqual(d.mom.toISOString(), '2012-05-01T22:00:00.000Z'); + + d = JIODate('2012-05'); + strictEqual(d.getPrecision(), 'month'); + strictEqual(d.toPrecisionString(), '2012-05'); + strictEqual(d.mom.toISOString(), '2012-05-01T00:00:00.000Z'); + + d = JIODate('2012'); + strictEqual(d.getPrecision(), 'year'); + strictEqual(d.toPrecisionString(), '2012'); + strictEqual(d.mom.toISOString(), '2012-01-01T00:00:00.000Z'); + + }); + + + test("Comparison between heterogeneous values is done with the lesser precision", function () { + var dmsec = JIODate('2012-05-02 06:07:08.989'), + dsec = JIODate('2012-05-02 06:07:08'), + dmin = JIODate('2012-05-02 06:07'), + dhour = JIODate('2012-05-02 06'), + dday = JIODate('2012-05-02'), + dmonth = JIODate('2012-05'), + dyear = JIODate('2012'); + + ok(dmsec.eq(dsec)); + ok(dmsec.eq(dmin)); + ok(dmsec.eq(dhour)); + ok(dmsec.eq(dday)); + ok(dmsec.eq(dmonth)); + ok(dmsec.eq(dyear)); + + ok(dsec.eq(dmsec)); + ok(dsec.eq(dmin)); + ok(dsec.eq(dhour)); + ok(dsec.eq(dday)); + ok(dsec.eq(dmonth)); + ok(dsec.eq(dyear)); + + ok(dmin.eq(dmsec)); + ok(dmin.eq(dsec)); + ok(dmin.eq(dhour)); + ok(dmin.eq(dday)); + ok(dmin.eq(dmonth)); + ok(dmin.eq(dyear)); + + ok(dhour.eq(dmsec)); + ok(dhour.eq(dsec)); + ok(dhour.eq(dmin)); + ok(dhour.eq(dday)); + ok(dhour.eq(dmonth)); + ok(dhour.eq(dyear)); + + ok(dday.eq(dmsec)); + ok(dday.eq(dsec)); + ok(dday.eq(dmin)); + ok(dday.eq(dhour)); + ok(dday.eq(dmonth)); + ok(dday.eq(dyear)); + + ok(dmonth.eq(dmsec)); + ok(dmonth.eq(dsec)); + ok(dmonth.eq(dmin)); + ok(dmonth.eq(dhour)); + ok(dmonth.eq(dday)); + ok(dmonth.eq(dyear)); + + ok(dyear.eq(dmsec)); + ok(dyear.eq(dsec)); + ok(dyear.eq(dmin)); + ok(dyear.eq(dhour)); + ok(dyear.eq(dday)); + ok(dyear.eq(dmonth)); + + ok(!dmsec.lt(JIODate('2012-05-02 06:07:08'))); + ok(dmsec.lt(JIODate('2012-05-02 06:07:09'))); + ok(dmsec.le(JIODate('2012-05-02 06:07:08'))); + ok(!dmsec.gt(JIODate('2012-05-02 06:07:08'))); + ok(dmsec.ge(JIODate('2012-05-02 06:07:08'))); + ok(!dmsec.ne(JIODate('2012-05-02 06:07:08'))); + ok(dmsec.eq(JIODate('2012-05-02 06:07:08'))); + strictEqual(dmsec.cmp(JIODate('2012-05-02 06:07:07')), +1); + strictEqual(dmsec.cmp(JIODate('2012-05-02 06:07:08')), 0); + strictEqual(dmsec.cmp(JIODate('2012-05-02 06:07:09')), -1); + + }); + + +})); + diff --git a/test/queries/key-typechecks.tests.js b/test/queries/key-typechecks.tests.js index cef22336dad50d7313a5d6b39624bb96881273cb..ea3eb9e566f33b3344ccc586feb41ed503499d37 100644 --- a/test/queries/key-typechecks.tests.js +++ b/test/queries/key-typechecks.tests.js @@ -15,7 +15,7 @@ }(['complex_queries', 'qunit'], function (complex_queries) { "use strict"; - module('Checks upon validity of key and key_schema objects'); + module('Key and key_schema objects validation'); test('Check the parameters passed to exec() and create()', function () { try { diff --git a/test/tests.html b/test/tests.html index c745dfc2dc637af71334ba575ccd2aa3a67a5ac0..577182ffc086152d4812a69909c4088445631d48 100644 --- a/test/tests.html +++ b/test/tests.html @@ -24,6 +24,10 @@ <script src="queries/tests.js"></script> <script src="queries/key-typechecks.tests.js"></script> + <script src="../lib/moment/moment-2.5.0.js"></script> + <script src="../src/jio.date/jiodate.js"></script> + <script src="queries/jiodate.tests.js"></script> + <script src="../src/jio.storage/localstorage.js"></script> <script src="queries/localstorage-keys.tests.js"></script> <script src="jio.storage/localstorage.tests.js"></script>