text: // moment.js
  // version : 2.0.0
  // author : Tim Wood
  // license : MIT
  // momentjs.com
  define("gallery/moment/2.0.0/moment-debug", [], function(require, exports, module) {
      /************************************
          Constants
      ************************************/
      var moment, VERSION = "2.0.0", round = Math.round, i, // internal storage for language config files
      languages = {}, // check for nodeJS
      hasModule = typeof module !== "undefined" && module.exports, // ASP.NET json date format regex
      aspNetJsonRegex = /^\/?Date\((\-?\d+)/i, // format tokens
      formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|YYYYY|YYYY|YY|a|A|hh?|HH?|mm?|ss?|SS?S?|X|zz?|ZZ?|.)/g, localFormattingTokens = /(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g, // parsing tokens
      parseMultipleFormatChunker = /([0-9a-zA-Z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+)/gi, // parsing token regexes
      parseTokenOneOrTwoDigits = /\d\d?/, // 0 - 99
      parseTokenOneToThreeDigits = /\d{1,3}/, // 0 - 999
      parseTokenThreeDigits = /\d{3}/, // 000 - 999
      parseTokenFourDigits = /\d{1,4}/, // 0 - 9999
      parseTokenSixDigits = /[+\-]?\d{1,6}/, // -999,999 - 999,999
      parseTokenWord = /[0-9]*[a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF]+\s*?[\u0600-\u06FF]+/i, // any word (or two) characters or numbers including two word month in arabic.
      parseTokenTimezone = /Z|[\+\-]\d\d:?\d\d/i, // +00:00 -00:00 +0000 -0000 or Z
      parseTokenT = /T/i, // T (ISO seperator)
      parseTokenTimestampMs = /[\+\-]?\d+(\.\d{1,3})?/, // 123456789 123456789.123
      // preliminary iso regex
      // 0000-00-00 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000
      isoRegex = /^\s*\d{4}-\d\d-\d\d((T| )(\d\d(:\d\d(:\d\d(\.\d\d?\d?)?)?)?)?([\+\-]\d\d:?\d\d)?)?/, isoFormat = "YYYY-MM-DDTHH:mm:ssZ", // iso time formats and regexes
      isoTimes = [ [ "HH:mm:ss.S", /(T| )\d\d:\d\d:\d\d\.\d{1,3}/ ], [ "HH:mm:ss", /(T| )\d\d:\d\d:\d\d/ ], [ "HH:mm", /(T| )\d\d:\d\d/ ], [ "HH", /(T| )\d\d/ ] ], // timezone chunker "+10:00" > ["10", "00"] or "-1530" > ["-15", "30"]
      parseTimezoneChunker = /([\+\-]|\d\d)/gi, // getter and setter names
      proxyGettersAndSetters = "Month|Date|Hours|Minutes|Seconds|Milliseconds".split("|"), unitMillisecondFactors = {
          Milliseconds: 1,
          Seconds: 1e3,
          Minutes: 6e4,
          Hours: 36e5,
          Days: 864e5,
          Months: 2592e6,
          Years: 31536e6
      }, // format function strings
      formatFunctions = {}, // tokens to ordinalize and pad
      ordinalizeTokens = "DDD w W M D d".split(" "), paddedTokens = "M D H h m s w W".split(" "), formatTokenFunctions = {
          M: function() {
              return this.month() + 1;
          },
          MMM: function(format) {
              return this.lang().monthsShort(this, format);
          },
          MMMM: function(format) {
              return this.lang().months(this, format);
          },
          D: function() {
              return this.date();
          },
          DDD: function() {
              return this.dayOfYear();
          },
          d: function() {
              return this.day();
          },
          dd: function(format) {
              return this.lang().weekdaysMin(this, format);
          },
          ddd: function(format) {
              return this.lang().weekdaysShort(this, format);
          },
          dddd: function(format) {
              return this.lang().weekdays(this, format);
          },
          w: function() {
              return this.week();
          },
          W: function() {
              return this.isoWeek();
          },
          YY: function() {
              return leftZeroFill(this.year() % 100, 2);
          },
          YYYY: function() {
              return leftZeroFill(this.year(), 4);
          },
          YYYYY: function() {
              return leftZeroFill(this.year(), 5);
          },
          a: function() {
              return this.lang().meridiem(this.hours(), this.minutes(), true);
          },
          A: function() {
              return this.lang().meridiem(this.hours(), this.minutes(), false);
          },
          H: function() {
              return this.hours();
          },
          h: function() {
              return this.hours() % 12 || 12;
          },
          m: function() {
              return this.minutes();
          },
          s: function() {
              return this.seconds();
          },
          S: function() {
              return ~~(this.milliseconds() / 100);
          },
          SS: function() {
              return leftZeroFill(~~(this.milliseconds() / 10), 2);
          },
          SSS: function() {
              return leftZeroFill(this.milliseconds(), 3);
          },
          Z: function() {
              var a = -this.zone(), b = "+";
              if (a < 0) {
                  a = -a;
                  b = "-";
              }
              return b + leftZeroFill(~~(a / 60), 2) + ":" + leftZeroFill(~~a % 60, 2);
          },
          ZZ: function() {
              var a = -this.zone(), b = "+";
              if (a < 0) {
                  a = -a;
                  b = "-";
              }
              return b + leftZeroFill(~~(10 * a / 6), 4);
          },
          X: function() {
              return this.unix();
          }
      };
      function padToken(func, count) {
          return function(a) {
              return leftZeroFill(func.call(this, a), count);
          };
      }
      function ordinalizeToken(func) {
          return function(a) {
              return this.lang().ordinal(func.call(this, a));
          };
      }
      while (ordinalizeTokens.length) {
          i = ordinalizeTokens.pop();
          formatTokenFunctions[i + "o"] = ordinalizeToken(formatTokenFunctions[i]);
      }
      while (paddedTokens.length) {
          i = paddedTokens.pop();
          formatTokenFunctions[i + i] = padToken(formatTokenFunctions[i], 2);
      }
      formatTokenFunctions.DDDD = padToken(formatTokenFunctions.DDD, 3);
      /************************************
          Constructors
      ************************************/
      function Language() {}
      // Moment prototype object
      function Moment(config) {
          extend(this, config);
      }
      // Duration Constructor
      function Duration(duration) {
          var data = this._data = {}, years = duration.years || duration.year || duration.y || 0, months = duration.months || duration.month || duration.M || 0, weeks = duration.weeks || duration.week || duration.w || 0, days = duration.days || duration.day || duration.d || 0, hours = duration.hours || duration.hour || duration.h || 0, minutes = duration.minutes || duration.minute || duration.m || 0, seconds = duration.seconds || duration.second || duration.s || 0, milliseconds = duration.milliseconds || duration.millisecond || duration.ms || 0;
          // representation for dateAddRemove
          this._milliseconds = milliseconds + seconds * 1e3 + // 1000
          minutes * 6e4 + // 1000 * 60
          hours * 36e5;
          // 1000 * 60 * 60
          // Because of dateAddRemove treats 24 hours as different from a
          // day when working around DST, we need to store them separately
          this._days = days + weeks * 7;
          // It is impossible translate months into days without knowing
          // which months you are are talking about, so we have to store
          // it separately.
          this._months = months + years * 12;
          // The following code bubbles up values, see the tests for
          // examples of what that means.
          data.milliseconds = milliseconds % 1e3;
          seconds += absRound(milliseconds / 1e3);
          data.seconds = seconds % 60;
          minutes += absRound(seconds / 60);
          data.minutes = minutes % 60;
          hours += absRound(minutes / 60);
          data.hours = hours % 24;
          days += absRound(hours / 24);
          days += weeks * 7;
          data.days = days % 30;
          months += absRound(days / 30);
          data.months = months % 12;
          years += absRound(months / 12);
          data.years = years;
      }
      /************************************
          Helpers
      ************************************/
      function extend(a, b) {
          for (var i in b) {
              if (b.hasOwnProperty(i)) {
                  a[i] = b[i];
              }
          }
          return a;
      }
      function absRound(number) {
          if (number < 0) {
              return Math.ceil(number);
          } else {
              return Math.floor(number);
          }
      }
      // left zero fill a number
      // see http://jsperf.com/left-zero-filling for performance comparison
      function leftZeroFill(number, targetLength) {
          var output = number + "";
          while (output.length < targetLength) {
              output = "0" + output;
          }
          return output;
      }
      // helper function for _.addTime and _.subtractTime
      function addOrSubtractDurationFromMoment(mom, duration, isAdding) {
          var ms = duration._milliseconds, d = duration._days, M = duration._months, currentDate;
          if (ms) {
              mom._d.setTime(+mom + ms * isAdding);
          }
          if (d) {
              mom.date(mom.date() + d * isAdding);
          }
          if (M) {
              currentDate = mom.date();
              mom.date(1).month(mom.month() + M * isAdding).date(Math.min(currentDate, mom.daysInMonth()));
          }
      }
      // check if is an array
      function isArray(input) {
          return Object.prototype.toString.call(input) === "[object Array]";
      }
      // compare two arrays, return the number of differences
      function compareArrays(array1, array2) {
          var len = Math.min(array1.length, array2.length), lengthDiff = Math.abs(array1.length - array2.length), diffs = 0, i;
          for (i = 0; i < len; i++) {
              if (~~array1[i] !== ~~array2[i]) {
                  diffs++;
              }
          }
          return diffs + lengthDiff;
      }
      /************************************
          Languages
      ************************************/
      Language.prototype = {
          set: function(config) {
              var prop, i;
              for (i in config) {
                  prop = config[i];
                  if (typeof prop === "function") {
                      this[i] = prop;
                  } else {
                      this["_" + i] = prop;
                  }
              }
          },
          _months: "January_February_March_April_May_June_July_August_September_October_November_December".split("_"),
          months: function(m) {
              return this._months[m.month()];
          },
          _monthsShort: "Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),
          monthsShort: function(m) {
              return this._monthsShort[m.month()];
          },
          monthsParse: function(monthName) {
              var i, mom, regex, output;
              if (!this._monthsParse) {
                  this._monthsParse = [];
              }
              for (i = 0; i < 12; i++) {
                  // make the regex if we don't have it already
                  if (!this._monthsParse[i]) {
                      mom = moment([ 2e3, i ]);
                      regex = "^" + this.months(mom, "") + "|^" + this.monthsShort(mom, "");
                      this._monthsParse[i] = new RegExp(regex.replace(".", ""), "i");
                  }
                  // test the regex
                  if (this._monthsParse[i].test(monthName)) {
                      return i;
                  }
              }
          },
          _weekdays: "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),
          weekdays: function(m) {
              return this._weekdays[m.day()];
          },
          _weekdaysShort: "Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),
          weekdaysShort: function(m) {
              return this._weekdaysShort[m.day()];
          },
          _weekdaysMin: "Su_Mo_Tu_We_Th_Fr_Sa".split("_"),
          weekdaysMin: function(m) {
              return this._weekdaysMin[m.day()];
          },
          _longDateFormat: {
              LT: "h:mm A",
              L: "MM/DD/YYYY",
              LL: "MMMM D YYYY",
              LLL: "MMMM D YYYY LT",
              LLLL: "dddd, MMMM D YYYY LT"
          },
          longDateFormat: function(key) {
              var output = this._longDateFormat[key];
              if (!output && this._longDateFormat[key.toUpperCase()]) {
                  output = this._longDateFormat[key.toUpperCase()].replace(/MMMM|MM|DD|dddd/g, function(val) {
                      return val.slice(1);
                  });
                  this._longDateFormat[key] = output;
              }
              return output;
          },
          meridiem: function(hours, minutes, isLower) {
              if (hours > 11) {
                  return isLower ? "pm" : "PM";
              } else {
                  return isLower ? "am" : "AM";
              }
          },
          _calendar: {
              sameDay: "[Today at] LT",
              nextDay: "[Tomorrow at] LT",
              nextWeek: "dddd [at] LT",
              lastDay: "[Yesterday at] LT",
              lastWeek: "[last] dddd [at] LT",
              sameElse: "L"
          },
          calendar: function(key, mom) {
              var output = this._calendar[key];
              return typeof output === "function" ? output.apply(mom) : output;
          },
          _relativeTime: {
              future: "in %s",
              past: "%s ago",
              s: "a few seconds",
              m: "a minute",
              mm: "%d minutes",
              h: "an hour",
              hh: "%d hours",
              d: "a day",
              dd: "%d days",
              M: "a month",
              MM: "%d months",
              y: "a year",
              yy: "%d years"
          },
          relativeTime: function(number, withoutSuffix, string, isFuture) {
              var output = this._relativeTime[string];
              return typeof output === "function" ? output(number, withoutSuffix, string, isFuture) : output.replace(/%d/i, number);
          },
          pastFuture: function(diff, output) {
              var format = this._relativeTime[diff > 0 ? "future" : "past"];
              return typeof format === "function" ? format(output) : format.replace(/%s/i, output);
          },
          ordinal: function(number) {
              return this._ordinal.replace("%d", number);
          },
          _ordinal: "%d",
          preparse: function(string) {
              return string;
          },
          postformat: function(string) {
              return string;
          },
          week: function(mom) {
              return weekOfYear(mom, this._week.dow, this._week.doy);
          },
          _week: {
              dow: 0,
              // Sunday is the first day of the week.
              doy: 6
          }
      };
      // Loads a language definition into the `languages` cache.  The function
      // takes a key and optionally values.  If not in the browser and no values
      // are provided, it will load the language file module.  As a convenience,
      // this function also returns the language values.
      function loadLang(key, values) {
          values.abbr = key;
          if (!languages[key]) {
              languages[key] = new Language();
          }
          languages[key].set(values);
          return languages[key];
      }
      // Determines which language definition to use and returns it.
      //
      // With no parameters, it will return the global language.  If you
      // pass in a language key, such as 'en', it will return the
      // definition for 'en', so long as 'en' has already been loaded using
      // moment.lang.
      function getLangDefinition(key) {
          if (!key) {
              return moment.fn._lang;
          }
          if (!languages[key] && hasModule) {
              require("./lang/" + key);
          }
          return languages[key];
      }
      /************************************
          Formatting
      ************************************/
      function removeFormattingTokens(input) {
          if (input.match(/\[.*\]/)) {
              return input.replace(/^\[|\]$/g, "");
          }
          return input.replace(/\\/g, "");
      }
      function makeFormatFunction(format) {
          var array = format.match(formattingTokens), i, length;
          for (i = 0, length = array.length; i < length; i++) {
              if (formatTokenFunctions[array[i]]) {
                  array[i] = formatTokenFunctions[array[i]];
              } else {
                  array[i] = removeFormattingTokens(array[i]);
              }
          }
          return function(mom) {
              var output = "";
              for (i = 0; i < length; i++) {
                  output += typeof array[i].call === "function" ? array[i].call(mom, format) : array[i];
              }
              return output;
          };
      }
      // format date using native date object
      function formatMoment(m, format) {
          var i = 5;
          function replaceLongDateFormatTokens(input) {
              return m.lang().longDateFormat(input) || input;
          }
          while (i-- && localFormattingTokens.test(format)) {
              format = format.replace(localFormattingTokens, replaceLongDateFormatTokens);
          }
          if (!formatFunctions[format]) {
              formatFunctions[format] = makeFormatFunction(format);
          }
          return formatFunctions[format](m);
      }
      /************************************
          Parsing
      ************************************/
      // get the regex to find the next token
      function getParseRegexForToken(token) {
          switch (token) {
            case "DDDD":
              return parseTokenThreeDigits;
  
            case "YYYY":
              return parseTokenFourDigits;
  
            case "YYYYY":
              return parseTokenSixDigits;
  
            case "S":
            case "SS":
            case "SSS":
            case "DDD":
              return parseTokenOneToThreeDigits;
  
            case "MMM":
            case "MMMM":
            case "dd":
            case "ddd":
            case "dddd":
            case "a":
            case "A":
              return parseTokenWord;
  
            case "X":
              return parseTokenTimestampMs;
  
            case "Z":
            case "ZZ":
              return parseTokenTimezone;
  
            case "T":
              return parseTokenT;
  
            case "MM":
            case "DD":
            case "YY":
            case "HH":
            case "hh":
            case "mm":
            case "ss":
            case "M":
            case "D":
            case "d":
            case "H":
            case "h":
            case "m":
            case "s":
              return parseTokenOneOrTwoDigits;
  
            default:
              return new RegExp(token.replace("\\", ""));
          }
      }
      // function to convert string input to date
      function addTimeToArrayFromToken(token, input, config) {
          var a, b, datePartArray = config._a;
          switch (token) {
            // MONTH
              case "M":
            // fall through to MM
              case "MM":
              datePartArray[1] = input == null ? 0 : ~~input - 1;
              break;
  
            case "MMM":
            // fall through to MMMM
              case "MMMM":
              a = getLangDefinition(config._l).monthsParse(input);
              // if we didn't find a month name, mark the date as invalid.
              if (a != null) {
                  datePartArray[1] = a;
              } else {
                  config._isValid = false;
              }
              break;
  
            // DAY OF MONTH
              case "D":
            // fall through to DDDD
              case "DD":
            // fall through to DDDD
              case "DDD":
            // fall through to DDDD
              case "DDDD":
              if (input != null) {
                  datePartArray[2] = ~~input;
              }
              break;
  
            // YEAR
              case "YY":
              datePartArray[0] = ~~input + (~~input > 68 ? 1900 : 2e3);
              break;
  
            case "YYYY":
            case "YYYYY":
              datePartArray[0] = ~~input;
              break;
  
            // AM / PM
              case "a":
            // fall through to A
              case "A":
              config._isPm = (input + "").toLowerCase() === "pm";
              break;
  
            // 24 HOUR
              case "H":
            // fall through to hh
              case "HH":
            // fall through to hh
              case "h":
            // fall through to hh
              case "hh":
              datePartArray[3] = ~~input;
              break;
  
            // MINUTE
              case "m":
            // fall through to mm
              case "mm":
              datePartArray[4] = ~~input;
              break;
  
            // SECOND
              case "s":
            // fall through to ss
              case "ss":
              datePartArray[5] = ~~input;
              break;
  
            // MILLISECOND
              case "S":
            case "SS":
            case "SSS":
              datePartArray[6] = ~~(("0." + input) * 1e3);
              break;
  
            // UNIX TIMESTAMP WITH MS
              case "X":
              config._d = new Date(parseFloat(input) * 1e3);
              break;
  
            // TIMEZONE
              case "Z":
            // fall through to ZZ
              case "ZZ":
              config._useUTC = true;
              a = (input + "").match(parseTimezoneChunker);
              if (a && a[1]) {
                  config._tzh = ~~a[1];
              }
              if (a && a[2]) {
                  config._tzm = ~~a[2];
              }
              // reverse offsets
              if (a && a[0] === "+") {
                  config._tzh = -config._tzh;
                  config._tzm = -config._tzm;
              }
              break;
          }
          // if the input is null, the date is not valid
          if (input == null) {
              config._isValid = false;
          }
      }
      // convert an array to a date.
      // the array should mirror the parameters below
      // note: all values past the year are optional and will default to the lowest possible value.
      // [year, month, day , hour, minute, second, millisecond]
      function dateFromArray(config) {
          var i, date, input = [];
          if (config._d) {
              return;
          }
          for (i = 0; i < 7; i++) {
              config._a[i] = input[i] = config._a[i] == null ? i === 2 ? 1 : 0 : config._a[i];
          }
          // add the offsets to the time to be parsed so that we can have a clean array for checking isValid
          input[3] += config._tzh || 0;
          input[4] += config._tzm || 0;
          date = new Date(0);
          if (config._useUTC) {
              date.setUTCFullYear(input[0], input[1], input[2]);
              date.setUTCHours(input[3], input[4], input[5], input[6]);
          } else {
              date.setFullYear(input[0], input[1], input[2]);
              date.setHours(input[3], input[4], input[5], input[6]);
          }
          config._d = date;
      }
      // date from string and format string
      function makeDateFromStringAndFormat(config) {
          // This array is used to make a Date, either with `new Date` or `Date.UTC`
          var tokens = config._f.match(formattingTokens), string = config._i, i, parsedInput;
          config._a = [];
          for (i = 0; i < tokens.length; i++) {
              parsedInput = (getParseRegexForToken(tokens[i]).exec(string) || [])[0];
              if (parsedInput) {
                  string = string.slice(string.indexOf(parsedInput) + parsedInput.length);
              }
              // don't parse if its not a known token
              if (formatTokenFunctions[tokens[i]]) {
                  addTimeToArrayFromToken(tokens[i], parsedInput, config);
              }
          }
          // handle am pm
          if (config._isPm && config._a[3] < 12) {
              config._a[3] += 12;
          }
          // if is 12 am, change hours to 0
          if (config._isPm === false && config._a[3] === 12) {
              config._a[3] = 0;
          }
          // return
          dateFromArray(config);
      }
      // date from string and array of format strings
      function makeDateFromStringAndArray(config) {
          var tempConfig, tempMoment, bestMoment, scoreToBeat = 99, i, currentDate, currentScore;
          while (config._f.length) {
              tempConfig = extend({}, config);
              tempConfig._f = config._f.pop();
              makeDateFromStringAndFormat(tempConfig);
              tempMoment = new Moment(tempConfig);
              if (tempMoment.isValid()) {
                  bestMoment = tempMoment;
                  break;
              }
              currentScore = compareArrays(tempConfig._a, tempMoment.toArray());
              if (currentScore < scoreToBeat) {
                  scoreToBeat = currentScore;
                  bestMoment = tempMoment;
              }
          }
          extend(config, bestMoment);
      }
      // date from iso format
      function makeDateFromString(config) {
          var i, string = config._i;
          if (isoRegex.exec(string)) {
              config._f = "YYYY-MM-DDT";
              for (i = 0; i < 4; i++) {
                  if (isoTimes[i][1].exec(string)) {
                      config._f += isoTimes[i][0];
                      break;
                  }
              }
              if (parseTokenTimezone.exec(string)) {
                  config._f += " Z";
              }
              makeDateFromStringAndFormat(config);
          } else {
              config._d = new Date(string);
          }
      }
      function makeDateFromInput(config) {
          var input = config._i, matched = aspNetJsonRegex.exec(input);
          if (input === undefined) {
              config._d = new Date();
          } else if (matched) {
              config._d = new Date(+matched[1]);
          } else if (typeof input === "string") {
              makeDateFromString(config);
          } else if (isArray(input)) {
              config._a = input.slice(0);
              dateFromArray(config);
          } else {
              config._d = input instanceof Date ? new Date(+input) : new Date(input);
          }
      }
      /************************************
          Relative Time
      ************************************/
      // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize
      function substituteTimeAgo(string, number, withoutSuffix, isFuture, lang) {
          return lang.relativeTime(number || 1, !!withoutSuffix, string, isFuture);
      }
      function relativeTime(milliseconds, withoutSuffix, lang) {
          var seconds = round(Math.abs(milliseconds) / 1e3), minutes = round(seconds / 60), hours = round(minutes / 60), days = round(hours / 24), years = round(days / 365), args = seconds < 45 && [ "s", seconds ] || minutes === 1 && [ "m" ] || minutes < 45 && [ "mm", minutes ] || hours === 1 && [ "h" ] || hours < 22 && [ "hh", hours ] || days === 1 && [ "d" ] || days <= 25 && [ "dd", days ] || days <= 45 && [ "M" ] || days < 345 && [ "MM", round(days / 30) ] || years === 1 && [ "y" ] || [ "yy", years ];
          args[2] = withoutSuffix;
          args[3] = milliseconds > 0;
          args[4] = lang;
          return substituteTimeAgo.apply({}, args);
      }
      /************************************
          Week of Year
      ************************************/
      // firstDayOfWeek       0 = sun, 6 = sat
      //                      the day of the week that starts the week
      //                      (usually sunday or monday)
      // firstDayOfWeekOfYear 0 = sun, 6 = sat
      //                      the first week is the week that contains the first
      //                      of this day of the week
      //                      (eg. ISO weeks use thursday (4))
      function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) {
          var end = firstDayOfWeekOfYear - firstDayOfWeek, daysToDayOfWeek = firstDayOfWeekOfYear - mom.day();
          if (daysToDayOfWeek > end) {
              daysToDayOfWeek -= 7;
          }
          if (daysToDayOfWeek < end - 7) {
              daysToDayOfWeek += 7;
          }
          return Math.ceil(moment(mom).add("d", daysToDayOfWeek).dayOfYear() / 7);
      }
      /************************************
          Top Level Functions
      ************************************/
      function makeMoment(config) {
          var input = config._i, format = config._f;
          if (input === null || input === "") {
              return null;
          }
          if (typeof input === "string") {
              config._i = input = getLangDefinition().preparse(input);
          }
          if (moment.isMoment(input)) {
              config = extend({}, input);
              config._d = new Date(+input._d);
          } else if (format) {
              if (isArray(format)) {
                  makeDateFromStringAndArray(config);
              } else {
                  makeDateFromStringAndFormat(config);
              }
          } else {
              makeDateFromInput(config);
          }
          return new Moment(config);
      }
      moment = function(input, format, lang) {
          return makeMoment({
              _i: input,
              _f: format,
              _l: lang,
              _isUTC: false
          });
      };
      // creating with utc
      moment.utc = function(input, format, lang) {
          return makeMoment({
              _useUTC: true,
              _isUTC: true,
              _l: lang,
              _i: input,
              _f: format
          });
      };
      // creating with unix timestamp (in seconds)
      moment.unix = function(input) {
          return moment(input * 1e3);
      };
      // duration
      moment.duration = function(input, key) {
          var isDuration = moment.isDuration(input), isNumber = typeof input === "number", duration = isDuration ? input._data : isNumber ? {} : input, ret;
          if (isNumber) {
              if (key) {
                  duration[key] = input;
              } else {
                  duration.milliseconds = input;
              }
          }
          ret = new Duration(duration);
          if (isDuration && input.hasOwnProperty("_lang")) {
              ret._lang = input._lang;
          }
          return ret;
      };
      // version number
      moment.version = VERSION;
      // default format
      moment.defaultFormat = isoFormat;
      // This function will load languages and then set the global language.  If
      // no arguments are passed in, it will simply return the current global
      // language key.
      moment.lang = function(key, values) {
          var i;
          if (!key) {
              return moment.fn._lang._abbr;
          }
          if (values) {
              loadLang(key, values);
          } else if (!languages[key]) {
              getLangDefinition(key);
          }
          moment.duration.fn._lang = moment.fn._lang = getLangDefinition(key);
      };
      // returns language data
      moment.langData = function(key) {
          if (key && key._lang && key._lang._abbr) {
              key = key._lang._abbr;
          }
          return getLangDefinition(key);
      };
      // compare moment object
      moment.isMoment = function(obj) {
          return obj instanceof Moment;
      };
      // for typechecking Duration objects
      moment.isDuration = function(obj) {
          return obj instanceof Duration;
      };
      /************************************
          Moment Prototype
      ************************************/
      moment.fn = Moment.prototype = {
          clone: function() {
              return moment(this);
          },
          valueOf: function() {
              return +this._d;
          },
          unix: function() {
              return Math.floor(+this._d / 1e3);
          },
          toString: function() {
              return this.format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ");
          },
          toDate: function() {
              return this._d;
          },
          toJSON: function() {
              return moment.utc(this).format("YYYY-MM-DD[T]HH:mm:ss.SSS[Z]");
          },
          toArray: function() {
              var m = this;
              return [ m.year(), m.month(), m.date(), m.hours(), m.minutes(), m.seconds(), m.milliseconds() ];
          },
          isValid: function() {
              if (this._isValid == null) {
                  if (this._a) {
                      this._isValid = !compareArrays(this._a, (this._isUTC ? moment.utc(this._a) : moment(this._a)).toArray());
                  } else {
                      this._isValid = !isNaN(this._d.getTime());
                  }
              }
              return !!this._isValid;
          },
          utc: function() {
              this._isUTC = true;
              return this;
          },
          local: function() {
              this._isUTC = false;
              return this;
          },
          format: function(inputString) {
              var output = formatMoment(this, inputString || moment.defaultFormat);
              return this.lang().postformat(output);
          },
          add: function(input, val) {
              var dur;
              // switch args to support add('s', 1) and add(1, 's')
              if (typeof input === "string") {
                  dur = moment.duration(+val, input);
              } else {
                  dur = moment.duration(input, val);
              }
              addOrSubtractDurationFromMoment(this, dur, 1);
              return this;
          },
          subtract: function(input, val) {
              var dur;
              // switch args to support subtract('s', 1) and subtract(1, 's')
              if (typeof input === "string") {
                  dur = moment.duration(+val, input);
              } else {
                  dur = moment.duration(input, val);
              }
              addOrSubtractDurationFromMoment(this, dur, -1);
              return this;
          },
          diff: function(input, units, asFloat) {
              var that = this._isUTC ? moment(input).utc() : moment(input).local(), zoneDiff = (this.zone() - that.zone()) * 6e4, diff, output;
              if (units) {
                  // standardize on singular form
                  units = units.replace(/s$/, "");
              }
              if (units === "year" || units === "month") {
                  diff = (this.daysInMonth() + that.daysInMonth()) * 432e5;
                  // 24 * 60 * 60 * 1000 / 2
                  output = (this.year() - that.year()) * 12 + (this.month() - that.month());
                  output += (this - moment(this).startOf("month") - (that - moment(that).startOf("month"))) / diff;
                  if (units === "year") {
                      output = output / 12;
                  }
              } else {
                  diff = this - that - zoneDiff;
                  output = units === "second" ? diff / 1e3 : // 1000
                  units === "minute" ? diff / 6e4 : // 1000 * 60
                  units === "hour" ? diff / 36e5 : // 1000 * 60 * 60
                  units === "day" ? diff / 864e5 : // 1000 * 60 * 60 * 24
                  units === "week" ? diff / 6048e5 : // 1000 * 60 * 60 * 24 * 7
                  diff;
              }
              return asFloat ? output : absRound(output);
          },
          from: function(time, withoutSuffix) {
              return moment.duration(this.diff(time)).lang(this.lang()._abbr).humanize(!withoutSuffix);
          },
          fromNow: function(withoutSuffix) {
              return this.from(moment(), withoutSuffix);
          },
          calendar: function() {
              var diff = this.diff(moment().startOf("day"), "days", true), format = diff < -6 ? "sameElse" : diff < -1 ? "lastWeek" : diff < 0 ? "lastDay" : diff < 1 ? "sameDay" : diff < 2 ? "nextDay" : diff < 7 ? "nextWeek" : "sameElse";
              return this.format(this.lang().calendar(format, this));
          },
          isLeapYear: function() {
              var year = this.year();
              return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
          },
          isDST: function() {
              return this.zone() < moment([ this.year() ]).zone() || this.zone() < moment([ this.year(), 5 ]).zone();
          },
          day: function(input) {
              var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay();
              return input == null ? day : this.add({
                  d: input - day
              });
          },
          startOf: function(units) {
              units = units.replace(/s$/, "");
              // the following switch intentionally omits break keywords
              // to utilize falling through the cases.
              switch (units) {
                case "year":
                  this.month(0);
  
                /* falls through */
                  case "month":
                  this.date(1);
  
                /* falls through */
                  case "week":
                case "day":
                  this.hours(0);
  
                /* falls through */
                  case "hour":
                  this.minutes(0);
  
                /* falls through */
                  case "minute":
                  this.seconds(0);
  
                /* falls through */
                  case "second":
                  this.milliseconds(0);
              }
              // weeks are a special case
              if (units === "week") {
                  this.day(0);
              }
              return this;
          },
          endOf: function(units) {
              return this.startOf(units).add(units.replace(/s?$/, "s"), 1).subtract("ms", 1);
          },
          isAfter: function(input, units) {
              units = typeof units !== "undefined" ? units : "millisecond";
              return +this.clone().startOf(units) > +moment(input).startOf(units);
          },
          isBefore: function(input, units) {
              units = typeof units !== "undefined" ? units : "millisecond";
              return +this.clone().startOf(units) < +moment(input).startOf(units);
          },
          isSame: function(input, units) {
              units = typeof units !== "undefined" ? units : "millisecond";
              return +this.clone().startOf(units) === +moment(input).startOf(units);
          },
          zone: function() {
              return this._isUTC ? 0 : this._d.getTimezoneOffset();
          },
          daysInMonth: function() {
              return moment.utc([ this.year(), this.month() + 1, 0 ]).date();
          },
          dayOfYear: function(input) {
              var dayOfYear = round((moment(this).startOf("day") - moment(this).startOf("year")) / 864e5) + 1;
              return input == null ? dayOfYear : this.add("d", input - dayOfYear);
          },
          isoWeek: function(input) {
              var week = weekOfYear(this, 1, 4);
              return input == null ? week : this.add("d", (input - week) * 7);
          },
          week: function(input) {
              var week = this.lang().week(this);
              return input == null ? week : this.add("d", (input - week) * 7);
          },
          // If passed a language key, it will set the language for this
          // instance.  Otherwise, it will return the language configuration
          // variables for this instance.
          lang: function(key) {
              if (key === undefined) {
                  return this._lang;
              } else {
                  this._lang = getLangDefinition(key);
                  return this;
              }
          }
      };
      // helper for adding shortcuts
      function makeGetterAndSetter(name, key) {
          moment.fn[name] = moment.fn[name + "s"] = function(input) {
              var utc = this._isUTC ? "UTC" : "";
              if (input != null) {
                  this._d["set" + utc + key](input);
                  return this;
              } else {
                  return this._d["get" + utc + key]();
              }
          };
      }
      // loop through and add shortcuts (Month, Date, Hours, Minutes, Seconds, Milliseconds)
      for (i = 0; i < proxyGettersAndSetters.length; i++) {
          makeGetterAndSetter(proxyGettersAndSetters[i].toLowerCase().replace(/s$/, ""), proxyGettersAndSetters[i]);
      }
      // add shortcut for year (uses different syntax than the getter/setter 'year' == 'FullYear')
      makeGetterAndSetter("year", "FullYear");
      // add plural methods
      moment.fn.days = moment.fn.day;
      moment.fn.weeks = moment.fn.week;
      moment.fn.isoWeeks = moment.fn.isoWeek;
      /************************************
          Duration Prototype
      ************************************/
      moment.duration.fn = Duration.prototype = {
          weeks: function() {
              return absRound(this.days() / 7);
          },
          valueOf: function() {
              return this._milliseconds + this._days * 864e5 + this._months * 2592e6;
          },
          humanize: function(withSuffix) {
              var difference = +this, output = relativeTime(difference, !withSuffix, this.lang());
              if (withSuffix) {
                  output = this.lang().pastFuture(difference, output);
              }
              return this.lang().postformat(output);
          },
          lang: moment.fn.lang
      };
      function makeDurationGetter(name) {
          moment.duration.fn[name] = function() {
              return this._data[name];
          };
      }
      function makeDurationAsGetter(name, factor) {
          moment.duration.fn["as" + name] = function() {
              return +this / factor;
          };
      }
      for (i in unitMillisecondFactors) {
          if (unitMillisecondFactors.hasOwnProperty(i)) {
              makeDurationAsGetter(i, unitMillisecondFactors[i]);
              makeDurationGetter(i.toLowerCase());
          }
      }
      makeDurationAsGetter("Weeks", 6048e5);
      /************************************
          Default Lang
      ************************************/
      // Set default language, other languages will inherit from English.
      moment.lang("en", {
          ordinal: function(number) {
              var b = number % 10, output = ~~(number % 100 / 10) === 1 ? "th" : b === 1 ? "st" : b === 2 ? "nd" : b === 3 ? "rd" : "th";
              return number + output;
          }
      });
      /************************************
          Exposing Moment
      ************************************/
      // CommonJS module is defined
      module.exports = moment;
  });
  