diff --git a/node_modules/date-utils/.npmignore b/node_modules/date-utils/.npmignore
new file mode 100644
index 0000000..b512c09
--- /dev/null
+++ b/node_modules/date-utils/.npmignore
@@ -0,0 +1 @@
+node_modules
\ No newline at end of file
diff --git a/node_modules/date-utils/.travis.yml b/node_modules/date-utils/.travis.yml
new file mode 100644
index 0000000..f1d0f13
--- /dev/null
+++ b/node_modules/date-utils/.travis.yml
@@ -0,0 +1,4 @@
+language: node_js
+node_js:
+ - 0.4
+ - 0.6
diff --git a/node_modules/date-utils/LICENSE b/node_modules/date-utils/LICENSE
new file mode 100644
index 0000000..94d695c
--- /dev/null
+++ b/node_modules/date-utils/LICENSE
@@ -0,0 +1,19 @@
+© 2011 by Jerry Sievert
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/node_modules/date-utils/README.md b/node_modules/date-utils/README.md
new file mode 100644
index 0000000..3fc28ce
--- /dev/null
+++ b/node_modules/date-utils/README.md
@@ -0,0 +1,98 @@
+# Date-Utils: Polyfills for the Date object
+
+[](http://travis-ci.org/JerrySievert/node-date-utils)
+
+## In a nutshell
+
+- Micro-Framework adding missing functionality to the Date object
+- Useable as a polyfill in the browser
+- Useable as a polyfill in Node.js
+- Works in CouchDB
+
+## Using within a Browser
+
+
+## Using with Node.js
+ $ npm install date-utils
+
+ require('date-utils');
+
+Note: This did not work in the `REPL` before `Node.js 0.6` due to how `Node.js` handles context in the `REPL`.
+
+## Static Methods
+ Date.today(); // today, 00:00:00
+ Date.yesterday(); // yesterday, 00:00:00
+ Date.tomorrow(); // tomorrow, 00:00:00
+
+ Date.validateDay(day, year, month); // true/false whether a date is valid
+ Date.validateYear(year); // true/false whether a year is valid
+ Date.validateMonth(month); // true/false whether a month is valid
+ Date.validateHour(hour); // true/false whether an hour is valid
+ Date.validateMinute(minute); // true/false whether a minute is valid
+ Date.validateSecond(second); // true/false whether a second is valid
+ Date.validateMillisecond(millisecond); // true/false whether a millisecond is valid
+
+ Date.compare(date1, date2); // -1 if date1 is smaller than date2, 0 if equal, 1 if date2 is smaller than date1
+ Date.equals(date1, date2); // true/false if date1 is equal to date2
+
+ Date.getDayNumberFromName(name); // su/sun/sunday - 0, mo/mon/monday - 1, etc
+ Date.getMonthNumberFromName(name); // jan/january - 0, feb/february - 1, etc
+ Date.isLeapYear(year); // true/false whether the year is a leap year
+ Date.getDaysInMonth(monthNumber); // number of days in the month
+
+## Instance Methods
+ d.clone(); // returns a new copy of date object set to the same time
+ d.getMonthAbbr(); // abreviated month name, Jan, Feb, etc
+ d.getMonthName(); // fill month name, January, February, etc
+ d.getUTCOffset(); // returns the UTC offset
+ d.getOrdinalNumber(); // day number of the year, 1-366 (leap year)
+ d.clearTime(); // sets time to 00:00:00
+ d.setTimeToNow(); // sets time to current time
+ d.toFormat(format); // returns date formatted with:
+ // YYYY - Four digit year
+ // MMMM - Full month name. ie January
+ // MMM - Short month name. ie Jan
+ // MM - Zero padded month ie 01
+ // M - Month ie 1
+ // DDDD - Full day or week name ie Tuesday
+ // DDD - Abbreviated day of the week ie Tue
+ // DD - Zero padded day ie 08
+ // D - Day ie 8
+ // HH24 - Hours in 24 notation ie 18
+ // HH - Padded Hours ie 06
+ // H - Hours ie 6
+ // MI - Padded Minutes
+ // SS - Padded Seconds
+ // PP - AM or PM
+ // P - am or pm
+ d.toYMD(separator); // returns YYYY-MM-DD by default, separator changes delimiter
+
+ d.between(date1, date2); // true/false if the date/time is between date1 and date2
+ d.compareTo(date); // -1 if date is smaller than this, 0 if equal, 1 if date is larger than this
+ d.equals(date); // true/false, true if dates are equal
+ d.isBefore(date); // true/false, true if this is before date passed
+ d.isAfter(date); // true/false, true if this is after date passed
+ d.getDaysBetween(date); // returns number of full days between this and passed
+ d.getHoursBetween(date); // returns number of hours days between this and passed
+ d.getMinutesBetween(date); // returns number of full minutes between this and passed
+ d.getSecondsBetween(date); // returns number of full seconds between this and passed
+
+ d.add({ milliseconds: 30,
+ minutes: 1,
+ hours: 4,
+ seconds: 30,
+ days: 2,
+ weeks: 1,
+ months: 3,
+ years: 2}); // adds time to existing time
+
+ d.addMilliseconds(number); // add milliseconds to existing time
+ d.addSeconds(number); // add seconds to existing time
+ d.addMinutes(number); // add minutes to existing time
+ d.addHours(number); // add hours to existing time
+ d.addDays(number); // add days to existing time
+ d.addWeeks(number); // add weeks to existing time
+ d.addMonths(number); // add months to existing time
+ d.addYears(number); // add years to existing time
+
+
diff --git a/node_modules/date-utils/lib/date-utils.js b/node_modules/date-utils/lib/date-utils.js
new file mode 100644
index 0000000..07959e3
--- /dev/null
+++ b/node_modules/date-utils/lib/date-utils.js
@@ -0,0 +1,786 @@
+/*
+
+© 2011 by Jerry Sievert
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*/
+
+(function () {
+ // constants
+ var monthsAbbr = [
+ 'Jan',
+ 'Feb',
+ 'Mar',
+ 'Apr',
+ 'May',
+ 'Jun',
+ 'Jul',
+ 'Aug',
+ 'Sep',
+ 'Oct',
+ 'Nov',
+ 'Dec'
+ ];
+
+ var monthsFull = [
+ 'January',
+ 'February',
+ 'March',
+ 'April',
+ 'May',
+ 'June',
+ 'July',
+ 'August',
+ 'September',
+ 'October',
+ 'November',
+ 'December'
+ ];
+
+ var daysAbbr = [
+ 'Sun',
+ 'Mon',
+ 'Tue',
+ 'Wed',
+ 'Thu',
+ 'Fri',
+ 'Sat'
+ ];
+
+ var daysFull = [
+ 'Sunday',
+ 'Monday',
+ 'Tuesday',
+ 'Wednesday',
+ 'Thursday',
+ 'Friday',
+ 'Saturday'
+ ];
+
+ var dayNames = {
+ 'su': 0,
+ 'sun': 0,
+ 'sunday': 0,
+ 'mo': 1,
+ 'mon': 1,
+ 'monday': 1,
+ 'tu': 2,
+ 'tue': 2,
+ 'tuesday': 2,
+ 'we': 3,
+ 'wed': 3,
+ 'wednesday': 3,
+ 'th': 4,
+ 'thu': 4,
+ 'thursday': 4,
+ 'fr': 5,
+ 'fri': 5,
+ 'friday': 5,
+ 'sa': 6,
+ 'sat': 6,
+ 'saturday': 6
+ };
+ var monthsAll = monthsFull.concat(monthsAbbr);
+ var daysAll = [
+ 'su',
+ 'sun',
+ 'sunday',
+ 'mo',
+ 'mon',
+ 'monday',
+ 'tu',
+ 'tue',
+ 'tuesday',
+ 'we',
+ 'wed',
+ 'wednesday',
+ 'th',
+ 'thu',
+ 'thursday',
+ 'fr',
+ 'fri',
+ 'friday',
+ 'sa',
+ 'sat',
+ 'saturday'
+ ];
+
+ var monthNames = {
+ 'jan': 0,
+ 'january': 0,
+ 'feb': 1,
+ 'february': 1,
+ 'mar': 2,
+ 'march': 2,
+ 'apr': 3,
+ 'april': 3,
+ 'may': 4,
+ 'jun': 5,
+ 'june': 5,
+ 'jul': 6,
+ 'july': 6,
+ 'aug': 7,
+ 'august': 7,
+ 'sep': 8,
+ 'september': 8,
+ 'oct': 9,
+ 'october': 9,
+ 'nov': 10,
+ 'november': 10,
+ 'dec': 11,
+ 'december': 11
+ };
+
+ var daysInMonth = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ];
+
+
+ // private helper functions
+ /** @ignore */
+ function pad(str, length) {
+ str = String(str);
+ while (str.length < length) {
+ str = '0' + str;
+ }
+ return str;
+ }
+
+ var isInteger = function (str) {
+ if (str.match(/^(\d+)$/)) {
+ return true;
+ }
+ return false;
+ };
+ var getInt = function (str, i, minlength, maxlength) {
+ for (var x = maxlength; x >= minlength; x--) {
+ var token = str.substring(i, i + x);
+ if (token.length < minlength) {
+ return null;
+ }
+ if (isInteger(token)) {
+ return token;
+ }
+ }
+ return null;
+ };
+
+ // static class methods
+ var origParse = Date.parse;
+ // ------------------------------------------------------------------
+ // getDateFromFormat( date_string , format_string )
+ //
+ // This function takes a date string and a format string. It matches
+ // If the date string matches the format string, it returns the
+ // getTime() of the date. If it does not match, it returns NaN.
+ // Original Author: Matt Kruse
+ // WWW: http://www.mattkruse.com/
+ // Adapted from: http://www.mattkruse.com/javascript/date/source.html
+ // ------------------------------------------------------------------
+
+
+ var getDateFromFormat = function (val, format) {
+ val = val + "";
+ format = format + "";
+ var iVal = 0;
+ var iFormat = 0;
+ var c = "";
+ var token = "";
+ var token2 = "";
+ var x, y;
+ var now = new Date();
+ var year = now.getYear();
+ var month = now.getMonth() + 1;
+ var date = 1;
+ var hh = 0;
+ var mm = 0;
+ var ss = 0;
+ var ampm = "";
+
+
+
+ while (iFormat < format.length) {
+ // Get next token from format string
+ c = format.charAt(iFormat);
+ token = "";
+ while ((format.charAt(iFormat) === c) && (iFormat < format.length)) {
+ token += format.charAt(iFormat++);
+ }
+ // Extract contents of value based on format token
+ if (token === "yyyy" || token === "yy" || token === "y") {
+ if (token === "yyyy") {
+ x = 4;
+ y = 4;
+ }
+ if (token === "yy") {
+ x = 2;
+ y = 2;
+ }
+ if (token === "y") {
+ x = 2;
+ y = 4;
+ }
+ year = getInt(val, iVal, x, y);
+ if (year === null) {
+ return NaN;
+ }
+ iVal += year.length;
+ if (year.length === 2) {
+ if (year > 70) {
+ year = 1900 + (year - 0);
+ } else {
+ year = 2000 + (year - 0);
+ }
+ }
+ } else if (token === "MMM" || token === "NNN") {
+ month = 0;
+ for (var i = 0; i < monthsAll.length; i++) {
+ var monthName = monthsAll[i];
+ if (val.substring(iVal, iVal + monthName.length).toLowerCase() === monthName.toLowerCase()) {
+ if (token === "MMM" || (token === "NNN" && i > 11)) {
+ month = i + 1;
+ if (month > 12) {
+ month -= 12;
+ }
+ iVal += monthName.length;
+ break;
+ }
+ }
+ }
+ if ((month < 1) || (month > 12)) {
+ return NaN;
+ }
+ } else if (token === "EE" || token === "E") {
+ for (var n = 0; n < daysAll.length; n++) {
+ var dayName = daysAll[n];
+ if (val.substring(iVal, iVal + dayName.length).toLowerCase() === dayName.toLowerCase()) {
+ iVal += dayName.length;
+ break;
+ }
+ }
+ } else if (token === "MM" || token === "M") {
+ month = getInt(val, iVal, token.length, 2);
+ if (month === null || (month < 1) || (month > 12)) {
+ return NaN;
+ }
+ iVal += month.length;
+ } else if (token === "dd" || token === "d") {
+ date = getInt(val, iVal, token.length, 2);
+ if (date === null || (date < 1) || (date > 31)) {
+ return NaN;
+ }
+ iVal += date.length;
+ } else if (token === "hh" || token === "h") {
+ hh = getInt(val, iVal, token.length, 2);
+ if (hh === null || (hh < 1) || (hh > 12)) {
+ return NaN;
+ }
+ iVal += hh.length;
+ } else if (token === "HH" || token === "H") {
+ hh = getInt(val, iVal, token.length, 2);
+ if (hh === null || (hh < 0) || (hh > 23)) {
+ return NaN;
+ }
+ iVal += hh.length;
+ } else if (token === "KK" || token === "K") {
+ hh = getInt(val, iVal, token.length, 2);
+ if (hh === null || (hh < 0) || (hh > 11)) {
+ return NaN;
+ }
+ iVal += hh.length;
+ } else if (token === "kk" || token === "k") {
+ hh = getInt(val, iVal, token.length, 2);
+ if (hh === null || (hh < 1) || (hh > 24)) {
+ return NaN;
+ }
+ iVal += hh.length;
+ hh--;
+ } else if (token === "mm" || token === "m") {
+ mm = getInt(val, iVal, token.length, 2);
+ if (mm === null || (mm < 0) || (mm > 59)) {
+ return NaN;
+ }
+ iVal += mm.length;
+ } else if (token === "ss" || token === "s") {
+ ss = getInt(val, iVal, token.length, 2);
+ if (ss === null || (ss < 0) || (ss > 59)) {
+ return NaN;
+ }
+ iVal += ss.length;
+ } else if (token === "a") {
+ if (val.substring(iVal, iVal + 2).toLowerCase() === "am") {
+ ampm = "AM";
+ } else if (val.substring(iVal, iVal + 2).toLowerCase() === "pm") {
+ ampm = "PM";
+ } else {
+ return NaN;
+ }
+ iVal += 2;
+ } else {
+ if (val.substring(iVal, iVal + token.length) !== token) {
+ return NaN;
+ } else {
+ iVal += token.length;
+ }
+ }
+ }
+ // If there are any trailing characters left in the value, it doesn't match
+ if (iVal !== val.length) {
+ return NaN;
+ }
+ // Is date valid for month?
+ if (month === 2) {
+ // Check for leap year
+ if (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0)) { // leap year
+ if (date > 29) {
+ return NaN;
+ }
+ } else {
+ if (date > 28) {
+ return NaN;
+ }
+ }
+ }
+ if ((month === 4) || (month === 6) || (month === 9) || (month === 11)) {
+ if (date > 30) {
+ return NaN;
+ }
+ }
+ // Correct hours value
+ if (hh < 12 && ampm === "PM") {
+ hh = hh - 0 + 12;
+ } else if (hh > 11 && ampm === "AM") {
+ hh -= 12;
+ }
+ var newdate = new Date(year, month - 1, date, hh, mm, ss);
+ return newdate.getTime();
+ };
+
+
+ /** @ignore */
+ Date.parse = function (date, format) {
+ if (format) {
+ return getDateFromFormat(date, format);
+ }
+ var timestamp = origParse(date), minutesOffset = 0, match;
+ if (isNaN(timestamp) && (match = /^(\d{4}|[+\-]\d{6})-(\d{2})-(\d{2})(?:[T ](\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3,}))?)?(?:(Z)|([+\-])(\d{2})(?::?(\d{2}))?))?/.exec(date))) {
+ if (match[8] !== 'Z') {
+ minutesOffset = +match[10] * 60 + (+match[11]);
+
+ if (match[9] === '+') {
+ minutesOffset = 0 - minutesOffset;
+ }
+ }
+
+ match[7] = match[7] || '000';
+
+ timestamp = Date.UTC(+match[1], +match[2] - 1, +match[3], +match[4], +match[5] + minutesOffset, +match[6], +match[7].substr(0, 3));
+ }
+
+ return timestamp;
+ };
+
+ function polyfill(name, func) {
+ if (Date.prototype[name] === undefined) {
+ Date.prototype[name] = func;
+ }
+ }
+
+ /**
+ Returns new instance of Date object with the date set to today and
+ the time set to midnight
+ @returns {Date} Today's Date
+ @function
+ */
+ Date.today = function () {
+ return new Date().clearTime();
+ };
+
+ /**
+ Returns new instance of Date object with the date set to today and
+ the time set to midnight in UTC
+ @returns {Date} Today's Date in UTC
+ @function
+ */
+ Date.UTCtoday = function () {
+ return new Date().clearUTCTime();
+ };
+
+ /**
+ Returns new instance of Date object with the date set to tomorrow and
+ the time set to midnight
+ @returns {Date} Tomorrow's Date
+ @function
+ */
+ Date.tomorrow = function () {
+ return Date.today().add({days: 1});
+ };
+
+ /**
+ Returns new instance of Date object with the date set to tomorrow and
+ the time set to midnight in UTC
+ @returns {Date} Tomorrow's Date in UTC
+ @function
+ */
+ Date.UTCtomorrow = function () {
+ return Date.UTCtoday().add({days: 1});
+ };
+
+ /**
+ Returns new instance of Date object with the date set to yesterday and
+ the time set to midnight
+ @returns {Date} Yesterday's Date
+ @function
+ */
+ Date.yesterday = function () {
+ return Date.today().add({days: -1});
+ };
+
+ /**
+ Returns new instance of Date object with the date set to yesterday and
+ the time set to midnight in UTC
+ @returns {Date} Yesterday's Date in UTC
+ @function
+ */
+ Date.UTCyesterday = function () {
+ return Date.UTCtoday().add({days: -1});
+ };
+
+ Date.validateDay = function (day, year, month) {
+ var date = new Date(year, month, day);
+ return (date.getFullYear() === year &&
+ date.getMonth() === month &&
+ date.getDate() === day);
+ };
+
+ Date.validateYear = function (year) {
+ return (year >= 0 && year <= 9999);
+ };
+
+ Date.validateSecond = function (second) {
+ return (second >= 0 && second < 60);
+ };
+
+ Date.validateMonth = function (month) {
+ return (month >= 0 && month < 12);
+ };
+
+ Date.validateMinute = function (minute) {
+ return (minute >= 0 && minute < 60);
+ };
+
+ Date.validateMillisecond = function (milli) {
+ return (milli >= 0 && milli < 1000);
+ };
+
+ Date.validateHour = function (hour) {
+ return (hour >= 0 && hour < 24);
+ };
+
+ Date.compare = function (date1, date2) {
+ if (date1.valueOf() < date2.valueOf()) {
+ return -1;
+ } else if (date1.valueOf() > date2.valueOf()) {
+ return 1;
+ }
+ return 0;
+ };
+
+ Date.equals = function (date1, date2) {
+ return date1.valueOf() === date2.valueOf();
+ };
+
+
+ Date.getDayNumberFromName = function (name) {
+ return dayNames[name.toLowerCase()];
+ };
+
+
+ Date.getMonthNumberFromName = function (name) {
+ return monthNames[name.toLowerCase()];
+ };
+
+ Date.isLeapYear = function (year) {
+ return (new Date(year, 1, 29).getDate() === 29);
+ };
+
+ Date.getDaysInMonth = function (year, month) {
+ if (month === 1) {
+ return Date.isLeapYear(year) ? 29 : 28;
+ }
+ return daysInMonth[month];
+ };
+
+ polyfill('getMonthAbbr', function () {
+ return monthsAbbr[this.getMonth()];
+ });
+
+ polyfill('getMonthName', function () {
+ return monthsFull[this.getMonth()];
+ });
+
+ polyfill('getUTCOffset', function () {
+ var tz = pad(Math.abs(this.getTimezoneOffset() / 0.6), 4);
+ if (this.getTimezoneOffset() > 0) {
+ tz = '-' + tz;
+ }
+ return tz;
+ });
+
+ polyfill('toCLFString', function () {
+ return pad(this.getDate(), 2) + '/' + this.getMonthAbbr() + '/' +
+ this.getFullYear() + ':' + pad(this.getHours(), 2) + ':' +
+ pad(this.getMinutes(), 2) + ':' + pad(this.getSeconds(), 2) +
+ ' ' + this.getUTCOffset();
+ });
+
+ polyfill('toYMD', function (separator) {
+ separator = typeof separator === 'undefined' ? '-' : separator;
+ return this.getFullYear() + separator + pad(this.getMonth() + 1, 2) +
+ separator + pad(this.getDate(), 2);
+ });
+
+ polyfill('toDBString', function () {
+ return this.getUTCFullYear() + '-' + pad(this.getUTCMonth() + 1, 2) +
+ '-' + pad(this.getUTCDate(), 2) + ' ' + pad(this.getUTCHours(), 2) +
+ ':' + pad(this.getUTCMinutes(), 2) + ':' + pad(this.getUTCSeconds(), 2);
+ });
+
+ polyfill('clearTime', function () {
+ this.setHours(0);
+ this.setMinutes(0);
+ this.setSeconds(0);
+ this.setMilliseconds(0);
+
+ return this;
+ });
+
+ polyfill('clearUTCTime', function () {
+ this.setUTCHours(0);
+ this.setUTCMinutes(0);
+ this.setUTCSeconds(0);
+ this.setUTCMilliseconds(0);
+
+ return this;
+ });
+
+ polyfill('add', function (obj) {
+ if (obj.milliseconds !== undefined) {
+ this.setMilliseconds(this.getMilliseconds() + obj.milliseconds);
+ }
+ if (obj.seconds !== undefined) {
+ this.setSeconds(this.getSeconds() + obj.seconds);
+ }
+ if (obj.minutes !== undefined) {
+ this.setMinutes(this.getMinutes() + obj.minutes);
+ }
+ if (obj.hours !== undefined) {
+ this.setHours(this.getHours() + obj.hours);
+ }
+ if (obj.days !== undefined) {
+ this.setDate(this.getDate() + obj.days);
+ }
+ if (obj.weeks !== undefined) {
+ this.setDate(this.getDate() + (obj.weeks * 7));
+ }
+ if (obj.months !== undefined) {
+ this.setMonth(this.getMonth() + obj.months);
+ }
+ if (obj.years !== undefined) {
+ this.setFullYear(this.getFullYear() + obj.years);
+ }
+ return this;
+ });
+
+ polyfill('addMilliseconds', function (milliseconds) {
+ return this.add({ milliseconds: milliseconds });
+ });
+
+ polyfill('addSeconds', function (seconds) {
+ return this.add({ seconds: seconds });
+ });
+
+ polyfill('addMinutes', function (minutes) {
+ return this.add({ minutes: minutes });
+ });
+
+ polyfill('addHours', function (hours) {
+ return this.add({ hours: hours });
+ });
+
+ polyfill('addDays', function (days) {
+ return this.add({ days: days });
+ });
+
+ polyfill('addWeeks', function (weeks) {
+ return this.add({ days: (weeks * 7) });
+ });
+
+ polyfill('addMonths', function (months) {
+ return this.add({ months: months });
+ });
+
+ polyfill('addYears', function (years) {
+ return this.add({ years: years });
+ });
+
+ polyfill('setTimeToNow', function () {
+ var n = new Date();
+ this.setMilliseconds(n.getMilliseconds());
+ this.setSeconds(n.getSeconds());
+ this.setMinutes(n.getMinutes());
+ this.setHours(n.getHours());
+ });
+
+ polyfill('clone', function () {
+ return new Date(this.valueOf());
+ });
+
+ polyfill('between', function (start, end) {
+ return (this.valueOf() >= start.valueOf() &&
+ this.valueOf() <= end.valueOf());
+ });
+
+ polyfill('compareTo', function (date) {
+ return Date.compare(this, date);
+ });
+
+ polyfill('equals', function (date) {
+ return Date.equals(this, date);
+ });
+
+ polyfill('isAfter', function (date) {
+ date = date ? date : new Date();
+ return (this.compareTo(date) > 0);
+ });
+
+ polyfill('isBefore', function (date) {
+ date = date ? date : new Date();
+ return (this.compareTo(date) < 0);
+ });
+
+ polyfill('getDaysBetween', function (date) {
+ return ((date.clone().valueOf() - this.valueOf()) / 86400000) | 0;
+ });
+
+ polyfill('getHoursBetween', function (date) {
+ return ((date.clone().valueOf() - this.valueOf()) / 3600000) | 0;
+ });
+
+ polyfill('getMinutesBetween', function (date) {
+ return ((date.clone().valueOf() - this.valueOf()) / 60000) | 0;
+ });
+
+ polyfill('getSecondsBetween', function (date) {
+ return ((date.clone().valueOf() - this.valueOf()) / 1000) | 0;
+ });
+
+ polyfill('getMillisecondsBetween', function (date) {
+ return ((date.clone().valueOf() - this.valueOf())) | 0;
+ });
+
+ polyfill('getOrdinalNumber', function () {
+ return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1;
+ });
+
+ polyfill('toFormat', function (format) {
+ return toFormat(format, getReplaceMap(this));
+ });
+
+ polyfill('toUTCFormat', function (format) {
+ return toFormat(format, getUTCReplaceMap(this));
+ });
+
+ var toFormat = function(format, replaceMap) {
+ var f = [ format ], i, l, s;
+ var replace = function (str, rep) {
+ var i = 0, l = f.length, j, ll, t, n = [];
+ for (; i < l; i++) {
+ if (typeof f[i] == 'string') {
+ t = f[i].split(str);
+ for (j = 0, ll = t.length - 1; j < ll; j++) {
+ n.push(t[j]);
+ n.push([rep]); // replacement pushed as non-string
+ }
+ n.push(t[ll]);
+ } else {
+ // must be a replacement, don't process, just push
+ n.push(f[i]);
+ }
+ }
+ f = n;
+ };
+
+ for (i in replaceMap) {
+ replace(i, replaceMap[i]);
+ }
+
+ s = '';
+ for (i = 0, l = f.length; i < l; i++)
+ s += typeof f[i] == 'string' ? f[i] : f[i][0];
+ return f.join('');
+ };
+
+ var getReplaceMap = function(date) {
+ var hours = (date.getHours() % 12) ? date.getHours() % 12 : 12;
+ return {
+ 'YYYY': date.getFullYear(),
+ 'YY': String(date.getFullYear()).slice(-2),
+ 'MMMM': monthsFull[date.getMonth()],
+ 'MMM': monthsAbbr[date.getMonth()],
+ 'MM': pad(date.getMonth() + 1, 2),
+ 'MI': pad(date.getMinutes(), 2),
+ 'M': date.getMonth() + 1,
+ 'DDDD': daysFull[date.getDay()],
+ 'DDD': daysAbbr[date.getDay()],
+ 'DD': pad(date.getDate(), 2),
+ 'D': date.getDate(),
+ 'HH24': pad(date.getHours(), 2),
+ 'HH': pad(hours, 2),
+ 'H': hours,
+ 'SS': pad(date.getSeconds(), 2),
+ 'PP': (date.getHours() >= 12) ? 'PM' : 'AM',
+ 'P': (date.getHours() >= 12) ? 'pm' : 'am',
+ 'LL': pad(date.getMilliseconds(), 3)
+ };
+ };
+
+ var getUTCReplaceMap = function(date) {
+ var hours = (date.getUTCHours() % 12) ? date.getUTCHours() % 12 : 12;
+ return {
+ 'YYYY': date.getUTCFullYear(),
+ 'YY': String(date.getUTCFullYear()).slice(-2),
+ 'MMMM': monthsFull[date.getUTCMonth()],
+ 'MMM': monthsAbbr[date.getUTCMonth()],
+ 'MM': pad(date.getUTCMonth() + 1, 2),
+ 'MI': pad(date.getUTCMinutes(), 2),
+ 'M': date.getUTCMonth() + 1,
+ 'DDDD': daysFull[date.getUTCDay()],
+ 'DDD': daysAbbr[date.getUTCDay()],
+ 'DD': pad(date.getUTCDate(), 2),
+ 'D': date.getUTCDate(),
+ 'HH24': pad(date.getUTCHours(), 2),
+ 'HH': pad(hours, 2),
+ 'H': hours,
+ 'SS': pad(date.getUTCSeconds(), 2),
+ 'PP': (date.getUTCHours() >= 12) ? 'PM' : 'AM',
+ 'P': (date.getUTCHours() >= 12) ? 'pm' : 'am',
+ 'LL': pad(date.getUTCMilliseconds(), 3)
+ };
+ };
+}());
diff --git a/node_modules/date-utils/lib/date-utils.min.js b/node_modules/date-utils/lib/date-utils.min.js
new file mode 100644
index 0000000..c7dd4b5
--- /dev/null
+++ b/node_modules/date-utils/lib/date-utils.min.js
@@ -0,0 +1 @@
+(function(){function f(e,t){e=String(e);while(e.length=n;i--){var s=e.substring(t,t+i);if(s.length70?p=1900+(p-0):p=2e3+(p-0))}else if(u==="MMM"||u==="NNN"){d=0;for(var w=0;w11){d=w+1,d>12&&(d-=12),n+=E.length;break}}if(d<1||d>12)return NaN}else if(u==="EE"||u==="E")for(var S=0;S12)return NaN;n+=d.length}else if(u==="dd"||u==="d"){v=c(e,n,u.length,2);if(v===null||v<1||v>31)return NaN;n+=v.length}else if(u==="hh"||u==="h"){m=c(e,n,u.length,2);if(m===null||m<1||m>12)return NaN;n+=m.length}else if(u==="HH"||u==="H"){m=c(e,n,u.length,2);if(m===null||m<0||m>23)return NaN;n+=m.length}else if(u==="KK"||u==="K"){m=c(e,n,u.length,2);if(m===null||m<0||m>11)return NaN;n+=m.length}else if(u==="kk"||u==="k"){m=c(e,n,u.length,2);if(m===null||m<1||m>24)return NaN;n+=m.length,m--}else if(u==="mm"||u==="m"){g=c(e,n,u.length,2);if(g===null||g<0||g>59)return NaN;n+=g.length}else if(u==="ss"||u==="s"){y=c(e,n,u.length,2);if(y===null||y<0||y>59)return NaN;n+=y.length}else if(u==="a"){if(e.substring(n,n+2).toLowerCase()==="am")b="AM";else{if(e.substring(n,n+2).toLowerCase()!=="pm")return NaN;b="PM"}n+=2}else{if(e.substring(n,n+u.length)!==u)return NaN;n+=u.length}}if(n!==e.length)return NaN;if(d===2)if(p%4===0&&p%100!==0||p%400===0){if(v>29)return NaN}else if(v>28)return NaN;if(d===4||d===6||d===9||d===11)if(v>30)return NaN;m<12&&b==="PM"?m=m-0+12:m>11&&b==="AM"&&(m-=12);var T=new Date(p,d-1,v,m,g,y);return T.getTime()};Date.parse=function(e,t){if(t)return p(e,t);var n=h(e),r=0,i;return isNaN(n)&&(i=/^(\d{4}|[+\-]\d{6})-(\d{2})-(\d{2})(?:[T ](\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3,}))?)?(?:(Z)|([+\-])(\d{2})(?::?(\d{2}))?))?/.exec(e))&&(i[8]!=="Z"&&(r=+i[10]*60+ +i[11],i[9]==="+"&&(r=0-r)),i[7]=i[7]||"000",n=Date.UTC(+i[1],+i[2]-1,+i[3],+i[4],+i[5]+r,+i[6],+i[7].substr(0,3))),n},Date.today=function(){return(new Date).clearTime()},Date.UTCtoday=function(){return(new Date).clearUTCTime()},Date.tomorrow=function(){return Date.today().add({days:1})},Date.UTCtomorrow=function(){return Date.UTCtoday().add({days:1})},Date.yesterday=function(){return Date.today().add({days:-1})},Date.UTCyesterday=function(){return Date.UTCtoday().add({days:-1})},Date.validateDay=function(e,t,n){var r=new Date(t,n,e);return r.getFullYear()===t&&r.getMonth()===n&&r.getDate()===e},Date.validateYear=function(e){return e>=0&&e<=9999},Date.validateSecond=function(e){return e>=0&&e<60},Date.validateMonth=function(e){return e>=0&&e<12},Date.validateMinute=function(e){return e>=0&&e<60},Date.validateMillisecond=function(e){return e>=0&&e<1e3},Date.validateHour=function(e){return e>=0&&e<24},Date.compare=function(e,t){return e.valueOf()t.valueOf()?1:0},Date.equals=function(e,t){return e.valueOf()===t.valueOf()},Date.getDayNumberFromName=function(e){return i[e.toLowerCase()]},Date.getMonthNumberFromName=function(e){return u[e.toLowerCase()]},Date.isLeapYear=function(e){return(new Date(e,1,29)).getDate()===29},Date.getDaysInMonth=function(e,t){return t===1?Date.isLeapYear(e)?29:28:a[t]},d("getMonthAbbr",function(){return e[this.getMonth()]}),d("getMonthName",function(){return t[this.getMonth()]}),d("getUTCOffset",function(){var e=f(Math.abs(this.getTimezoneOffset()/.6),4);return this.getTimezoneOffset()>0&&(e="-"+e),e}),d("toCLFString",function(){return f(this.getDate(),2)+"/"+this.getMonthAbbr()+"/"+this.getFullYear()+":"+f(this.getHours(),2)+":"+f(this.getMinutes(),2)+":"+f(this.getSeconds(),2)+" "+this.getUTCOffset()}),d("toYMD",function(e){return e=typeof e=="undefined"?"-":e,this.getFullYear()+e+f(this.getMonth()+1,2)+e+f(this.getDate(),2)}),d("toDBString",function(){return this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1,2)+"-"+f(this.getUTCDate(),2)+" "+f(this.getUTCHours(),2)+":"+f(this.getUTCMinutes(),2)+":"+f(this.getUTCSeconds(),2)}),d("clearTime",function(){return this.setHours(0),this.setMinutes(0),this.setSeconds(0),this.setMilliseconds(0),this}),d("clearUTCTime",function(){return this.setUTCHours(0),this.setUTCMinutes(0),this.setUTCSeconds(0),this.setUTCMilliseconds(0),this}),d("add",function(e){return e.milliseconds!==undefined&&this.setMilliseconds(this.getMilliseconds()+e.milliseconds),e.seconds!==undefined&&this.setSeconds(this.getSeconds()+e.seconds),e.minutes!==undefined&&this.setMinutes(this.getMinutes()+e.minutes),e.hours!==undefined&&this.setHours(this.getHours()+e.hours),e.days!==undefined&&this.setDate(this.getDate()+e.days),e.weeks!==undefined&&this.setDate(this.getDate()+e.weeks*7),e.months!==undefined&&this.setMonth(this.getMonth()+e.months),e.years!==undefined&&this.setFullYear(this.getFullYear()+e.years),this}),d("addMilliseconds",function(e){return this.add({milliseconds:e})}),d("addSeconds",function(e){return this.add({seconds:e})}),d("addMinutes",function(e){return this.add({minutes:e})}),d("addHours",function(e){return this.add({hours:e})}),d("addDays",function(e){return this.add({days:e})}),d("addWeeks",function(e){return this.add({days:e*7})}),d("addMonths",function(e){return this.add({months:e})}),d("addYears",function(e){return this.add({years:e})}),d("setTimeToNow",function(){var e=new Date;this.setMilliseconds(e.getMilliseconds()),this.setSeconds(e.getSeconds()),this.setMinutes(e.getMinutes()),this.setHours(e.getHours())}),d("clone",function(){return new Date(this.valueOf())}),d("between",function(e,t){return this.valueOf()>=e.valueOf()&&this.valueOf()<=t.valueOf()}),d("compareTo",function(e){return Date.compare(this,e)}),d("equals",function(e){return Date.equals(this,e)}),d("isAfter",function(e){return e=e?e:new Date,this.compareTo(e)>0}),d("isBefore",function(e){return e=e?e:new Date,this.compareTo(e)<0}),d("getDaysBetween",function(e){return(e.clone().valueOf()-this.valueOf())/864e5|0}),d("getHoursBetween",function(e){return(e.clone().valueOf()-this.valueOf())/36e5|0}),d("getMinutesBetween",function(e){return(e.clone().valueOf()-this.valueOf())/6e4|0}),d("getSecondsBetween",function(e){return(e.clone().valueOf()-this.valueOf())/1e3|0}),d("getMillisecondsBetween",function(e){return e.clone().valueOf()-this.valueOf()|0}),d("getOrdinalNumber",function(){return Math.ceil((this.clone().clearTime()-new Date(this.getFullYear(),0,1))/864e5)+1}),d("toFormat",function(e){return v(e,m(this))}),d("toUTCFormat",function(e){return v(e,g(this))});var v=function(e,t){var n=[e],r,i,s,o=function(e,t){var r=0,i=n.length,s,o,u,a=[];for(;r=12?"PM":"AM",P:i.getHours()>=12?"pm":"am",LL:f(i.getMilliseconds(),3)}},g=function(i){var s=i.getUTCHours()%12?i.getUTCHours()%12:12;return{YYYY:i.getUTCFullYear(),YY:String(i.getUTCFullYear()).slice(-2),MMMM:t[i.getUTCMonth()],MMM:e[i.getUTCMonth()],MM:f(i.getUTCMonth()+1,2),MI:f(i.getUTCMinutes(),2),M:i.getUTCMonth()+1,DDDD:r[i.getUTCDay()],DDD:n[i.getUTCDay()],DD:f(i.getUTCDate(),2),D:i.getUTCDate(),HH24:f(i.getUTCHours(),2),HH:f(s,2),H:s,SS:f(i.getUTCSeconds(),2),PP:i.getUTCHours()>=12?"PM":"AM",P:i.getUTCHours()>=12?"pm":"am",LL:f(i.getUTCMilliseconds(),3)}}})();
\ No newline at end of file
diff --git a/node_modules/date-utils/package.json b/node_modules/date-utils/package.json
new file mode 100644
index 0000000..bd1925f
--- /dev/null
+++ b/node_modules/date-utils/package.json
@@ -0,0 +1,55 @@
+{
+ "name": "date-utils",
+ "description": "Date add-ons for Node.js",
+ "version": "1.2.12",
+ "keywords": [
+ "date",
+ "utils",
+ "date-utils",
+ "time"
+ ],
+ "author": {
+ "name": "Jerry Sievert",
+ "email": "code@legitimatesounding.com",
+ "url": "http://legitimatesounding.com/blog/"
+ },
+ "homepage": "http://github.com/JerrySievert/node-date-utils/",
+ "contributors": [
+ {
+ "name": "Jerry Sievert",
+ "url": "http://legitimatesounding.com"
+ }
+ ],
+ "license": [
+ "MIT"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/JerrySievert/node-date-utils.git"
+ },
+ "bugs": {
+ "url": "http://github.com/JerrySievert/node-date-utils/issues"
+ },
+ "directories": {
+ "lib": "./lib",
+ "test": "./test"
+ },
+ "devDependencies": {
+ "vows": ">0.4.0"
+ },
+ "scripts": {
+ "test": "vows --spec"
+ },
+ "engines": {
+ "node": ">0.4.0"
+ },
+ "main": "./lib/date-utils",
+ "_id": "date-utils@1.2.12",
+ "dependencies": {},
+ "optionalDependencies": {},
+ "_engineSupported": true,
+ "_npmVersion": "1.1.21",
+ "_nodeVersion": "v0.6.18",
+ "_defaultsLoaded": true,
+ "_from": "date-utils"
+}
diff --git a/node_modules/date-utils/test/date-format-test.js b/node_modules/date-utils/test/date-format-test.js
new file mode 100644
index 0000000..bcffc0c
--- /dev/null
+++ b/node_modules/date-utils/test/date-format-test.js
@@ -0,0 +1,151 @@
+var vows = require('vows');
+var assert = require('assert');
+
+require('../lib/date-utils.js');
+
+function pad(str, length) {
+ str = String(str);
+ while (str.length < length) {
+ str = '0' + str;
+ }
+ return str;
+}
+
+vows.describe('Date Format').addBatch({
+ 'can return month abbreviations as static method': {
+ topic: function () { return new Date(123456789); },
+ 'returns the correct abbreviated month': function (date) {
+ assert.equal(date.getMonthAbbr(), 'Jan');
+ }
+ },
+
+ 'can return month as static method': {
+ topic: function () { return new Date(123456789); },
+ 'returns the correct month': function (date) {
+ assert.equal(date.getMonthAbbr(), 'Jan');
+ }
+ },
+
+ 'can return common log formatted string': {
+ topic: function () { return new Date(Date.UTC(2011, 0, 1, 1, 1, 1, 0)); },
+ 'returns the correct clf string': function (date) {
+ var tz = pad(Math.abs(date.getTimezoneOffset() / 0.6), 4);
+ if (date.getTimezoneOffset() > 0) {
+ tz = '-' + tz;
+ }
+
+ date = new Date(date.valueOf() + date.getTimezoneOffset() * 60000);
+ assert.equal(date.toCLFString(), '01/Jan/2011:01:01:01 ' + tz);
+ }
+ },
+
+ 'can return correctly formatted toFormat': {
+ topic: function () { var topic = new Date(2011, 2, 1);
+ topic.addHours(13)
+ .addMinutes(11)
+ .addSeconds(41)
+ .addMilliseconds(23);
+ return topic;
+ },
+ 'returns correctly': function (date) {
+ assert.equal(date.toFormat('YYYY'), '2011');
+ assert.equal(date.toFormat('YY'), '11');
+ assert.equal(date.toFormat('M'), '3');
+ assert.equal(date.toFormat('MM'), '03');
+ assert.equal(date.toFormat('MMM'), 'Mar');
+ assert.equal(date.toFormat('MMMM'), 'March');
+ assert.equal(date.toFormat('D'), '1');
+ assert.equal(date.toFormat('DD'), '01');
+ assert.equal(date.toFormat('DDD'), 'Tue');
+ assert.equal(date.toFormat('DDDD'), 'Tuesday');
+ assert.equal(date.toFormat('H'), '1');
+ assert.equal(date.toFormat('HH'), '01');
+ assert.equal(date.toFormat('HH24'), '13');
+ assert.equal(date.toFormat('MI'), '11');
+ assert.equal(date.toFormat('SS'), '41');
+ assert.equal(date.toFormat('LL'), '023');
+ },
+
+ 'returns complex formats correct': function (date) {
+ assert.equal(date.toFormat('DDD-MMM-YYYY'), 'Tue-Mar-2011');
+ assert.equal(date.toFormat('DD/MM/YY'), '01/03/11');
+ assert.equal(date.toFormat('D:M:YY'), '1:3:11');
+ }
+ },
+
+ 'can return correctly formatted toUTCFormat': {
+ topic: function () {
+ return topic = new Date(Date.UTC(2011, 2, 1, 13, 11, 41, 23));
+ },
+
+ 'returns correctly': function (date) {
+ assert.equal(date.toUTCFormat('YYYY'), '2011');
+ assert.equal(date.toUTCFormat('YY'), '11');
+ assert.equal(date.toUTCFormat('M'), '3');
+ assert.equal(date.toUTCFormat('MM'), '03');
+ assert.equal(date.toUTCFormat('MMM'), 'Mar');
+ assert.equal(date.toUTCFormat('MMMM'), 'March');
+ assert.equal(date.toUTCFormat('D'), '1');
+ assert.equal(date.toUTCFormat('DD'), '01');
+ assert.equal(date.toUTCFormat('DDD'), 'Tue');
+ assert.equal(date.toUTCFormat('DDDD'), 'Tuesday');
+ assert.equal(date.toUTCFormat('H'), '1');
+ assert.equal(date.toUTCFormat('HH'), '01');
+ assert.equal(date.toUTCFormat('HH24'), '13');
+ assert.equal(date.toUTCFormat('MI'), '11');
+ assert.equal(date.toUTCFormat('SS'), '41');
+ assert.equal(date.toUTCFormat('LL'), '023');
+ },
+
+ 'returns complex formats correct': function (date) {
+ assert.equal(date.toUTCFormat('DDD-MMM-YYYY'), 'Tue-Mar-2011');
+ assert.equal(date.toUTCFormat('DD/MM/YY'), '01/03/11');
+ assert.equal(date.toUTCFormat('D:M:YY'), '1:3:11');
+ }
+ },
+
+ 'can return correct months': {
+ topic: function () { return new Date(2011, 0, 1); },
+ 'returns Jan correcty': function (date) { assert.equal(date.addMonths(0).toFormat('MMM'), 'Jan'); },
+ 'returns Feb correcty': function (date) { assert.equal(date.addMonths(1).toFormat('MMM'), 'Feb'); },
+ 'returns Mar correcty': function (date) { assert.equal(date.addMonths(1).toFormat('MMM'), 'Mar'); },
+ 'returns Apr correcty': function (date) { assert.equal(date.addMonths(1).toFormat('MMM'), 'Apr'); },
+ 'returns May correcty': function (date) { assert.equal(date.addMonths(1).toFormat('MMM'), 'May'); },
+ 'returns Jun correcty': function (date) { assert.equal(date.addMonths(1).toFormat('MMM'), 'Jun'); },
+ 'returns Jul correcty': function (date) { assert.equal(date.addMonths(1).toFormat('MMM'), 'Jul'); },
+ 'returns Aug correcty': function (date) { assert.equal(date.addMonths(1).toFormat('MMM'), 'Aug'); },
+ 'returns Sep correcty': function (date) { assert.equal(date.addMonths(1).toFormat('MMM'), 'Sep'); },
+ 'returns Oct correcty': function (date) { assert.equal(date.addMonths(1).toFormat('MMM'), 'Oct'); },
+ 'returns Nov correcty': function (date) { assert.equal(date.addMonths(1).toFormat('MMM'), 'Nov'); },
+ 'returns Dec correcty': function (date) { assert.equal(date.addMonths(1).toFormat('MMM'), 'Dec'); },
+ },
+
+ 'can return database formatted string': {
+ topic: function () { return new Date(Date.UTC(2011, 0, 1, 1, 1, 1, 0)); },
+ 'returns the correct database string': function (date) {
+ assert.equal(date.toDBString(), '2011-01-01 01:01:01');
+ }
+ },
+
+ 'when passing an argument to toYMD': {
+ topic: function () { return new Date(2011, 0, 1, 1, 1, 1, 0).toYMD('-'); },
+ 'the correct string is returned': function (topic) {
+ assert.equal(topic, '2011-01-01');
+ }
+ },
+
+ 'when passing an empty argument to toYMD': {
+ topic: function () { return new Date(2011, 0, 1, 1, 1, 1, 0).toYMD(''); },
+ 'the correct string is returned': function (topic) {
+ assert.equal(topic, '20110101');
+ }
+ },
+
+ 'when passing no argument to toYMD': {
+ topic: function () { return new Date(2011, 0, 1, 1, 1, 1, 0).toYMD(); },
+ 'the correct default is chosen and the string is returned': function (topic) {
+ assert.equal(topic, '2011-01-01');
+ }
+ }
+
+}).export(module);
diff --git a/node_modules/date-utils/test/date-new-test.js b/node_modules/date-utils/test/date-new-test.js
new file mode 100644
index 0000000..ac00c45
--- /dev/null
+++ b/node_modules/date-utils/test/date-new-test.js
@@ -0,0 +1,105 @@
+var vows = require('vows');
+var assert = require('assert');
+
+require('../lib/date-utils.js');
+
+vows.describe('Date New').addBatch({
+ 'can return a new object from today static method': {
+ topic: function () { return Date.today(); },
+ 'returns the correct time': function (date) {
+ var compare = new Date().clearTime();
+ assert.equal(date.valueOf(), compare.valueOf());
+ }
+ },
+
+ 'clearTime() works': {
+ topic: function() { return new Date().clearTime(); },
+ 'returns the correct value': function (date) {
+ var compare = new Date();
+ compare.setHours(0);
+ compare.setMinutes(0);
+ compare.setSeconds(0);
+ compare.setMilliseconds(0);
+
+ assert.equal(date.valueOf(), compare.valueOf());
+ }
+ },
+
+ 'clearUTCTime() works': {
+ topic: function() { return new Date().clearUTCTime(); },
+ 'returns the correct value': function (date) {
+ var compare = new Date();
+ compare.setUTCHours(0);
+ compare.setUTCMinutes(0);
+ compare.setUTCSeconds(0);
+ compare.setUTCMilliseconds(0);
+
+ assert.equal(date.valueOf(), compare.valueOf());
+ }
+ },
+
+ 'today() works': {
+ topic: function() {
+ return Date.today();
+ },
+ 'returns the correct value': function(date) {
+ var compare = new Date().clearTime();
+ assert.equal(date.valueOf(), compare.valueOf());
+ }
+ },
+
+ 'UTCtoday() works': {
+ topic: function() {
+ return Date.UTCtoday();
+ },
+ 'returns the correct value': function(date) {
+ var compare = new Date().clearUTCTime();
+ assert.equal(date.valueOf(), compare.valueOf());
+ }
+ },
+
+ 'yesterday() works': {
+ topic: function() {
+ return Date.yesterday();
+ },
+ 'returns the correct value': function(date) {
+ var compare = new Date().clearTime();
+ compare.setSeconds(compare.getSeconds() - 86400);
+ assert.equal(date.valueOf(), compare.valueOf());
+ }
+ },
+
+ 'UTCyesterday() works': {
+ topic: function() {
+ return Date.UTCyesterday();
+ },
+ 'returns the correct value': function(date) {
+ var compare = new Date().clearUTCTime();
+ compare.setSeconds(compare.getSeconds() - 86400);
+ assert.equal(date.valueOf(), compare.valueOf());
+ }
+ },
+
+ 'tomorrow() works': {
+ topic: function() {
+ return Date.tomorrow();
+ },
+ 'returns the correct value': function(date) {
+ var compare = new Date().clearTime();
+ compare.setSeconds(compare.getSeconds() + 86400);
+ assert.equal(date.valueOf(), compare.valueOf());
+ }
+ },
+
+ 'UTCtomorrow() works': {
+ topic: function() {
+ return Date.UTCtomorrow();
+ },
+ 'returns the correct value': function(date) {
+ var compare = new Date().clearUTCTime();
+ compare.setSeconds(compare.getSeconds() + 86400);
+ assert.equal(date.valueOf(), compare.valueOf());
+ }
+ }
+
+}).export(module);
\ No newline at end of file
diff --git a/node_modules/date-utils/test/date-parse-test.js b/node_modules/date-utils/test/date-parse-test.js
new file mode 100644
index 0000000..c878e7c
--- /dev/null
+++ b/node_modules/date-utils/test/date-parse-test.js
@@ -0,0 +1,128 @@
+var vows = require('vows');
+var assert = require('assert');
+
+require('../lib/date-utils.js');
+
+vows.describe('Date Parse').addBatch({
+ 'can instantiate milliseconds': {
+ topic: function () { return new Date(123456789); },
+ 'returns a valid date object': function (date) {
+ assert.ok(date);
+ },
+ 'returns a correct value': function (date) {
+ assert.equal(date.valueOf(), 123456789);
+ }
+ },
+
+ 'can instantiate string': {
+ topic: function () { return new Date('Jan 1, 2011 01:01:01 GMT'); },
+ 'returns a valid date object': function (date) {
+ assert.ok(date);
+ },
+ 'returns a correct value': function (date) {
+ assert.equal(date.valueOf(), 1293843661000);
+ }
+ },
+
+ 'can instantiate arguments': {
+ topic: function () { return new Date(2011, 1, 1, 1, 1, 1, 0); },
+ 'returns a valid date object': function (date) {
+ assert.ok(date);
+ }
+ },
+
+ 'can parse normal date': {
+ topic: function () { return Date.parse('Jan 1, 2011 01:01:01 GMT'); },
+ 'returns a correct value': function (milli) {
+ assert.equal(milli, 1293843661000);
+ }
+ },
+ 'can parse ISO-8601': {
+ topic: function () { return Date.parse('2011-01-01T01:01:01Z'); },
+ 'returns a correct value': function (milli) {
+ assert.equal(milli, 1293843661000);
+ }
+ },
+ 'can parse custom format': {
+ topic: function () {
+ return Date.parse('20/6/2011 8:30', 'd/M/y H:m');
+ },
+ 'returns a correct value': function (milli) {
+ var against = new Date(2011, 5, 20, 8, 30, 0);
+ assert.equal(milli, against.valueOf());
+ }
+ },
+ 'parse custom format with full month name': {
+ topic: function () {
+ return Date.parse('June 20, 2011 08:30:00', 'MMM d, y H:m:s');
+ },
+ 'returns a correct value': function (milli) {
+ var against = new Date(2011, 5, 20, 8, 30, 0);
+ assert.equal(milli, against.valueOf());
+ }
+ },
+ 'parse custom format with abbr month name': {
+ topic: function () {
+ return Date.parse('Jun 20, 2011 08:30:00', 'MMM d, y H:m:s');
+ },
+ 'returns a correct value': function (milli) {
+ var against = new Date(2011, 5, 20, 8, 30, 0);
+ assert.equal(milli, against.valueOf());
+ }
+ },
+ 'parse custom format with 12 hr clock': {
+ topic: function () {
+ return Date.parse('June 20, 2011 08:30:00AM', 'MMM d, y h:m:sa');
+ },
+ 'returns a correct value': function (milli) {
+ var against = new Date(2011, 5, 20, 8, 30, 0);
+ assert.equal(milli, against.valueOf());
+ }
+ },
+ 'parse mysql date format': {
+ topic: function () {
+ return Date.parse('2011-06-20 08:30:00', 'y-M-d H:m:s');
+ },
+ 'returns a correct value': function (milli) {
+ var against = new Date(2011, 5, 20, 8, 30, 0);
+ assert.equal(milli, against.valueOf());
+ }
+ },
+ 'parse us date format w/o time': {
+ topic: function () {
+ return Date.parse('6/20/2011', 'M/d/y');
+ },
+ 'returns a correct value': function (milli) {
+ var against = new Date(2011, 5, 20);
+ assert.equal(milli, against.valueOf());
+ }
+ },
+ 'parse us date format with time': {
+ topic: function () {
+ return Date.parse('6/20/2011 00:00:01', 'M/d/y H:m:s');
+ },
+ 'returns a correct value': function (milli) {
+ var against = new Date(2011, 5, 20, 0, 0, 1);
+ assert.equal(milli, against.valueOf());
+ }
+ },
+ 'parse uk date format w/o time': {
+ topic: function () {
+ return Date.parse('20/6/2011', 'd/M/y');
+ },
+ 'returns a correct value': function (milli) {
+ var against = new Date(2011, 5, 20);
+ assert.equal(milli, against.valueOf());
+ }
+ },
+ 'parse uk date format with time': {
+ topic: function () {
+
+ return Date.parse('20/6/2011 00:00:01', 'd/M/y H:m:s');
+ },
+ 'returns a correct value': function (milli) {
+ var against = new Date(2011, 5, 20, 0, 0, 1);
+ assert.equal(milli, against.valueOf());
+ }
+ }
+}).export(module);
diff --git a/node_modules/date-utils/test/date-validate-test.js b/node_modules/date-utils/test/date-validate-test.js
new file mode 100644
index 0000000..5a2e076
--- /dev/null
+++ b/node_modules/date-utils/test/date-validate-test.js
@@ -0,0 +1,573 @@
+var vows = require('vows');
+var assert = require('assert');
+
+require('../lib/date-utils.js');
+
+vows.describe('Date Validate').addBatch({
+ 'can deal with hours': {
+ topic: function () { return Date; },
+ 'false for less than 0': function (topic) {
+ assert.equal(topic.validateHour(-1), false);
+ },
+ 'false for greater than 23': function (topic) {
+ assert.equal(topic.validateHour(24), false);
+ },
+ 'true for in range': function (topic) {
+ assert.equal(topic.validateHour(12), true);
+ }
+ },
+
+ 'can deal with minutes': {
+ topic: function () { return Date; },
+ 'false for less than 0': function (topic) {
+ assert.equal(topic.validateMinute(-1), false);
+ },
+ 'false for greater than 59': function (topic) {
+ assert.equal(topic.validateMinute(60), false);
+ },
+ 'true for in range': function (topic) {
+ assert.equal(topic.validateMinute(30), true);
+ }
+ },
+
+ 'can deal with seconds': {
+ topic: function () { return Date; },
+ 'false for less than 0': function (topic) {
+ assert.equal(topic.validateSecond(-1), false);
+ },
+ 'false for greater than 59': function (topic) {
+ assert.equal(topic.validateSecond(60), false);
+ },
+ 'true for in range': function (topic) {
+ assert.equal(topic.validateSecond(30), true);
+ }
+ },
+
+ 'can deal with milliseconds': {
+ topic: function () { return Date; },
+ 'false for less than 0': function (topic) {
+ assert.equal(topic.validateMillisecond(-1), false);
+ },
+ 'false for greater than 999': function (topic) {
+ assert.equal(topic.validateMillisecond(1000), false);
+ },
+ 'true for in range': function (topic) {
+ assert.equal(topic.validateMillisecond(500), true);
+ }
+ },
+
+ 'can deal with years': {
+ topic: function () { return Date; },
+ 'false for less than 0': function (topic) {
+ assert.equal(topic.validateYear(-1), false);
+ },
+ 'false for greater than 9999': function (topic) {
+ assert.equal(topic.validateYear(10000), false);
+ },
+ 'true for in range': function (topic) {
+ assert.equal(topic.validateYear(5000), true);
+ }
+ },
+
+ 'can deal with days': {
+ topic: function () { return Date; },
+ 'false for less than 0': function (topic) {
+ assert.equal(topic.validateDay(-1, 2011, 12), false);
+ },
+ 'false for greater than 31': function (topic) {
+ assert.equal(topic.validateDay(32, 2011, 12), false);
+ },
+ 'true for in range': function (topic) {
+ assert.equal(topic.validateDay(10, 2011, 11), true);
+ }
+ },
+
+ 'static compare works': {
+ topic: function () { return Date.today(); },
+ '-1 for yesterday': function (topic) {
+ assert.equal(Date.compare(Date.yesterday(), topic), -1);
+ },
+ '1 for tomorrow': function (topic) {
+ assert.equal(Date.compare(Date.tomorrow(), topic), 1);
+ },
+ '0 for today': function (topic) {
+ assert.equal(Date.compare(Date.today(), topic), 0);
+ }
+ },
+
+ 'static equals works': {
+ topic: function () { return Date.today(); },
+ 'equal for today': function (topic) {
+ assert.equal(Date.equals(topic, Date.today()), true);
+ },
+ 'false for tomorrow': function (topic) {
+ assert.equal(Date.equals(topic, Date.tomorrow()), false);
+ },
+ 'false for yesterday': function (topic) {
+ assert.equal(Date.equals(topic, Date.yesterday()), false);
+ }
+ },
+
+ 'getDayNumberFromName works': {
+ topic: function () { return Date; },
+ 'sunday works': function (topic) {
+ assert.equal(topic.getDayNumberFromName('sunday'), 0);
+ },
+ 'sun works': function (topic) {
+ assert.equal(topic.getDayNumberFromName('sun'), 0);
+ },
+ 'su works': function (topic) {
+ assert.equal(topic.getDayNumberFromName('su'), 0);
+ },
+ 'monday works': function (topic) {
+ assert.equal(topic.getDayNumberFromName('monday'), 1);
+ },
+ 'mon works': function (topic) {
+ assert.equal(topic.getDayNumberFromName('mon'), 1);
+ },
+ 'mo works': function (topic) {
+ assert.equal(topic.getDayNumberFromName('mo'), 1);
+ },
+ 'tuesday works': function (topic) {
+ assert.equal(topic.getDayNumberFromName('tuesday'), 2);
+ },
+ 'tue works': function (topic) {
+ assert.equal(topic.getDayNumberFromName('tue'), 2);
+ },
+ 'tu works': function (topic) {
+ assert.equal(topic.getDayNumberFromName('tu'), 2);
+ },
+ 'wednesday works': function (topic) {
+ assert.equal(topic.getDayNumberFromName('wednesday'), 3);
+ },
+ 'wed works': function (topic) {
+ assert.equal(topic.getDayNumberFromName('wed'), 3);
+ },
+ 'we works': function (topic) {
+ assert.equal(topic.getDayNumberFromName('we'), 3);
+ },
+ 'thursday works': function (topic) {
+ assert.equal(topic.getDayNumberFromName('thursday'), 4);
+ },
+ 'thu works': function (topic) {
+ assert.equal(topic.getDayNumberFromName('thu'), 4);
+ },
+ 'th works': function (topic) {
+ assert.equal(topic.getDayNumberFromName('th'), 4);
+ },
+ 'friday works': function (topic) {
+ assert.equal(topic.getDayNumberFromName('friday'), 5);
+ },
+ 'fri works': function (topic) {
+ assert.equal(topic.getDayNumberFromName('fri'), 5);
+ },
+ 'fr works': function (topic) {
+ assert.equal(topic.getDayNumberFromName('fr'), 5);
+ },
+ 'saturday works': function (topic) {
+ assert.equal(topic.getDayNumberFromName('saturday'), 6);
+ },
+ 'sat works': function (topic) {
+ assert.equal(topic.getDayNumberFromName('sat'), 6);
+ },
+ 'sa works': function (topic) {
+ assert.equal(topic.getDayNumberFromName('sa'), 6);
+ },
+ 'everything else does not': function (topic) {
+ assert.equal(topic.getDayNumberFromName('junk'), undefined);
+ }
+ },
+
+ 'getMonthNumberFromName works': {
+ topic: function () { return Date; },
+ 'january works': function (topic) {
+ assert.equal(topic.getMonthNumberFromName('january'), 0);
+ },
+ 'jan works': function (topic) {
+ assert.equal(topic.getMonthNumberFromName('jan'), 0);
+ },
+ 'february works': function (topic) {
+ assert.equal(topic.getMonthNumberFromName('february'), 1);
+ },
+ 'feb works': function (topic) {
+ assert.equal(topic.getMonthNumberFromName('feb'), 1);
+ },
+ 'march works': function (topic) {
+ assert.equal(topic.getMonthNumberFromName('march'), 2);
+ },
+ 'mar works': function (topic) {
+ assert.equal(topic.getMonthNumberFromName('mar'), 2);
+ },
+ 'april works': function (topic) {
+ assert.equal(topic.getMonthNumberFromName('april'), 3);
+ },
+ 'apr works': function (topic) {
+ assert.equal(topic.getMonthNumberFromName('apr'), 3);
+ },
+ 'may works': function (topic) {
+ assert.equal(topic.getMonthNumberFromName('may'), 4);
+ },
+ 'june works': function (topic) {
+ assert.equal(topic.getMonthNumberFromName('june'), 5);
+ },
+ 'jun works': function (topic) {
+ assert.equal(topic.getMonthNumberFromName('jun'), 5);
+ },
+ 'july works': function (topic) {
+ assert.equal(topic.getMonthNumberFromName('july'), 6);
+ },
+ 'jul works': function (topic) {
+ assert.equal(topic.getMonthNumberFromName('jul'), 6);
+ },
+ 'august works': function (topic) {
+ assert.equal(topic.getMonthNumberFromName('august'), 7);
+ },
+ 'aug works': function (topic) {
+ assert.equal(topic.getMonthNumberFromName('aug'), 7);
+ },
+ 'september works': function (topic) {
+ assert.equal(topic.getMonthNumberFromName('september'), 8);
+ },
+ 'sep works': function (topic) {
+ assert.equal(topic.getMonthNumberFromName('sep'), 8);
+ },
+ 'october works': function (topic) {
+ assert.equal(topic.getMonthNumberFromName('october'), 9);
+ },
+ 'oct works': function (topic) {
+ assert.equal(topic.getMonthNumberFromName('oct'), 9);
+ },
+ 'november works': function (topic) {
+ assert.equal(topic.getMonthNumberFromName('november'), 10);
+ },
+ 'nov works': function (topic) {
+ assert.equal(topic.getMonthNumberFromName('nov'), 10);
+ },
+ 'december works': function (topic) {
+ assert.equal(topic.getMonthNumberFromName('december'), 11);
+ },
+ 'dec works': function (topic) {
+ assert.equal(topic.getMonthNumberFromName('dec'), 11);
+ }
+ },
+
+ 'can add milliseconds': {
+ 'adding positive milliseconds works': function () {
+ var topic = Date.today();
+ topic.addMilliseconds(500);
+ assert.equal(topic.getMilliseconds(), 500);
+ },
+ 'adding negative milliseconds works': function () {
+ var topic = Date.today();
+ topic.addMilliseconds(500);
+ assert.equal(topic.getMilliseconds(), 500);
+ topic.addMilliseconds(-250);
+ assert.equal(topic.getMilliseconds(), 250);
+ }
+ },
+
+ 'can add seconds': {
+ 'adding positive seconds works': function () {
+ var topic = Date.today();
+ topic.addSeconds(50);
+ assert.equal(topic.getSeconds(), 50);
+ },
+ 'adding negative seconds works': function () {
+ var topic = Date.today();
+ topic.addSeconds(50);
+ assert.equal(topic.getSeconds(), 50);
+ topic.addSeconds(-25);
+ assert.equal(topic.getSeconds(), 25);
+ }
+ },
+
+ 'can add minutes': {
+ 'adding positive minutes works': function () {
+ var topic = Date.today();
+ topic.addMinutes(50);
+ assert.equal(topic.getMinutes(), 50);
+ },
+ 'adding negative minutes works': function () {
+ var topic = Date.today();
+ topic.addMinutes(50);
+ assert.equal(topic.getMinutes(), 50);
+ topic.addMinutes(-25);
+ assert.equal(topic.getMinutes(), 25);
+ }
+ },
+
+ 'can add hours': {
+ 'adding positive hours works': function () {
+ var topic = Date.today();
+ topic.addHours(5);
+ assert.equal(topic.getHours(), 5);
+ },
+ 'adding negative hours works': function () {
+ var topic = Date.today();
+ topic.addHours(5);
+ assert.equal(topic.getHours(), 5);
+ topic.addHours(-2);
+ assert.equal(topic.getHours(), 3);
+ }
+ },
+
+ 'can add days': {
+ 'adding positive days works': function () {
+ var topic = new Date(2011, 0, 10);
+ topic.addDays(1);
+ assert.equal(topic.getDate(), 11);
+ },
+ 'adding negative days works': function () {
+ var topic = new Date(2011, 0, 10);
+ topic.addDays(1);
+ assert.equal(topic.getDate(), 11);
+ topic.addDays(-2);
+ assert.equal(topic.getDate(), 9);
+ }
+ },
+
+ 'can add weeks': {
+ 'adding positive weeks works': function () {
+ var topic = new Date(2011, 0, 10);
+ topic.addWeeks(1);
+ assert.equal(topic.getDate(), 17);
+ },
+ 'adding negative weeks works': function () {
+ var topic = new Date(2011, 0, 10);
+ topic.addWeeks(1);
+ assert.equal(topic.getDate(), 17);
+ topic.addWeeks(-2);
+ assert.equal(topic.getDate(), 3);
+ }
+ },
+
+ 'can add months': {
+ 'adding positive months works': function () {
+ var topic = new Date(2011, 1, 10);
+ topic.addMonths(1);
+ assert.equal(topic.getMonth(), 2);
+ },
+ 'adding negative months works': function () {
+ var topic = new Date(2011, 1, 10);
+ topic.addMonths(1);
+ assert.equal(topic.getMonth(), 2);
+ topic.addMonths(-2);
+ assert.equal(topic.getMonth(), 0);
+ }
+ },
+
+ 'can set time to now': {
+ 'setting time to now works': function () {
+ var topic = Date.today();
+ topic.setTimeToNow();
+ var now = new Date();
+
+ // hokey, but should be sufficient
+ assert.equal((now.valueOf() - topic.valueOf() < 100), true);
+ }
+ },
+
+ 'can clone time': {
+ topic: function () { return new Date(); },
+ 'clone works': function (topic) {
+ var clone = topic.clone();
+ assert.equal(clone.valueOf(), topic.valueOf());
+ }
+ },
+
+ 'between works': {
+ 'between returns true for valid start and end': function () {
+ var today = Date.today();
+ var yesterday = Date.yesterday();
+ var tomorrow = Date.tomorrow();
+ assert.equal(today.between(yesterday, tomorrow), true);
+ },
+ 'between returns false for invalid start and end': function () {
+ var today = Date.today();
+ var yesterday = Date.yesterday();
+ var tomorrow = Date.tomorrow();
+ assert.equal(today.between(tomorrow, yesterday), false);
+ }
+ },
+
+ 'compareTo works': {
+ topic: function () { return Date.today(); },
+ '-1 for tomorrow': function (topic) {
+ assert.equal(topic.compareTo(Date.tomorrow()), -1);
+ },
+ '1 for yesterday': function (topic) {
+ assert.equal(topic.compareTo(Date.yesterday()), 1);
+ },
+ '0 for today': function (topic) {
+ assert.equal(topic.compareTo(Date.today()), 0);
+ }
+ },
+
+
+ 'equals instance works': {
+ topic: function () { return Date.today(); },
+ 'true for equal': function (topic) {
+ assert.equal(topic.equals(Date.today()), true);
+ },
+ 'false for not equal': function (topic) {
+ assert.equal(topic.equals(Date.tomorrow()), false);
+ }
+ },
+
+ 'isBefore works': {
+ topic: function () { return Date.today(); },
+ 'true for before': function (topic) {
+ assert.equal(topic.isBefore(Date.tomorrow()), true);
+ },
+ 'false for after': function (topic) {
+ assert.equal(topic.isBefore(Date.yesterday()), false);
+ }
+ },
+
+ 'isAfter works': {
+ topic: function () { return Date.today(); },
+ 'false for before': function (topic) {
+ assert.equal(topic.isAfter(Date.tomorrow()), false);
+ },
+ 'true for after': function (topic) {
+ assert.equal(topic.isAfter(Date.yesterday()), true);
+ }
+ },
+
+ 'getDaysBetween works': {
+ topic: function () { return Date.today(); },
+ '1 for tomorrow': function (topic) {
+ assert.equal(topic.getDaysBetween(Date.tomorrow()), 1);
+ },
+ '-1 for yesterday': function (topic) {
+ assert.equal(topic.getDaysBetween(Date.yesterday()), -1);
+ },
+ '0 for today': function (topic) {
+ assert.equal(topic.getDaysBetween(Date.today()), 0);
+ }
+ },
+
+ 'getDaysBetween works for beginning of year': {
+ topic: function () { return new Date('Jan 1, 2011 01:01:01 GMT'); },
+ 'should return 0 for the same day': function (topic) {
+ var date = new Date('Jan 1, 2011 01:01:01 GMT');
+ assert.equal(topic.getDaysBetween(date), 0);
+ },
+ 'should return 1 for tomorrow': function (topic) {
+ var date = new Date('Jan 2, 2011 01:01:01 GMT');
+ assert.equal(topic.getDaysBetween(date), 1);
+ }
+ },
+
+ 'getMinutesBetween works': {
+ topic: function () { return new Date('Jan 1, 2011 23:31:01 GMT'); },
+ '10 for 10 minutes': function (topic) {
+ assert.equal(topic.getMinutesBetween(new Date('Jan 1, 2011 23:41:01 GMT')), 10);
+ },
+ '-10 for 10 minutes ago': function (topic) {
+ assert.equal(topic.getMinutesBetween(new Date('Jan 1, 2011 23:21:01 GMT')), -10);
+ },
+ '0 for same minute': function (topic) {
+ assert.equal(topic.getMinutesBetween(new Date('Jan 1, 2011 23:31:01 GMT')), 0);
+ },
+ 'for time difference that spans days': function (topic) {
+ assert.equal(topic.getMinutesBetween(new Date('Jan 2, 2011 00:01:01 GMT')), 30);
+ }
+ },
+
+ 'getSecondsBetween works': {
+ topic: function () { return new Date('Jan 1, 2011 23:31:01 GMT'); },
+ '10 for 10 seconds': function (topic) {
+ assert.equal(topic.getSecondsBetween(new Date('Jan 1, 2011 23:31:11 GMT')), 10);
+ },
+ '-10 for 10 seconds ago': function (topic) {
+ assert.equal(topic.getSecondsBetween(new Date('Jan 1, 2011 23:30:51 GMT')), -10);
+ },
+ '0 for same second': function (topic) {
+ assert.equal(topic.getSecondsBetween(new Date('Jan 1, 2011 23:31:01 GMT')), 0);
+ }
+ },
+
+ 'getMillisecondsBetween works': {
+ topic: function () { return new Date(); },
+ '10 for 10 milliseconds': function (topic) {
+ assert.equal(topic.getMillisecondsBetween(new Date(+topic + 10)), 10);
+ },
+ '-10 for 10 milliseconds ago': function (topic) {
+ assert.equal(topic.getMillisecondsBetween(new Date(+topic - 10)), -10);
+ },
+ '0 for same millisecond': function (topic) {
+ assert.equal(topic.getMillisecondsBetween(new Date(+topic)), 0);
+ }
+ },
+
+ 'getHoursBetween works': {
+ topic: function () { return new Date('Jan 1, 2011 23:31:01 GMT'); },
+ '1 for 1 hour': function (topic) {
+ assert.equal(topic.getHoursBetween(new Date('Jan 2, 2011 00:31:01 GMT')), 1);
+ },
+ '-1 for 1 hour ago': function (topic) {
+ assert.equal(topic.getHoursBetween(new Date('Jan 1, 2011 22:31:01 GMT')), -1);
+ },
+ '0 for same hour': function (topic) {
+ assert.equal(topic.getHoursBetween(new Date('Jan 1, 2011 23:31:01 GMT')), 0);
+ }
+ },
+
+ 'getOrdinalNumber works': {
+ 'returns correct day': function () {
+ var date = new Date('02-01-2011');
+ assert.equal(date.getOrdinalNumber(), 32);
+ }
+ },
+
+ 'getOrdinalNumber works for january 1st': {
+ 'returns correct day': function () {
+ var date = new Date('01-01-2011');
+ assert.equal(date.getOrdinalNumber(), 1);
+ }
+ },
+
+ 'getDaysInMonth works': {
+ 'january': function (topic) {
+ assert.equal(Date.getDaysInMonth(2011, 0), 31);
+ },
+ 'february': function (topic) {
+ assert.equal(Date.getDaysInMonth(2011, 1), 28);
+ },
+ 'february leap year': function (topic) {
+ assert.equal(Date.getDaysInMonth(2008, 1), 29);
+ },
+ 'march': function (topic) {
+ assert.equal(Date.getDaysInMonth(2011, 2), 31);
+ },
+ 'april': function (topic) {
+ assert.equal(Date.getDaysInMonth(2011, 3), 30);
+ },
+ 'may': function (topic) {
+ assert.equal(Date.getDaysInMonth(2011, 4), 31);
+ },
+ 'june': function (topic) {
+ assert.equal(Date.getDaysInMonth(2011, 5), 30);
+ },
+ 'july': function (topic) {
+ assert.equal(Date.getDaysInMonth(2011, 6), 31);
+ },
+ 'august': function (topic) {
+ assert.equal(Date.getDaysInMonth(2011, 7), 31);
+ },
+ 'september': function (topic) {
+ assert.equal(Date.getDaysInMonth(2011, 8), 30);
+ },
+ 'october': function (topic) {
+ assert.equal(Date.getDaysInMonth(2011, 9), 31);
+ },
+ 'november': function (topic) {
+ assert.equal(Date.getDaysInMonth(2011, 10), 30);
+ },
+ 'december': function (topic) {
+ assert.equal(Date.getDaysInMonth(2011, 11), 31);
+ }
+ }
+
+}).export(module);
diff --git a/public/javascripts/newexercisevalidation.js b/public/javascripts/newexercisevalidation.js
index 453ca54..bd6a315 100644
--- a/public/javascripts/newexercisevalidation.js
+++ b/public/javascripts/newexercisevalidation.js
@@ -1,73 +1,57 @@
$(document).ready(function() {
////Validation
- var name = new LiveValidation('name');
- name.add( Validate.Format, { pattern: /^\s*[a-zA-Z0-9,\s]+\s*$/ } );
- name.add( Validate.Length, { minimum: 3, maximum: 12 , failureMessage: "Please enter a valid name" } );
- name.add( Validate.Presence );
+$("#newexercise").validate({
+ rules: {
+ name: {
+ required: true,
+ remote: {
+ cache:false,
+ async:false,
+ dataType: 'json',
+ url: "/admin/exercises",
+ type: "post",
+ data: {
+ name: function() {
+ return $("#name").val();
+ }
+ },
+ dataFilter: function(data) {
+ return (JSON.parse(data).name);
+ }
+ }
+ },
+ difficulty: {
+ required: true,
+ digits: true,
+ range: [1, 10]
+ },
+ description: {
+ required: true,
+ maxlength: 24
+ },
+ type: {
+ notEqual: "notselected",
+ required: true
+ }
+ },
+ messages: {
+ name: {
+ required: "Please enter an exercise name",
+ remote: "Name already taken"
+ }
+ }
+});
- var type = new LiveValidation('type');
- type.add( Validate.Exclusion, { within: ['notselected', 'Select One'], failureMessage: "Please select an entry from the list" } );
- type.add( Validate.Presence );
- var difficulty = new LiveValidation('difficulty');
- difficulty.add( Validate.Numericality, { minimum: 1, maximum: 10, onlyInteger: true, failureMessage: "Must be a number between 1 and 10" });
- difficulty.add( Validate.Presence );
- var description = new LiveValidation('description');
- description.add( Validate.Format, { pattern: /^\s*[a-zA-Z0-9,\s]+\s*$/ } );
- description.add( Validate.Presence );
- var musclearray0 = new LiveValidation('musclearray[0]');
- musclearray0.add( Validate.Numericality, { minimum: 1, maximum: 10, onlyInteger: true, failureMessage: "Must be a number between 1 and 10" });
- musclearray0.add( Validate.Presence );
- var musclearray1 = new LiveValidation('musclearray[1]');
- musclearray1.add( Validate.Numericality, { minimum: 1, maximum: 10, onlyInteger: true, failureMessage: "Must be a number between 1 and 10" });
- musclearray1.add( Validate.Presence );
- var musclearray2 = new LiveValidation('musclearray[2]');
- musclearray2.add( Validate.Numericality, { minimum: 1, maximum: 10, onlyInteger: true, failureMessage: "Must be a number between 1 and 10" });
- musclearray2.add( Validate.Presence );
- var musclearray3 = new LiveValidation('musclearray[3]');
- musclearray3.add( Validate.Numericality, { minimum: 1, maximum: 10, onlyInteger: true, failureMessage: "Must be a number between 1 and 10" });
- musclearray3.add( Validate.Presence );
- var musclearray4 = new LiveValidation('musclearray[4]');
- musclearray4.add( Validate.Numericality, { minimum: 1, maximum: 10, onlyInteger: true, failureMessage: "Must be a number between 1 and 10" });
- musclearray4.add( Validate.Presence );
- var musclearray5 = new LiveValidation('musclearray[5]');
- musclearray5.add( Validate.Numericality, { minimum: 1, maximum: 10, onlyInteger: true, failureMessage: "Must be a number between 1 and 10" });
- musclearray5.add( Validate.Presence );
- var musclearray6 = new LiveValidation('musclearray[6]');
- musclearray6.add( Validate.Numericality, { minimum: 1, maximum: 10, onlyInteger: true, failureMessage: "Must be a number between 1 and 10" });
- musclearray6.add( Validate.Presence );
- var musclearray7 = new LiveValidation('musclearray[7]');
- musclearray7.add( Validate.Numericality, { minimum: 1, maximum: 10, onlyInteger: true, failureMessage: "Must be a number between 1 and 10" });
- musclearray7.add( Validate.Presence );
- var musclearray8 = new LiveValidation('musclearray[8]');
- musclearray8.add( Validate.Numericality, { minimum: 1, maximum: 10, onlyInteger: true, failureMessage: "Must be a number between 1 and 10" });
- musclearray8.add( Validate.Presence );
- var musclearray9 = new LiveValidation('musclearray[9]');
- musclearray9.add( Validate.Numericality, { minimum: 1, maximum: 10, onlyInteger: true, failureMessage: "Must be a number between 1 and 10" });
- musclearray9.add( Validate.Presence );
-
-// Pass a function that checks if a number is divisible by one that you pass it in args object
-// In this case, 5 is passed, so should return true and validation will pass
-//Validate.Custom( 55, { against: function(value,args){ return !(value % args.divisibleBy) }, args: {divisibleBy: 5} } );
-
-// $.ajax({
-// type: 'get',
-// url: '/admin/exercises/',
-// data: { name: 'Cheddar'}
-// });
-
-
-// $.getJSON('admin/exercise', function(data) {
-// var items = [];
-
-// $.each(data, function(key, val) {
-// items.push('' + val + '');
-// });
-
-// $('', {
-// 'class': 'my-new-list',
-// html: items.join('')
-// }).appendTo('body');
-// });
+$(".musclearray").each(function(){
+ $(this).rules("add", {
+ required: true,
+ digits: true,
+ range: [1, 10],
+ messages: {
+ required: "Muscle Array values must be betwen 1 and 10"
+ }
+ });
+ });
diff --git a/public/javascripts/scripts.js b/public/javascripts/scripts.js
index 0ee8a61..84e4205 100644
--- a/public/javascripts/scripts.js
+++ b/public/javascripts/scripts.js
@@ -65,5 +65,12 @@ $(document).ready(function() {
+
+jQuery.validator.addMethod("notEqual", function(value, element, param) {
+ return this.optional(element) || value != param;
+},"Please select a value");
+
+
+
});
diff --git a/routes/admin.js b/routes/admin.js
index bf1df3c..fdedfd8 100644
--- a/routes/admin.js
+++ b/routes/admin.js
@@ -101,7 +101,7 @@ app.get('/admin/exercises', loggedIn, isAdmin, function(req, res, next){
});
- app.post('/admin/exercises', function(req, res, next) {
+ app.post('/admin/exercises/new', function(req, res, next) {
console.log("/nreq.body" + JSON.stringify(req.body));
var exercise = req.body;
Exercise.create(exercise, function(err) {
@@ -136,6 +136,24 @@ app.get('/admin/exercises', loggedIn, isAdmin, function(req, res, next){
});
});
+ app.post('/admin/exercises', function(req, res) {
+ res.contentType('json');
+ Exercise.findOne({name: req.body.name})
+ .exec(function(err, exercise) {
+ if (err) {
+ return next(err);
+ }
+ if (! exercise) {
+ console.log("Failure" + JSON.stringify({ success : false }));
+ return res.send(JSON.stringify({ "name": "true" }));
+ }
+ //req.exercise = exercise;
+
+ console.log("Success" + exercise.name);
+ res.send(JSON.stringify({ "name": "false" }));
+ });
+ });
+
//////////////////////////////////////////
diff --git a/views/admin/newexercise.jade b/views/admin/newexercise.jade
index 7ebdd66..344e381 100644
--- a/views/admin/newexercise.jade
+++ b/views/admin/newexercise.jade
@@ -1,25 +1,25 @@
extends ../layout
block additionalscripts
- script(src='/javascripts/newexercisevalidation.js')
+ script(src='/javascripts/newexercisevalidation.js')
block content
h1 New Exercise
- form(method="POST", action="/admin/exercises")
+ form(id="newexercise", method="POST", action="/admin/exercises/new")
ul
li
- label(for="name") Exercise Name
Need to add check to ensure we donbt get duplicate names
+ label(for="name") Exercise Name
input#name(name="name")
li
label(for="type") Exercise Type
select#type(name="type")
option(value='notselected') Select One
option(value='freeweights') Free Weights
- option(value='0130') Exercise Machines
- option(value='0200') Bodyweight
- option(value='0200') Kettlebells
- option(value='0200') Cardio
+ option(value='machine') Exercise Machines
+ option(value='bodyweight') Bodyweight
+ option(value='kettlebells') Kettlebells
+ option(value='cardio') Cardio
li
label(for="type") Exercise Description
@@ -32,7 +32,7 @@ block content
marray = "musclearray[" + i + "]"
li
label(for="type") Muscle data #{i}
- input(name= marray, class= marray, id= marray)
+ input(name= marray, class="musclearray", id= marray)
- }
li
label(for="type") Keywords
diff --git a/views/admin/newexercisevalidation.jade b/views/admin/newexercisevalidation.jade
deleted file mode 100644
index 7a635e0..0000000
--- a/views/admin/newexercisevalidation.jade
+++ /dev/null
@@ -1,14 +0,0 @@
-/script(
- $(document).ready(function() {
- ////Validation
- var name = new LiveValidation('name');
- name.add( Validate.Format, { pattern: /^\s*[a-zA-Z0-9,\s]+\s*$/ } );
- name.add( Validate.Length, { minimum: 3, maximum: 12 , failureMessage: "Please enter a valid name" } );
- var type = new LiveValidation('type');
- type.add( Validate.Exclusion, { within: ['notselected', 'Select One'], failureMessage: "Please select an entry from the list" } );
- var difficulty = new LiveValidation('difficulty');
- difficulty.add( Validate.Numericality, { minimum: 1, maximum: 10, onlyInteger: true, failureMessage: "Must be a number between 1 and 10" });
- var description = new LiveValidation('description');
- description.add( Validate.Format, { pattern: /^\s*[a-zA-Z0-9,\s]+\s*$/ } );
- });
-/)
\ No newline at end of file