MediaWiki:Gadget-Countdown.js

/*global window */ /** * @license countdown.js v2.6.0 http://countdownjs.org * Copyright (c)2006-2014 Stephen M. McKamey. * Licensed under The MIT License. */ /*jshint bitwise:false */

/** * @public * @type {Object|null} */ var module;

/** * API entry * @public * @param {function(Object)|Date|number} start the starting date * @param {function(Object)|Date|number} end the ending date * @param {number} units the units to populate * @return {Object|number} */

var countdown = (

/** * @param {Object} module CommonJS Module */ function(module) { /*jshint smarttabs:true */

'use strict';

/**	 * @private * @const * @type {number} */	var MILLISECONDS	= 0x001;

/**	 * @private * @const * @type {number} */	var SECONDS			= 0x002;

/**	 * @private * @const * @type {number} */	var MINUTES			= 0x004;

/**	 * @private * @const * @type {number} */	var HOURS			= 0x008;

/**	 * @private * @const * @type {number} */	var DAYS			= 0x010;

/**	 * @private * @const * @type {number} */	var WEEKS			= 0x020;

/**	 * @private * @const * @type {number} */	var MONTHS			= 0x040;

/**	 * @private * @const * @type {number} */	var YEARS			= 0x080;

/**	 * @private * @const * @type {number} */	var DECADES			= 0x100;

/**	 * @private * @const * @type {number} */	var CENTURIES		= 0x200;

/**	 * @private * @const * @type {number} */	var MILLENNIA		= 0x400;

/**	 * @private * @const * @type {number} */	var DEFAULTS		= YEARS|MONTHS|DAYS|HOURS|MINUTES|SECONDS;

/**	 * @private * @const * @type {number} */	var MILLISECONDS_PER_SECOND = 1000;

/**	 * @private * @const * @type {number} */	var SECONDS_PER_MINUTE = 60;

/**	 * @private * @const * @type {number} */	var MINUTES_PER_HOUR = 60;

/**	 * @private * @const * @type {number} */	var HOURS_PER_DAY = 24;

/**	 * @private * @const * @type {number} */	var MILLISECONDS_PER_DAY = HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE * MILLISECONDS_PER_SECOND;

/**	 * @private * @const * @type {number} */	var DAYS_PER_WEEK = 7;

/**	 * @private * @const * @type {number} */	var MONTHS_PER_YEAR = 12;

/**	 * @private * @const * @type {number} */	var YEARS_PER_DECADE = 10;

/**	 * @private * @const * @type {number} */	var DECADES_PER_CENTURY = 10;

/**	 * @private * @const * @type {number} */	var CENTURIES_PER_MILLENNIUM = 10;

/**	 * @private * @param {number} x number * @return {number} */	var ceil = Math.ceil;

/**	 * @private * @param {number} x number * @return {number} */	var floor = Math.floor;

/**	 * @private * @param {Date} ref reference date * @param {number} shift number of months to shift * @return {number} number of days shifted */	function borrowMonths(ref, shift) { var prevTime = ref.getTime;

// increment month by shift ref.setMonth( ref.getMonth + shift );

// this is the trickiest since months vary in length return Math.round( (ref.getTime - prevTime) / MILLISECONDS_PER_DAY ); }

/**	 * @private * @param {Date} ref reference date * @return {number} number of days */	function daysPerMonth(ref) { var a = ref.getTime;

// increment month by 1 var b = new Date(a); b.setMonth( ref.getMonth + 1 );

// this is the trickiest since months vary in length return Math.round( (b.getTime - a) / MILLISECONDS_PER_DAY ); }

/**	 * @private * @param {Date} ref reference date * @return {number} number of days */	function daysPerYear(ref) { var a = ref.getTime;

// increment year by 1 var b = new Date(a); b.setFullYear( ref.getFullYear + 1 );

// this is the trickiest since years (periodically) vary in length return Math.round( (b.getTime - a) / MILLISECONDS_PER_DAY ); }

/**	 * Applies the Timespan to the given date. * 	 * @private * @param {Timespan} ts	 * @param {Date=} date * @return {Date} */	function addToDate(ts, date) { date = (date instanceof Date) || ((date !== null) && isFinite(date)) ? new Date(+date) : new Date; if (!ts) { return date; }

// if there is a value field, use it directly var value = +ts.value || 0; if (value) { date.setTime(date.getTime + value); return date; }

value = +ts.milliseconds || 0; if (value) { date.setMilliseconds(date.getMilliseconds + value); }

value = +ts.seconds || 0; if (value) { date.setSeconds(date.getSeconds + value); }

value = +ts.minutes || 0; if (value) { date.setMinutes(date.getMinutes + value); }

value = +ts.hours || 0; if (value) { date.setHours(date.getHours + value); }

value = +ts.weeks || 0; if (value) { value *= DAYS_PER_WEEK; }

value += +ts.days || 0; if (value) { date.setDate(date.getDate + value); }

value = +ts.months || 0; if (value) { date.setMonth(date.getMonth + value); }

value = +ts.millennia || 0; if (value) { value *= CENTURIES_PER_MILLENNIUM; }

value += +ts.centuries || 0; if (value) { value *= DECADES_PER_CENTURY; }

value += +ts.decades || 0; if (value) { value *= YEARS_PER_DECADE; }

value += +ts.years || 0; if (value) { date.setFullYear(date.getFullYear + value); }

return date; }

/**	 * @private * @const * @type {number} */	var LABEL_MILLISECONDS	= 0;

/**	 * @private * @const * @type {number} */	var LABEL_SECONDS		= 1;

/**	 * @private * @const * @type {number} */	var LABEL_MINUTES		= 2;

/**	 * @private * @const * @type {number} */	var LABEL_HOURS			= 3;

/**	 * @private * @const * @type {number} */	var LABEL_DAYS			= 4;

/**	 * @private * @const * @type {number} */	var LABEL_WEEKS			= 5;

/**	 * @private * @const * @type {number} */	var LABEL_MONTHS		= 6;

/**	 * @private * @const * @type {number} */	var LABEL_YEARS			= 7;

/**	 * @private * @const * @type {number} */	var LABEL_DECADES		= 8;

/**	 * @private * @const * @type {number} */	var LABEL_CENTURIES		= 9;

/**	 * @private * @const * @type {number} */	var LABEL_MILLENNIA		= 10;

/**	 * @private * @type {Array} */	var LABELS_SINGLUAR;

/**	 * @private * @type {Array} */	var LABELS_PLURAL;

/**	 * @private * @type {string} */	var LABEL_LAST;

/**	 * @private * @type {string} */	var LABEL_DELIM;

/**	 * @private * @type {string} */	var LABEL_NOW;

/**	 * Formats a number & unit as a string * 	 * @param {number} value * @param {number} unit * @return {string} */	var formatter;

/**	 * Formats a number as a string * 	 * @private * @param {number} value * @return {string} */	var formatNumber;

/**	 * @private * @param {number} value * @param {number} unit unit index into label list * @return {string} */	function plurality(value, unit) { return formatNumber(value)+((value === 1) ? LABELS_SINGLUAR[unit] : LABELS_PLURAL[unit]); }

/**	 * Formats the entries with singular or plural labels * 	 * @private * @param {Timespan} ts	 * @return {Array} */	var formatList;

/**	 * Timespan representation of a duration of time * 	 * @private * @this {Timespan} * @constructor */	function Timespan {}

/**	 * Formats the Timespan as a sentence * 	 * @param {string=} emptyLabel the string to use when no values returned * @return {string} */	Timespan.prototype.toString = function(emptyLabel) { var label = formatList(this);

var count = label.length; if (!count) { return emptyLabel ? ''+emptyLabel : LABEL_NOW; }		if (count === 1) { return label[0]; }

var last = LABEL_LAST+label.pop; return label.join(LABEL_DELIM)+last; };

/**	 * Formats the Timespan as a sentence in HTML * 	 * @param {string=} tag HTML tag name to wrap each value * @param {string=} emptyLabel the string to use when no values returned * @return {string} */	Timespan.prototype.toHTML = function(tag, emptyLabel) { tag = tag || 'span'; var label = formatList(this);

var count = label.length; if (!count) { emptyLabel = emptyLabel || LABEL_NOW; return emptyLabel ? ''+emptyLabel+'' : emptyLabel; }		for (var i=0; i'+label[i]+''; }		if (count === 1) { return label[0]; }

var last = LABEL_LAST+label.pop; return label.join(LABEL_DELIM)+last; };

/**	 * Applies the Timespan to the given date * 	 * @param {Date=} date the date to which the timespan is added. * @return {Date} */	Timespan.prototype.addTo = function(date) { return addToDate(this, date); };

/**	 * Formats the entries as English labels * 	 * @private * @param {Timespan} ts	 * @return {Array} */	formatList = function(ts) { var list = [];

var value = ts.millennia; if (value) { list.push(formatter(value, LABEL_MILLENNIA)); }

value = ts.centuries; if (value) { list.push(formatter(value, LABEL_CENTURIES)); }

value = ts.decades; if (value) { list.push(formatter(value, LABEL_DECADES)); }

value = ts.years; if (value) { list.push(formatter(value, LABEL_YEARS)); }

value = ts.months; if (value) { list.push(formatter(value, LABEL_MONTHS)); }

value = ts.weeks; if (value) { list.push(formatter(value, LABEL_WEEKS)); }

value = ts.days; if (value) { list.push(formatter(value, LABEL_DAYS)); }

value = ts.hours; if (value) { list.push(formatter(value, LABEL_HOURS)); }

value = ts.minutes; if (value) { list.push(formatter(value, LABEL_MINUTES)); }

value = ts.seconds; if (value) { list.push(formatter(value, LABEL_SECONDS)); }

value = ts.milliseconds; if (value) { list.push(formatter(value, LABEL_MILLISECONDS)); }

return list; };

/**	 * Borrow any underflow units, carry any overflow units * 	 * @private * @param {Timespan} ts	 * @param {string} toUnit */	function rippleRounded(ts, toUnit) { switch (toUnit) { case 'seconds': if (ts.seconds !== SECONDS_PER_MINUTE || isNaN(ts.minutes)) { return; }				// ripple seconds up to minutes ts.minutes++; ts.seconds = 0;

/* falls through */ case 'minutes': if (ts.minutes !== MINUTES_PER_HOUR || isNaN(ts.hours)) { return; }				// ripple minutes up to hours ts.hours++; ts.minutes = 0;

/* falls through */ case 'hours': if (ts.hours !== HOURS_PER_DAY || isNaN(ts.days)) { return; }				// ripple hours up to days ts.days++; ts.hours = 0;

/* falls through */ case 'days': if (ts.days !== DAYS_PER_WEEK || isNaN(ts.weeks)) { return; }				// ripple days up to weeks ts.weeks++; ts.days = 0;

/* falls through */ case 'weeks': if (ts.weeks !== daysPerMonth(ts.refMonth)/DAYS_PER_WEEK || isNaN(ts.months)) { return; }				// ripple weeks up to months ts.months++; ts.weeks = 0;

/* falls through */ case 'months': if (ts.months !== MONTHS_PER_YEAR || isNaN(ts.years)) { return; }				// ripple months up to years ts.years++; ts.months = 0;

/* falls through */ case 'years': if (ts.years !== YEARS_PER_DECADE || isNaN(ts.decades)) { return; }				// ripple years up to decades ts.decades++; ts.years = 0;

/* falls through */ case 'decades': if (ts.decades !== DECADES_PER_CENTURY || isNaN(ts.centuries)) { return; }				// ripple decades up to centuries ts.centuries++; ts.decades = 0;

/* falls through */ case 'centuries': if (ts.centuries !== CENTURIES_PER_MILLENNIUM || isNaN(ts.millennia)) { return; }				// ripple centuries up to millennia ts.millennia++; ts.centuries = 0; /* falls through */ }	}

/**	 * Ripple up partial units one place * 	 * @private * @param {Timespan} ts timespan * @param {number} frac accumulated fractional value * @param {string} fromUnit source unit name * @param {string} toUnit target unit name * @param {number} conversion multiplier between units * @param {number} digits max number of decimal digits to output * @return {number} new fractional value */	function fraction(ts, frac, fromUnit, toUnit, conversion, digits) { if (ts[fromUnit] >= 0) { frac += ts[fromUnit]; delete ts[fromUnit]; }

frac /= conversion; if (frac + 1 <= 1) { // drop if below machine epsilon return 0; }

if (ts[toUnit] >= 0) { // ensure does not have more than specified number of digits ts[toUnit] = +(ts[toUnit] + frac).toFixed(digits); rippleRounded(ts, toUnit); return 0; }

return frac; }

/**	 * Ripple up partial units to next existing * 	 * @private * @param {Timespan} ts	 * @param {number} digits max number of decimal digits to output */	function fractional(ts, digits) { var frac = fraction(ts, 0, 'milliseconds', 'seconds', MILLISECONDS_PER_SECOND, digits); if (!frac) { return; }

frac = fraction(ts, frac, 'seconds', 'minutes', SECONDS_PER_MINUTE, digits); if (!frac) { return; }

frac = fraction(ts, frac, 'minutes', 'hours', MINUTES_PER_HOUR, digits); if (!frac) { return; }

frac = fraction(ts, frac, 'hours', 'days', HOURS_PER_DAY, digits); if (!frac) { return; }

frac = fraction(ts, frac, 'days', 'weeks', DAYS_PER_WEEK, digits); if (!frac) { return; }

frac = fraction(ts, frac, 'weeks', 'months', daysPerMonth(ts.refMonth)/DAYS_PER_WEEK, digits); if (!frac) { return; }

frac = fraction(ts, frac, 'months', 'years', daysPerYear(ts.refMonth)/daysPerMonth(ts.refMonth), digits); if (!frac) { return; }

frac = fraction(ts, frac, 'years', 'decades', YEARS_PER_DECADE, digits); if (!frac) { return; }

frac = fraction(ts, frac, 'decades', 'centuries', DECADES_PER_CENTURY, digits); if (!frac) { return; }

frac = fraction(ts, frac, 'centuries', 'millennia', CENTURIES_PER_MILLENNIUM, digits);

// should never reach this with remaining fractional value if (frac) { throw new Error('Fractional unit overflow'); } }

/**	 * Borrow any underflow units, carry any overflow units * 	 * @private * @param {Timespan} ts	 */ function ripple(ts) { var x;

if (ts.milliseconds < 0) { // ripple seconds down to milliseconds x = ceil(-ts.milliseconds / MILLISECONDS_PER_SECOND); ts.seconds -= x;			ts.milliseconds += x * MILLISECONDS_PER_SECOND;

} else if (ts.milliseconds >= MILLISECONDS_PER_SECOND) { // ripple milliseconds up to seconds ts.seconds += floor(ts.milliseconds / MILLISECONDS_PER_SECOND); ts.milliseconds %= MILLISECONDS_PER_SECOND; }

if (ts.seconds < 0) { // ripple minutes down to seconds x = ceil(-ts.seconds / SECONDS_PER_MINUTE); ts.minutes -= x;			ts.seconds += x * SECONDS_PER_MINUTE;

} else if (ts.seconds >= SECONDS_PER_MINUTE) { // ripple seconds up to minutes ts.minutes += floor(ts.seconds / SECONDS_PER_MINUTE); ts.seconds %= SECONDS_PER_MINUTE; }

if (ts.minutes < 0) { // ripple hours down to minutes x = ceil(-ts.minutes / MINUTES_PER_HOUR); ts.hours -= x;			ts.minutes += x * MINUTES_PER_HOUR;

} else if (ts.minutes >= MINUTES_PER_HOUR) { // ripple minutes up to hours ts.hours += floor(ts.minutes / MINUTES_PER_HOUR); ts.minutes %= MINUTES_PER_HOUR; }

if (ts.hours < 0) { // ripple days down to hours x = ceil(-ts.hours / HOURS_PER_DAY); ts.days -= x;			ts.hours += x * HOURS_PER_DAY;

} else if (ts.hours >= HOURS_PER_DAY) { // ripple hours up to days ts.days += floor(ts.hours / HOURS_PER_DAY); ts.hours %= HOURS_PER_DAY; }

while (ts.days < 0) { // NOTE: never actually seen this loop more than once

// ripple months down to days ts.months--; ts.days += borrowMonths(ts.refMonth, 1); }

// weeks is always zero here

if (ts.days >= DAYS_PER_WEEK) { // ripple days up to weeks ts.weeks += floor(ts.days / DAYS_PER_WEEK); ts.days %= DAYS_PER_WEEK; }

if (ts.months < 0) { // ripple years down to months x = ceil(-ts.months / MONTHS_PER_YEAR); ts.years -= x;			ts.months += x * MONTHS_PER_YEAR;

} else if (ts.months >= MONTHS_PER_YEAR) { // ripple months up to years ts.years += floor(ts.months / MONTHS_PER_YEAR); ts.months %= MONTHS_PER_YEAR; }

// years is always non-negative here // decades, centuries and millennia are always zero here

if (ts.years >= YEARS_PER_DECADE) { // ripple years up to decades ts.decades += floor(ts.years / YEARS_PER_DECADE); ts.years %= YEARS_PER_DECADE;

if (ts.decades >= DECADES_PER_CENTURY) { // ripple decades up to centuries ts.centuries += floor(ts.decades / DECADES_PER_CENTURY); ts.decades %= DECADES_PER_CENTURY;

if (ts.centuries >= CENTURIES_PER_MILLENNIUM) { // ripple centuries up to millennia ts.millennia += floor(ts.centuries / CENTURIES_PER_MILLENNIUM); ts.centuries %= CENTURIES_PER_MILLENNIUM; }			}		}	}

/**	 * Remove any units not requested * 	 * @private * @param {Timespan} ts	 * @param {number} units the units to populate * @param {number} max number of labels to output * @param {number} digits max number of decimal digits to output */	function pruneUnits(ts, units, max, digits) { var count = 0;

// Calc from largest unit to smallest to prevent underflow if (!(units & MILLENNIA) || (count >= max)) { // ripple millennia down to centuries ts.centuries += ts.millennia * CENTURIES_PER_MILLENNIUM; delete ts.millennia;

} else if (ts.millennia) { count++; }

if (!(units & CENTURIES) || (count >= max)) { // ripple centuries down to decades ts.decades += ts.centuries * DECADES_PER_CENTURY; delete ts.centuries;

} else if (ts.centuries) { count++; }

if (!(units & DECADES) || (count >= max)) { // ripple decades down to years ts.years += ts.decades * YEARS_PER_DECADE; delete ts.decades;

} else if (ts.decades) { count++; }

if (!(units & YEARS) || (count >= max)) { // ripple years down to months ts.months += ts.years * MONTHS_PER_YEAR; delete ts.years;

} else if (ts.years) { count++; }

if (!(units & MONTHS) || (count >= max)) { // ripple months down to days if (ts.months) { ts.days += borrowMonths(ts.refMonth, ts.months); }			delete ts.months;

if (ts.days >= DAYS_PER_WEEK) { // ripple day overflow back up to weeks ts.weeks += floor(ts.days / DAYS_PER_WEEK); ts.days %= DAYS_PER_WEEK; }

} else if (ts.months) { count++; }

if (!(units & WEEKS) || (count >= max)) { // ripple weeks down to days ts.days += ts.weeks * DAYS_PER_WEEK; delete ts.weeks;

} else if (ts.weeks) { count++; }

if (!(units & DAYS) || (count >= max)) { //ripple days down to hours ts.hours += ts.days * HOURS_PER_DAY; delete ts.days;

} else if (ts.days) { count++; }

if (!(units & HOURS) || (count >= max)) { // ripple hours down to minutes ts.minutes += ts.hours * MINUTES_PER_HOUR; delete ts.hours;

} else if (ts.hours) { count++; }

if (!(units & MINUTES) || (count >= max)) { // ripple minutes down to seconds ts.seconds += ts.minutes * SECONDS_PER_MINUTE; delete ts.minutes;

} else if (ts.minutes) { count++; }

if (!(units & SECONDS) || (count >= max)) { // ripple seconds down to milliseconds ts.milliseconds += ts.seconds * MILLISECONDS_PER_SECOND; delete ts.seconds;

} else if (ts.seconds) { count++; }

// nothing to ripple milliseconds down to		// so ripple back up to smallest existing unit as a fractional value if (!(units & MILLISECONDS) || (count >= max)) { fractional(ts, digits); }	}

/**	 * Populates the Timespan object * 	 * @private * @param {Timespan} ts	 * @param {?Date} start the starting date * @param {?Date} end the ending date * @param {number} units the units to populate * @param {number} max number of labels to output * @param {number} digits max number of decimal digits to output */	function populate(ts, start, end, units, max, digits) { var now = new Date;

ts.start = start = start || now; ts.end = end = end || now; ts.units = units;

ts.value = end.getTime - start.getTime; if (ts.value < 0) { // swap if reversed var tmp = end; end = start; start = tmp; }

// reference month for determining days in month ts.refMonth = new Date(start.getFullYear, start.getMonth, 15, 12, 0, 0); try { // reset to initial deltas ts.millennia = 0; ts.centuries = 0; ts.decades = 0; ts.years = end.getFullYear - start.getFullYear; ts.months = end.getMonth - start.getMonth; ts.weeks = 0; ts.days = end.getDate - start.getDate; ts.hours = end.getHours - start.getHours; ts.minutes = end.getMinutes - start.getMinutes; ts.seconds = end.getSeconds - start.getSeconds; ts.milliseconds = end.getMilliseconds - start.getMilliseconds;

ripple(ts); pruneUnits(ts, units, max, digits);

} finally { delete ts.refMonth; }

return ts; }

/**	 * Determine an appropriate refresh rate based upon units * 	 * @private * @param {number} units the units to populate * @return {number} milliseconds to delay */	function getDelay(units) { if (units & MILLISECONDS) { // refresh very quickly return MILLISECONDS_PER_SECOND / 30; //30Hz }

if (units & SECONDS) { // refresh every second return MILLISECONDS_PER_SECOND; //1Hz }

if (units & MINUTES) { // refresh every minute return MILLISECONDS_PER_SECOND * SECONDS_PER_MINUTE; }

if (units & HOURS) { // refresh hourly return MILLISECONDS_PER_SECOND * SECONDS_PER_MINUTE * MINUTES_PER_HOUR; }		if (units & DAYS) { // refresh daily return MILLISECONDS_PER_SECOND * SECONDS_PER_MINUTE * MINUTES_PER_HOUR * HOURS_PER_DAY; }

// refresh the rest weekly return MILLISECONDS_PER_SECOND * SECONDS_PER_MINUTE * MINUTES_PER_HOUR * HOURS_PER_DAY * DAYS_PER_WEEK; }

/**	 * API entry point * 	 * @public * @param {Date|number|Timespan|null|function(Timespan,number)} start the starting date * @param {Date|number|Timespan|null|function(Timespan,number)} end the ending date * @param {number=} units the units to populate * @param {number=} max number of labels to output * @param {number=} digits max number of decimal digits to output * @return {Timespan|number} */	function countdown(start, end, units, max, digits) { var callback;

// ensure some units or use defaults units = +units || DEFAULTS; // max must be positive max = (max > 0) ? max : NaN; // clamp digits to an integer between [0, 20] digits = (digits > 0) ? (digits < 20) ? Math.round(digits) : 20 : 0;

// ensure start date var startTS = null; if ('function' === typeof start) { callback = start; start = null;

} else if (!(start instanceof Date)) { if ((start !== null) && isFinite(start)) { start = new Date(+start); } else { if ('object' === typeof startTS) { startTS = /** @type{Timespan} */(start); }				start = null; }		}

// ensure end date var endTS = null; if ('function' === typeof end) { callback = end; end = null;

} else if (!(end instanceof Date)) { if ((end !== null) && isFinite(end)) { end = new Date(+end); } else { if ('object' === typeof end) { endTS = /** @type{Timespan} */(end); }				end = null; }		}

// must wait to interpret timespans until after resolving dates if (startTS) { start = addToDate(startTS, end); }		if (endTS) { end = addToDate(endTS, start); }

if (!start && !end) { // used for unit testing return new Timespan; }

if (!callback) { return populate(new Timespan, /** @type{Date} */(start), /** @type{Date} */(end), /** @type{number} */(units), /** @type{number} */(max), /** @type{number} */(digits)); }

// base delay off units var delay = getDelay(units), timerId, fn = function { callback(					populate(new Timespan, /** @type{Date} */(start), /** @type{Date} */(end), /** @type{number} */(units), /** @type{number} */(max), /** @type{number} */(digits)),					timerId				); };

fn; return (timerId = setInterval(fn, delay)); }

/**	 * @public * @const * @type {number} */	countdown.MILLISECONDS = MILLISECONDS;

/**	 * @public * @const * @type {number} */	countdown.SECONDS = SECONDS;

/**	 * @public * @const * @type {number} */	countdown.MINUTES = MINUTES;

/**	 * @public * @const * @type {number} */	countdown.HOURS = HOURS;

/**	 * @public * @const * @type {number} */	countdown.DAYS = DAYS;

/**	 * @public * @const * @type {number} */	countdown.WEEKS = WEEKS;

/**	 * @public * @const * @type {number} */	countdown.MONTHS = MONTHS;

/**	 * @public * @const * @type {number} */	countdown.YEARS = YEARS;

/**	 * @public * @const * @type {number} */	countdown.DECADES = DECADES;

/**	 * @public * @const * @type {number} */	countdown.CENTURIES = CENTURIES;

/**	 * @public * @const * @type {number} */	countdown.MILLENNIA = MILLENNIA;

/**	 * @public * @const * @type {number} */	countdown.DEFAULTS = DEFAULTS;

/**	 * @public * @const * @type {number} */	countdown.ALL = MILLENNIA|CENTURIES|DECADES|YEARS|MONTHS|WEEKS|DAYS|HOURS|MINUTES|SECONDS|MILLISECONDS;

/**	 * Customize the format settings. * @public * @param {Object} format settings object */	var setFormat = countdown.setFormat = function(format) { if (!format) { return; }

if ('singular' in format || 'plural' in format) { var singular = format.singular || []; if (singular.split) { singular = singular.split('|'); }			var plural = format.plural || []; if (plural.split) { plural = plural.split('|'); }

for (var i=LABEL_MILLISECONDS; i<=LABEL_MILLENNIA; i++) { // override any specified units LABELS_SINGLUAR[i] = singular[i] || LABELS_SINGLUAR[i]; LABELS_PLURAL[i] = plural[i] || LABELS_PLURAL[i]; }		}

if ('string' === typeof format.last) { LABEL_LAST = format.last; }		if ('string' === typeof format.delim) { LABEL_DELIM = format.delim; }		if ('string' === typeof format.empty) { LABEL_NOW = format.empty; }		if ('function' === typeof format.formatNumber) { formatNumber = format.formatNumber; }		if ('function' === typeof format.formatter) { formatter = format.formatter; }	};

/**	 * Revert to the default formatting. * @public */	var resetFormat = countdown.resetFormat = function { LABELS_SINGLUAR = ' millisecond| second| minute| hour| day| week| month| year| decade| century| millennium'.split('|'); LABELS_PLURAL = ' milliseconds| seconds| minutes| hours| days| weeks| months| years| decades| centuries| millennia'.split('|'); LABEL_LAST = ' and '; LABEL_DELIM = ', '; LABEL_NOW = ''; formatNumber = function(value) { return value; }; formatter = plurality; };

/**	 * Override the unit labels. * @public * @param {string|Array=} singular a pipe ('|') delimited list of singular unit name overrides * @param {string|Array=} plural a pipe ('|') delimited list of plural unit name overrides * @param {string=} last a delimiter before the last unit (default: ' and ') * @param {string=} delim a delimiter to use between all other units (default: ', ') * @param {string=} empty a label to use when all units are zero (default: '') * @param {function(number):string=} formatNumber a function which formats numbers as a string * @param {function(number,number):string=} formatter a function which formats a number/unit pair as a string * @deprecated since version 2.6.0 */	countdown.setLabels = function(singular, plural, last, delim, empty, formatNumber, formatter) { setFormat({			singular: singular,			plural: plural,			last: last,			delim: delim,			empty: empty,			formatNumber: formatNumber,			formatter: formatter		}); };

/**	 * Revert to the default unit labels. * @public * @deprecated since version 2.6.0 */	countdown.resetLabels = resetFormat;

resetFormat;

if (module && module.exports) { module.exports = countdown;

} else if (typeof window.define === 'function' && typeof window.define.amd !== 'undefined') { window.define('countdown', [], function {			return countdown;		}); }

return countdown;

})(module);

$('.countdown').each( function(index,el) {	var units = countdown.DAYS | countdown.HOURS | countdown.MINUTES;	var singular = '||m|h|d';	var plural = singular;	var last = ' ';	var delim = ' ';	var end = new Date($(el).attr('data-countdown-end'));	countdown( end, function(ts) { countdown.resetLabels; countdown.setLabels(singular, plural, last, delim); $(el).html(ts.toString); countdown.resetLabels; },		units); });