/* Minification failed. Returning unminified contents. (2786,42-43): run-time error JS1195: Expected expression: , (2789,69-70): run-time error JS1195: Expected expression: , */ //! moment.js //! version : 2.5.1 //! authors : Tim Wood, Iskren Chernev, Moment.js contributors //! license : MIT //! momentjs.com (function (undefined) { /************************************ Constants ************************************/ var moment, VERSION = "2.5.1", 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 = {}, // moment internal properties momentProperties = { _isAMomentObject: null, _i: null, _f: null, _l: null, _strict: null, _isUTC: null, _offset: null, // optional. Combine with _isUTC _pf: null, _lang: null // optional }, // 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 parseTokenSignedNumber = /[+-]?\d+/, // -inf - inf // 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{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/, isoFormat = 'YYYY-MM-DDTHH:mm:ssZ', isoDates = [ ['YYYYYY-MM-DD', /[+-]\d{6}-\d{2}-\d{2}/], ['YYYY-MM-DD', /\d{4}-\d{2}-\d{2}/], ['GGGG-[W]WW-E', /\d{4}-W\d{2}-\d/], ['GGGG-[W]WW', /\d{4}-W\d{2}/], ['YYYY-DDD', /\d{4}-\d{3}/] ], // 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 leftZeroFill(this.weekYear(), 4); }, ggggg: function () { return leftZeroFill(this.weekYear(), 5); }, GG: function () { return leftZeroFill(this.isoWeekYear() % 100, 2); }, GGGG: function () { return leftZeroFill(this.isoWeekYear(), 4); }, 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 defaultParsingFlags() { // We need to deep clone this object, and es5 standard is not very // helpful. return { empty: false, unusedTokens: [], unusedInput: [], overflow: -2, charsLeftOver: 0, nullInput: false, invalidMonth: null, invalidFormat: false, userInvalidated: false, iso: false }; } 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 cloneMoment(m) { var result = {}, i; for (i in m) { if (m.hasOwnProperty(i) && momentProperties.hasOwnProperty(i)) { result[i] = m[i]; } } return result; } 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 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 'Y': case 'G': case 'g': return parseTokenSignedNumber; 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': if (strict) { return parseTokenThreeDigits; } /* falls through */ case 'DDD': return 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 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); tempConfig._pf = defaultParsingFlags(); 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, l, string = config._i, match = isoRegex.exec(string); if (match) { config._pf.iso = true; for (i = 0, l = isoDates.length; i < l; i++) { if (isoDates[i][1].exec(string)) { // match[5] should be "T" or undefined config._f = isoDates[i][0] + (match[6] || " "); break; } } for (i = 0, l = isoTimes.length; i < l; 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) { var d = makeUTCDate(year, 0, 1).getUTCDay(), daysToAdd, dayOfYear; weekday = weekday != null ? weekday : firstDayOfWeek; daysToAdd = firstDayOfWeek - d + (d > firstDayOfWeekOfYear ? 7 : 0) - (d < firstDayOfWeek ? 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 (input === null) { return moment.invalid({ nullInput: true }); } if (typeof input === 'string') { config._i = input = getLangDefinition().preparse(input); } if (moment.isMoment(input)) { config = cloneMoment(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) { var c; if (typeof (lang) === "boolean") { strict = lang; lang = undefined; } // object construction must be done this way. // https://github.com/moment/moment/issues/1423 c = {}; c._isAMomentObject = true; c._i = input; c._f = format; c._l = lang; c._strict = strict; c._isUTC = false; c._pf = defaultParsingFlags(); return makeMoment(c); }; // creating with utc moment.utc = function (input, format, lang, strict) { var c; if (typeof (lang) === "boolean") { strict = lang; lang = undefined; } // object construction must be done this way. // https://github.com/moment/moment/issues/1423 c = {}; c._isAMomentObject = true; c._useUTC = true; c._isUTC = true; c._l = lang; c._i = input; c._f = format; c._strict = strict; c._pf = defaultParsingFlags(); return makeMoment(c).utc(); }; // 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 || (obj != null && obj.hasOwnProperty('_isAMomentObject')); }; // 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); ; var V12 = V12 ? V12 : {}; (function (parent) { var settings = { retailerId: 5557, retailerGuid: "811d05e2-24c4-44cb-acbe-eb0683b2a43c", applicationUrl: "https://apply.v12finance.com/javascriptgateway/retailer-scripts/5557/811d05e2-24c4-44cb-acbe-eb0683b2a43c/submitusingformpost", version: "0.5.0" }; var financeProducts = [ { "productId": 13, "productGuid": "47879A99-7DBF-483B-B097-F859892F823A", "name": "Buy Now Pay Later", "minLoan": 250.0000, "maxLoan": 3000.0000, "months": 36, "apr": 19.9, "serviceFee": 0.0, "documentFee": 0.0000, "documentFeeCollectionMonth": 0, "documentFeeMaximum": 0, "documentFeeMinimum": 0, "documentFeePercentage": 0.0, "optionPeriod": 0, "deferredPeriod": 6, "tag": "BNPL6/36", "altTag": "ONIB36-19.9", "settlementFee": 35.00 }, { "productId": -1, "productGuid": "47879A99-7DBF-483B-B097-F859892F823A", "name": "Buy Now Pay Later", "minLoan": 250.0000, "maxLoan": 3000.0000, "months": 1, "apr": 0, "serviceFee": 0.0, "documentFee": 0.0000, "documentFeeCollectionMonth": 0, "documentFeeMaximum": 0, "documentFeeMinimum": 0, "documentFeePercentage": 0.0, "optionPeriod": 0, "deferredPeriod": 6, "tag": "BNPL6/6", "altTag": "ONIB36-19.9", "settlementFee": 35.00 }, { "productId": 23, "productGuid": "af782dbe-65e8-4562-84fa-247f6cc26c5e", "name": "Long Term Finance", "minLoan": 400.0000, "maxLoan": 15000.0000, "months": 24, "apr": 14.9, "serviceFee": 0.0, "documentFee": 0.0000, "documentFeeCollectionMonth": 0, "documentFeeMaximum": 0, "documentFeeMinimum": 0, "documentFeePercentage": 0.0, "optionPeriod": 0, "deferredPeriod": 0, "tag": "CC24-14.9", "altTag": "ONIB24-14.9", "settlementFee": 0.00 }, { "productId": 24, "productGuid": "59d90cc2-e567-47ea-9f3f-4cecbf253a01", "name": "Long Term Finance", "minLoan": 400.0000, "maxLoan": 15000.0000, "months": 36, "apr": 14.9, "serviceFee": 0.0, "documentFee": 0.0000, "documentFeeCollectionMonth": 0, "documentFeeMaximum": 0, "documentFeeMinimum": 0, "documentFeePercentage": 0.0, "optionPeriod": 0, "deferredPeriod": 0, "tag": "CC36-14.9", "altTag": "ONIB36-14.9", "settlementFee": 0.00 }, { "productId": 88, "productGuid": "34ee414c-94d8-4cd2-8f62-fc5b8a2d2a7d", "name": "10 Month IFC", "minLoan": 499.0000, "maxLoan": 15000.0000, "months": 10, "apr": 0.0, "serviceFee": 0.0, "documentFee": 0.0000, "documentFeeCollectionMonth": 0, "documentFeeMaximum": 0, "documentFeeMinimum": 0, "documentFeePercentage": 0.0, "optionPeriod": 0, "deferredPeriod": 0, "tag": "IFC-10", "altTag": "ONIF10", "settlementFee": 0.00 }, { "productId": 259, "productGuid": "018438ca-4dd4-46d7-8fba-6b5f55d95174", "name": "Take 5", "minLoan": 249.0000, "maxLoan": 1500.0000, "months": 5, "apr": 0.0, "serviceFee": 0.0, "documentFee": 0.0000, "documentFeeCollectionMonth": 0, "documentFeeMaximum": 0, "documentFeeMinimum": 15, "documentFeePercentage": 0.05, "optionPeriod": 0, "deferredPeriod": 0, "tag": "Take5", "altTag": "ONIF5", "settlementFee": 0.00 }, { "productId": -2, "productGuid": "34ee414c-94d8-4cd2-8f62-fc5b8a2d2a7d", "name": "5 Month IFC", "minLoan": 419.0000, "maxLoan": 3000.0000, "months": 5, "apr": 0.0, "serviceFee": 0.0, "documentFee": 0.0000, "documentFeeCollectionMonth": 0, "documentFeeMaximum": 0, "documentFeeMinimum": 0, "documentFeePercentage": 0.0, "optionPeriod": 0, "deferredPeriod": 0, "tag": "IFC-5", "altTag": "ONIF5", "settlementFee": 0.00 } ]; parent.getFinanceProduct = function (id) { for (var i = 0; i < financeProducts.length; i++) { if (financeProducts[i].productId == id || financeProducts[i].tag == id || financeProducts[i].altTag == id) { return financeProducts[i]; } } return null; } parent.calculateApr = function (loan, instalment, deferred, term) { var result = parseFloat(0); var high = parseFloat(200); var low = parseFloat(0); var n, x, j, q, r, y, z if (deferred > 1) { n = (term + deferred + 1); } else { n = (term + 1); } x = 1; while (x < 20) { result = (high + low) / 2; j = parseFloat(Math.pow((1.0000 + result / 100.0000), (1.0000 / 12.0000))); q = parseFloat((1.0000 / j)); if (deferred < 1) { y = parseFloat((instalment * (1.0000 - Math.pow(q, n))) / (1 - q) - instalment); z = parseFloat(0.00); } else { y = parseFloat((instalment * (1.0000 - Math.pow(q, n - 1))) / (1 - q) - instalment); z = parseFloat((instalment * (1.0000 - Math.pow(q, deferred))) / (1 - q) - instalment); } if ((y - z) < loan) { high = result; } else { low = result; } x++; } return result; } parent.sumCashFlows = function (months, cashflows) { var total = parseFloat(0.00); for (var i = 1; i < months; i++) { total = parseFloat(total + parseFloat(cashflows[i - 1].cashFlows)); } return total; } parent.earliestDate = function (cashflows, months) { var earliest = cashflows[0].dataDate; for (var i = 1; i < months; i++) { if (moment(cashflows[i].dataDate).isBefore(earliest)) { earliest = cashflows[i].dataDate; } } return earliest; } parent.presentValue = function (cashflows, irr, loanTerm, checkdate, numdays) { var presValue = parseFloat(0.0); for (var i = 0; i < loanTerm; i++) { var cf = parseFloat(cashflows[i].cashFlows); var diff = parseFloat(moment(checkdate).diff(cashflows[i].dataDate, 'days')); presValue += parseFloat(cf / Math.pow(1 + irr, diff) / numdays); } return presValue; } parent.XIRR = function (values, dates, guess) { // Credits: algorithm inspired by Apache OpenOffice // Calculates the resulting amount var irrResult = function (values, dates, rate) { var r = rate + 1; var result = values[0]; for (var i = 1; i < values.length; i++) { result += values[i] / Math.pow(r, moment(dates[i]).diff(moment(dates[0]), 'days') / 365); } return result; } // Calculates the first derivation var irrResultDeriv = function (values, dates, rate) { var r = rate + 1; var result = 0; for (var i = 1; i < values.length; i++) { var frac = moment(dates[i]).diff(moment(dates[0]), 'days') / 365; result -= frac * values[i] / Math.pow(r, frac + 1); } return result; } // Check that values contains at least one positive value and one negative value var positive = false; var negative = false; for (var i = 0; i < values.length; i++) { if (values[i] > 0) positive = true; if (values[i] < 0) negative = true; } // Return error if values does not contain at least one positive value and one negative value if (!positive || !negative) return '#NUM!'; // Initialize guess and resultRate var guess = (typeof guess === 'undefined') ? 0.1 : guess; var resultRate = guess; // Set maximum epsilon for end of iteration var epsMax = 1e-10; // Set maximum number of iterations var iterMax = 50; // Implement Newton's method var newRate, epsRate, resultValue; var iteration = 0; var contLoop = true; do { resultValue = irrResult(values, dates, resultRate); newRate = resultRate - resultValue / irrResultDeriv(values, dates, resultRate); epsRate = Math.abs(newRate - resultRate); resultRate = newRate; contLoop = (epsRate > epsMax) && (Math.abs(resultValue) > epsMax); } while (contLoop && (++iteration < iterMax)); if (contLoop) return '#NUM!'; // Return internal rate of return return resultRate; } parent.calculateAprFromIrr = function (loan, monthlyinstalment, loanTerm, documentfee, documentfeecollectionmonth) { var startDate = new Date(); var incomeTable = []; var dateTable = []; var checkDate; var incomeObject = { cashFlows: 0, dataDate: 0 }; var irr, irrPrev, presentValuePrev, pv; if (documentfeecollectionmonth == 0) { incomeTable.push(parseFloat(loan * -1) + documentfee); } else { incomeTable.push(parseFloat(loan * -1)); } dateTable.push(startDate); for (var i = 1; i <= loanTerm; i++) { var nextDate = moment(startDate).add('M', i); dateTable.push(nextDate); if ((i - 1) == documentfeecollectionmonth && documentfeecollectionmonth > 0) { incomeTable.push(parseFloat(monthlyinstalment + documentfee)); } else { incomeTable.push(parseFloat(monthlyinstalment)); } } var r = parent.XIRR(incomeTable, dateTable, 0.1); return Math.round(r * 10000) / 100; } parent.calculateFromProductCode = function (productCode, cashPrice, deposit) { return parent.calculate(parent.getFinanceProduct(productCode), cashPrice, deposit); } //Calculates all financial parameters parent.calculate = function (financeProduct, cashPrice, deposit) { var apr = parseFloat(financeProduct.apr); var calculatedApr; var months = parseFloat(financeProduct.months); var serviceFee = parseFloat(financeProduct.serviceFee); var balancePayable = parseFloat(0.00); var documentFee = 0; cashPrice = parseFloat(cashPrice); deposit = parseFloat(deposit); var loanAmount = cashPrice - deposit; var initialPayments, finalPayment, balancePayable; documentFee = financeProduct.documentFee + (loanAmount * financeProduct.documentFeePercentage); if (financeProduct.documentFeeMinimum > 0 && documentFee < financeProduct.documentFeeMinimum) { documentFee = financeProduct.documentFeeMinimum } if (financeProduct.documentFeeMaximum > 0 && documentFee > financeProduct.documentFeeMaximum) { documentFee = financeProduct.documentFeeMaximum } if (apr == 0) { initialPayments = Math.round((loanAmount / months) * 100) / 100; if (initialPayments * months < loanAmount) { initialPayments += 0.01; } finalPayment = (loanAmount - (initialPayments * (months - 1))); balancePayable = loanAmount; calculatedApr = 0; if (documentFee > 0) { calculatedApr = parent.calculateAprFromIrr(loanAmount, initialPayments, months, parseFloat(documentFee), parseFloat(financeProduct.documentFeeCollectionMonth)); } } else { var yield = Math.pow(((apr) / 100) + 1, (1.00 / 12)); var pv = loanAmount - serviceFee; if (financeProduct.deferredPeriod > 1) { pv = (pv * Math.pow(yield, (financeProduct.deferredPeriod - 1))); } initialPayments = Math.floor(((0 - pv / ((Math.pow(yield, 0 - months) - 1) / (yield - 1)))) * 100) / 100; finalPayment = initialPayments; balancePayable = (initialPayments * months); calculatedApr = parent.calculateApr((loanAmount - financeProduct.serviceFee), initialPayments, financeProduct.deferredPeriod, months); if (documentFee > 0) { calculatedApr = parent.calculateAprFromIrr(loanAmount, initialPayments, months, parseFloat(documentFee), parseFloat(financeProduct.documentFeeCollectionMonth)); } } //var x = parent.calculateAprFromIrr(loanAmount, initialPayments, months, parseFloat(financeProduct.documentFee), parseFloat(financeProduct.documentFeeCollectionMonth)); balancePayable = initialPayments * (months - 1); balancePayable += finalPayment; var interest = (balancePayable - loanAmount); var chargeForCredit = (interest + serviceFee + documentFee); var amountPayable = (loanAmount + chargeForCredit); var productAvailable = true; var availabilityReason = ""; if (loanAmount < financeProduct.minLoan) { productAvailable = false; availabilityReason = "Only available on loan amounts over £" + financeProduct.minLoan.toFixed(2); } else if (loanAmount > financeProduct.maxLoan) { productAvailable = false; availabilityReason = "Only available on loan amounts under £" + financeProduct.maxLoan.toFixed(2); } var financeCalculation = { initialPayments: initialPayments.toFixed(2), finalPayment: finalPayment.toFixed(2), balancePayable: balancePayable.toFixed(2), interest: interest.toFixed(2), chargeForCredit: chargeForCredit.toFixed(2), amountPayable: amountPayable.toFixed(2), cashPrice: cashPrice.toFixed(2), deposit: deposit.toFixed(2), loanAmount: loanAmount.toFixed(2), months: months, monthsDeferred: financeProduct.deferredPeriod, apr: calculatedApr.toFixed(2), productAvailable: productAvailable, availabilityReason: availabilityReason, productId: financeProduct.productId, productGuid: financeProduct.productGuid, name: financeProduct.name, settlementFee: financeProduct.settlementFee.toFixed(2), serviceFee: serviceFee.toFixed(2), documentFee: documentFee.toFixed(2), documentFeeMinimum: financeProduct.documentFeeMinimum, documentFeeMaximum: financeProduct.documentFeeMaximum, documentFeeCollectionMonth: financeProduct.documentFeeCollectionMonth, documentFeePercentage: financeProduct.documentFeePercentage }; return financeCalculation; }; })(V12); ; (function (window, $, V12) { //************************************ //#region Init //************************************ var products = new Array(); //products.push({ Id: 'take5', V12id: 259, family: 'take5', minRecommended: 249, maxRecommended: 399.99 }); //take5 products.push({ Id: 'take5', V12id: -2, family: 'take5', minRecommended: 419, maxRecommended: 899.99 }); //take5 products.push({ Id: 'take66', V12id: -1, family: 'take6', minRecommended: 400, maxRecommended: 449.99 });//Buy Now Pay Later products.push({ Id: 'take636', V12id: 13, family: 'take6', minRecommended: 400, maxRecommended: 449.99 });//Buy Now Pay Later products.push({ Id: 'take10', V12id: 88, family: 'take10', minRecommended: 450, maxRecommended: 599.99 });//10 Month IFC products.push({ Id: 'takelonger36', V12id: 24, family: 'takelonger', minRecommended: 600, maxRecommended: '' });//Long Term Finance 36 products.push({ Id: 'takelonger24', V12id: 23, family: 'takelonger', minRecommended: 600, maxRecommended: '' });//Long Term Finance 24 //#endregion //************************************ //#region DocumentLoad //************************************ $(function () { var form = $('#finance-calculator'); var amountElement = $('input[name=amount]', form); var table = $('#finace-calculation'); //Hook up the submit button form.submit(function () { return handleSubmit(amountElement, table, form); }); var queryAmount = parseFloat(querystring('amount')); if (!isNaN(queryAmount)) { amountElement.val(queryAmount); handleSubmit(amountElement, table, form); } }); //#endregion //************************************ //#region Public Methods //************************************ //#endregion //************************************ //#region Private Methods //************************************ function handleSubmit(amountElement, table, form) { var amount = amountElement.val(); if (!amount || !amount.length) { alert('Please enter the amount you would like to finance'); return false; } var amountValue = parseFloat(amount); if (isNaN(amountValue)) { alert('Please enter a number'); return false; } //update the product values updateFinanceCalculations(amountValue, table, form); //prevent post return false; } //update the actual values displayed etc function updateFinanceCalculations(amount, table, form) { var updateProducts = refreshProductCalculations(amount); if (!updateProducts) { return false; } //loop through all the products, applying the changes as necessary (if we have any) for (var i = 0; i < products.length; i++) { var product = products[i]; var finance = product.calculatedValues; $('[data-monthlycost="' + product.Id + '"]').html('£' + formatValue(finance.initialPayments)); $('[data-period="' + product.Id + '"]').html(finance.months + ' months'); $('[data-totalcost="' + product.Id + '"]').html('£' + formatValue(finance.amountPayable)); $('[data-apr="' + product.Id + '"]').html(finance.apr + '%'); if (finance.productAvailable) { $('p[data-notavailablereason="' + product.family + '"]').hide(); $('[data-hideifnotavailable="' + product.family + '"]').show(); } else { $('[data-hideifnotavailable="' + product.family + '"]').hide(); $('p[data-notavailablereason="' + product.family + '"]').html(finance.availabilityReason); $('p[data-notavailablereason="' + product.family + '"]').show(); } if (isRecommended(product,amount)) { $('[data-isrecommended="' + product.Id + '"]').addClass('recommended'); } else { $('[data-isrecommended="' + product.Id + '"]').removeClass('recommended'); } } if (table.is(":visible")) { $('html, body').animate({ scrollTop: form.offset().top - headerHeight }, 1000); } else { table.slideDown(600, function () { $('html, body').animate({ scrollTop: form.offset().top - headerHeight }, 1000); }); } return true; } function isRecommended(product, amount) { //if (isNaN(product.minRecommended) || amount >= product.minRecommended) { // return isNaN(product.maxRecommended) || amount <= product.maxRecommended; //} return false; } function formatValue(num) { var parsedValue = parseFloat(num); if (parsedValue % 1 != 0) { return num; } return parsedValue; } //update the products using the provided financial value function refreshProductCalculations(amount) { if (isNaN(amount)) { return false; } //have a value so calculate all products for (var i = 0; i < products.length; i++) { var product = products[i]; product.calculatedValues = V12.calculateFromProductCode(product.V12id, amount, 0); } return true; } //utility function to get an array of values from the querystring function querystring(key) { var re = new RegExp('(?:\\?|&)' + key + '=(.*?)(?=&|$)', 'gi'); var r = [], m; while ((m = re.exec(document.location.search)) != null) r.push(m[1]); return r; } //#endregion })(window, jQuery, V12); ;