simple_admin_rails 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +22 -0
  4. data/Rakefile +37 -0
  5. data/app/assets/javascripts/application.js +10 -0
  6. data/app/assets/javascripts/bootstrap.js +4 -0
  7. data/app/assets/javascripts/moment.js +3043 -0
  8. data/app/assets/javascripts/simple_admin/admin.js +8 -0
  9. data/app/assets/javascripts/simple_admin/application.js +13 -0
  10. data/app/assets/stylesheets/application.css +7 -0
  11. data/app/assets/stylesheets/bootstrap_and_overrides.css.less +29 -0
  12. data/app/assets/stylesheets/simple_admin/application.css +29 -0
  13. data/app/controllers/simple_admin/admin_controller.rb +118 -0
  14. data/app/controllers/simple_admin/application_controller.rb +4 -0
  15. data/app/helpers/simple_admin/application_helper.rb +4 -0
  16. data/app/models/admin.rb +165 -0
  17. data/app/views/layouts/simple_admin/application.html.erb +70 -0
  18. data/app/views/simple_admin/admin/_dashboard.html.erb +19 -0
  19. data/app/views/simple_admin/admin/index.html.erb +50 -0
  20. data/app/views/simple_admin/admin/model_edit.html.erb +13 -0
  21. data/app/views/simple_admin/admin/model_new.html.erb +10 -0
  22. data/config/initializers/kaminari_config.rb +10 -0
  23. data/config/initializers/simple_form.rb +166 -0
  24. data/config/initializers/simple_form_bootstrap.rb +136 -0
  25. data/config/locales/en.bootstrap.yml +23 -0
  26. data/config/locales/simple_form.en.yml +31 -0
  27. data/config/routes.rb +12 -0
  28. data/lib/simple_admin.rb +4 -0
  29. data/lib/simple_admin/engine.rb +40 -0
  30. data/lib/simple_admin/version.rb +3 -0
  31. data/lib/tasks/simple_admin_tasks.rake +4 -0
  32. data/lib/templates/erb/scaffold/_form.html.erb +13 -0
  33. data/test/dummy/README.rdoc +28 -0
  34. data/test/dummy/Rakefile +6 -0
  35. data/test/dummy/app/assets/javascripts/application.js +13 -0
  36. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  37. data/test/dummy/app/controllers/application_controller.rb +5 -0
  38. data/test/dummy/app/helpers/application_helper.rb +2 -0
  39. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  40. data/test/dummy/bin/bundle +3 -0
  41. data/test/dummy/bin/rails +4 -0
  42. data/test/dummy/bin/rake +4 -0
  43. data/test/dummy/bin/setup +29 -0
  44. data/test/dummy/config.ru +4 -0
  45. data/test/dummy/config/application.rb +26 -0
  46. data/test/dummy/config/boot.rb +5 -0
  47. data/test/dummy/config/database.yml +25 -0
  48. data/test/dummy/config/environment.rb +5 -0
  49. data/test/dummy/config/environments/development.rb +41 -0
  50. data/test/dummy/config/environments/production.rb +79 -0
  51. data/test/dummy/config/environments/test.rb +42 -0
  52. data/test/dummy/config/initializers/assets.rb +11 -0
  53. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  54. data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  55. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  56. data/test/dummy/config/initializers/inflections.rb +16 -0
  57. data/test/dummy/config/initializers/mime_types.rb +4 -0
  58. data/test/dummy/config/initializers/session_store.rb +3 -0
  59. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  60. data/test/dummy/config/locales/en.yml +23 -0
  61. data/test/dummy/config/routes.rb +4 -0
  62. data/test/dummy/config/secrets.yml +22 -0
  63. data/test/dummy/db/development.sqlite3 +0 -0
  64. data/test/dummy/log/development.log +6 -0
  65. data/test/dummy/public/404.html +67 -0
  66. data/test/dummy/public/422.html +67 -0
  67. data/test/dummy/public/500.html +66 -0
  68. data/test/dummy/public/favicon.ico +0 -0
  69. data/test/integration/navigation_test.rb +10 -0
  70. data/test/simple_admin_test.rb +7 -0
  71. data/test/test_helper.rb +19 -0
  72. metadata +244 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: fe2d912b7c42db118f1dc381fc12bacc34fa249b
4
+ data.tar.gz: 204263daa8e2ba8294529fec87f253bd832def99
5
+ SHA512:
6
+ metadata.gz: 967057ce52ece4da8e5677fbb0ec7b92cd247b1493cf6d21d062ce3eee349db928cf2a46cba398291e1a179c9d1a0cb5abc843edb3b8605a739da24546a4c29b
7
+ data.tar.gz: a21377a9ee317322f6d9a3a44f889b5560a9cd10ba1cf8f38f3d759754fc54aa44b651e14c5a445794eec82749c26cf025a2e930b33da99015ddc0630fee8c9e
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2015 Victor Stan
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,22 @@
1
+ = SimpleAdmin
2
+ No frills
3
+
4
+ == Licence
5
+
6
+ This project rocks and uses MIT-LICENSE.
7
+
8
+ == Documentation Wiki
9
+ https://github.com/victorbstan/SimpleAdmin/wiki/Documentation-Wiki
10
+
11
+ == Description
12
+ A simple (one model) Rails Engine drop-in administration interface for your Rails project.
13
+
14
+ == About
15
+ The motivation for this gem is to provide a simple to understand, easy to hack and extend administration interface for a traditional Rails/ActiveRecord project.
16
+
17
+ It has been build for and extracted from a real-world production project. Originally created as a `lib` it can now be installed into any project as a Rails Engine (gem).
18
+
19
+ == TODO
20
+ 1. Write tests
21
+ 2. Get feedback
22
+ 3. Profit
data/Rakefile ADDED
@@ -0,0 +1,37 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'SimpleAdmin'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+
21
+ load 'rails/tasks/statistics.rake'
22
+
23
+
24
+
25
+ Bundler::GemHelper.install_tasks
26
+
27
+ require 'rake/testtask'
28
+
29
+ Rake::TestTask.new(:test) do |t|
30
+ t.libs << 'lib'
31
+ t.libs << 'test'
32
+ t.pattern = 'test/**/*_test.rb'
33
+ t.verbose = false
34
+ end
35
+
36
+
37
+ task default: :test
@@ -0,0 +1,10 @@
1
+ // This is a manifest file that'll be compiled into including all the files listed below.
2
+ // Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
3
+ // be included in the compiled file accessible from http://example.com/assets/application.js
4
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
5
+ // the compiled file.
6
+ //
7
+ //= require jquery
8
+ //= require jquery_ujs
9
+ //= require twitter/bootstrap
10
+ //= require_tree .
@@ -0,0 +1,4 @@
1
+ jQuery(function() {
2
+ $("a[rel~=popover], .has-popover").popover();
3
+ $("a[rel~=tooltip], .has-tooltip").tooltip();
4
+ });
@@ -0,0 +1,3043 @@
1
+ //! moment.js
2
+ //! version : 2.9.0
3
+ //! authors : Tim Wood, Iskren Chernev, Moment.js contributors
4
+ //! license : MIT
5
+ //! momentjs.com
6
+
7
+ (function (undefined) {
8
+ /************************************
9
+ Constants
10
+ ************************************/
11
+
12
+ var moment,
13
+ VERSION = '2.9.0',
14
+ // the global-scope this is NOT the global object in Node.js
15
+ globalScope = (typeof global !== 'undefined' && (typeof window === 'undefined' || window === global.window)) ? global : this,
16
+ oldGlobalMoment,
17
+ round = Math.round,
18
+ hasOwnProperty = Object.prototype.hasOwnProperty,
19
+ i,
20
+
21
+ YEAR = 0,
22
+ MONTH = 1,
23
+ DATE = 2,
24
+ HOUR = 3,
25
+ MINUTE = 4,
26
+ SECOND = 5,
27
+ MILLISECOND = 6,
28
+
29
+ // internal storage for locale config files
30
+ locales = {},
31
+
32
+ // extra moment internal properties (plugins register props here)
33
+ momentProperties = [],
34
+
35
+ // check for nodeJS
36
+ hasModule = (typeof module !== 'undefined' && module && module.exports),
37
+
38
+ // ASP.NET json date format regex
39
+ aspNetJsonRegex = /^\/?Date\((\-?\d+)/i,
40
+ aspNetTimeSpanJsonRegex = /(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/,
41
+
42
+ // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html
43
+ // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere
44
+ isoDurationRegex = /^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/,
45
+
46
+ // format tokens
47
+ formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Q|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|x|X|zz?|ZZ?|.)/g,
48
+ localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,
49
+
50
+ // parsing token regexes
51
+ parseTokenOneOrTwoDigits = /\d\d?/, // 0 - 99
52
+ parseTokenOneToThreeDigits = /\d{1,3}/, // 0 - 999
53
+ parseTokenOneToFourDigits = /\d{1,4}/, // 0 - 9999
54
+ parseTokenOneToSixDigits = /[+\-]?\d{1,6}/, // -999,999 - 999,999
55
+ parseTokenDigits = /\d+/, // nonzero number of digits
56
+ parseTokenWord = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i, // any word (or two) characters or numbers including two/three word month in arabic.
57
+ parseTokenTimezone = /Z|[\+\-]\d\d:?\d\d/gi, // +00:00 -00:00 +0000 -0000 or Z
58
+ parseTokenT = /T/i, // T (ISO separator)
59
+ parseTokenOffsetMs = /[\+\-]?\d+/, // 1234567890123
60
+ parseTokenTimestampMs = /[\+\-]?\d+(\.\d{1,3})?/, // 123456789 123456789.123
61
+
62
+ //strict parsing regexes
63
+ parseTokenOneDigit = /\d/, // 0 - 9
64
+ parseTokenTwoDigits = /\d\d/, // 00 - 99
65
+ parseTokenThreeDigits = /\d{3}/, // 000 - 999
66
+ parseTokenFourDigits = /\d{4}/, // 0000 - 9999
67
+ parseTokenSixDigits = /[+-]?\d{6}/, // -999,999 - 999,999
68
+ parseTokenSignedNumber = /[+-]?\d+/, // -inf - inf
69
+
70
+ // iso 8601 regex
71
+ // 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00)
72
+ isoRegex = /^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,
73
+
74
+ isoFormat = 'YYYY-MM-DDTHH:mm:ssZ',
75
+
76
+ isoDates = [
77
+ ['YYYYYY-MM-DD', /[+-]\d{6}-\d{2}-\d{2}/],
78
+ ['YYYY-MM-DD', /\d{4}-\d{2}-\d{2}/],
79
+ ['GGGG-[W]WW-E', /\d{4}-W\d{2}-\d/],
80
+ ['GGGG-[W]WW', /\d{4}-W\d{2}/],
81
+ ['YYYY-DDD', /\d{4}-\d{3}/]
82
+ ],
83
+
84
+ // iso time formats and regexes
85
+ isoTimes = [
86
+ ['HH:mm:ss.SSSS', /(T| )\d\d:\d\d:\d\d\.\d+/],
87
+ ['HH:mm:ss', /(T| )\d\d:\d\d:\d\d/],
88
+ ['HH:mm', /(T| )\d\d:\d\d/],
89
+ ['HH', /(T| )\d\d/]
90
+ ],
91
+
92
+ // timezone chunker '+10:00' > ['10', '00'] or '-1530' > ['-', '15', '30']
93
+ parseTimezoneChunker = /([\+\-]|\d\d)/gi,
94
+
95
+ // getter and setter names
96
+ proxyGettersAndSetters = 'Date|Hours|Minutes|Seconds|Milliseconds'.split('|'),
97
+ unitMillisecondFactors = {
98
+ 'Milliseconds' : 1,
99
+ 'Seconds' : 1e3,
100
+ 'Minutes' : 6e4,
101
+ 'Hours' : 36e5,
102
+ 'Days' : 864e5,
103
+ 'Months' : 2592e6,
104
+ 'Years' : 31536e6
105
+ },
106
+
107
+ unitAliases = {
108
+ ms : 'millisecond',
109
+ s : 'second',
110
+ m : 'minute',
111
+ h : 'hour',
112
+ d : 'day',
113
+ D : 'date',
114
+ w : 'week',
115
+ W : 'isoWeek',
116
+ M : 'month',
117
+ Q : 'quarter',
118
+ y : 'year',
119
+ DDD : 'dayOfYear',
120
+ e : 'weekday',
121
+ E : 'isoWeekday',
122
+ gg: 'weekYear',
123
+ GG: 'isoWeekYear'
124
+ },
125
+
126
+ camelFunctions = {
127
+ dayofyear : 'dayOfYear',
128
+ isoweekday : 'isoWeekday',
129
+ isoweek : 'isoWeek',
130
+ weekyear : 'weekYear',
131
+ isoweekyear : 'isoWeekYear'
132
+ },
133
+
134
+ // format function strings
135
+ formatFunctions = {},
136
+
137
+ // default relative time thresholds
138
+ relativeTimeThresholds = {
139
+ s: 45, // seconds to minute
140
+ m: 45, // minutes to hour
141
+ h: 22, // hours to day
142
+ d: 26, // days to month
143
+ M: 11 // months to year
144
+ },
145
+
146
+ // tokens to ordinalize and pad
147
+ ordinalizeTokens = 'DDD w W M D d'.split(' '),
148
+ paddedTokens = 'M D H h m s w W'.split(' '),
149
+
150
+ formatTokenFunctions = {
151
+ M : function () {
152
+ return this.month() + 1;
153
+ },
154
+ MMM : function (format) {
155
+ return this.localeData().monthsShort(this, format);
156
+ },
157
+ MMMM : function (format) {
158
+ return this.localeData().months(this, format);
159
+ },
160
+ D : function () {
161
+ return this.date();
162
+ },
163
+ DDD : function () {
164
+ return this.dayOfYear();
165
+ },
166
+ d : function () {
167
+ return this.day();
168
+ },
169
+ dd : function (format) {
170
+ return this.localeData().weekdaysMin(this, format);
171
+ },
172
+ ddd : function (format) {
173
+ return this.localeData().weekdaysShort(this, format);
174
+ },
175
+ dddd : function (format) {
176
+ return this.localeData().weekdays(this, format);
177
+ },
178
+ w : function () {
179
+ return this.week();
180
+ },
181
+ W : function () {
182
+ return this.isoWeek();
183
+ },
184
+ YY : function () {
185
+ return leftZeroFill(this.year() % 100, 2);
186
+ },
187
+ YYYY : function () {
188
+ return leftZeroFill(this.year(), 4);
189
+ },
190
+ YYYYY : function () {
191
+ return leftZeroFill(this.year(), 5);
192
+ },
193
+ YYYYYY : function () {
194
+ var y = this.year(), sign = y >= 0 ? '+' : '-';
195
+ return sign + leftZeroFill(Math.abs(y), 6);
196
+ },
197
+ gg : function () {
198
+ return leftZeroFill(this.weekYear() % 100, 2);
199
+ },
200
+ gggg : function () {
201
+ return leftZeroFill(this.weekYear(), 4);
202
+ },
203
+ ggggg : function () {
204
+ return leftZeroFill(this.weekYear(), 5);
205
+ },
206
+ GG : function () {
207
+ return leftZeroFill(this.isoWeekYear() % 100, 2);
208
+ },
209
+ GGGG : function () {
210
+ return leftZeroFill(this.isoWeekYear(), 4);
211
+ },
212
+ GGGGG : function () {
213
+ return leftZeroFill(this.isoWeekYear(), 5);
214
+ },
215
+ e : function () {
216
+ return this.weekday();
217
+ },
218
+ E : function () {
219
+ return this.isoWeekday();
220
+ },
221
+ a : function () {
222
+ return this.localeData().meridiem(this.hours(), this.minutes(), true);
223
+ },
224
+ A : function () {
225
+ return this.localeData().meridiem(this.hours(), this.minutes(), false);
226
+ },
227
+ H : function () {
228
+ return this.hours();
229
+ },
230
+ h : function () {
231
+ return this.hours() % 12 || 12;
232
+ },
233
+ m : function () {
234
+ return this.minutes();
235
+ },
236
+ s : function () {
237
+ return this.seconds();
238
+ },
239
+ S : function () {
240
+ return toInt(this.milliseconds() / 100);
241
+ },
242
+ SS : function () {
243
+ return leftZeroFill(toInt(this.milliseconds() / 10), 2);
244
+ },
245
+ SSS : function () {
246
+ return leftZeroFill(this.milliseconds(), 3);
247
+ },
248
+ SSSS : function () {
249
+ return leftZeroFill(this.milliseconds(), 3);
250
+ },
251
+ Z : function () {
252
+ var a = this.utcOffset(),
253
+ b = '+';
254
+ if (a < 0) {
255
+ a = -a;
256
+ b = '-';
257
+ }
258
+ return b + leftZeroFill(toInt(a / 60), 2) + ':' + leftZeroFill(toInt(a) % 60, 2);
259
+ },
260
+ ZZ : function () {
261
+ var a = this.utcOffset(),
262
+ b = '+';
263
+ if (a < 0) {
264
+ a = -a;
265
+ b = '-';
266
+ }
267
+ return b + leftZeroFill(toInt(a / 60), 2) + leftZeroFill(toInt(a) % 60, 2);
268
+ },
269
+ z : function () {
270
+ return this.zoneAbbr();
271
+ },
272
+ zz : function () {
273
+ return this.zoneName();
274
+ },
275
+ x : function () {
276
+ return this.valueOf();
277
+ },
278
+ X : function () {
279
+ return this.unix();
280
+ },
281
+ Q : function () {
282
+ return this.quarter();
283
+ }
284
+ },
285
+
286
+ deprecations = {},
287
+
288
+ lists = ['months', 'monthsShort', 'weekdays', 'weekdaysShort', 'weekdaysMin'],
289
+
290
+ updateInProgress = false;
291
+
292
+ // Pick the first defined of two or three arguments. dfl comes from
293
+ // default.
294
+ function dfl(a, b, c) {
295
+ switch (arguments.length) {
296
+ case 2: return a != null ? a : b;
297
+ case 3: return a != null ? a : b != null ? b : c;
298
+ default: throw new Error('Implement me');
299
+ }
300
+ }
301
+
302
+ function hasOwnProp(a, b) {
303
+ return hasOwnProperty.call(a, b);
304
+ }
305
+
306
+ function defaultParsingFlags() {
307
+ // We need to deep clone this object, and es5 standard is not very
308
+ // helpful.
309
+ return {
310
+ empty : false,
311
+ unusedTokens : [],
312
+ unusedInput : [],
313
+ overflow : -2,
314
+ charsLeftOver : 0,
315
+ nullInput : false,
316
+ invalidMonth : null,
317
+ invalidFormat : false,
318
+ userInvalidated : false,
319
+ iso: false
320
+ };
321
+ }
322
+
323
+ function printMsg(msg) {
324
+ if (moment.suppressDeprecationWarnings === false &&
325
+ typeof console !== 'undefined' && console.warn) {
326
+ console.warn('Deprecation warning: ' + msg);
327
+ }
328
+ }
329
+
330
+ function deprecate(msg, fn) {
331
+ var firstTime = true;
332
+ return extend(function () {
333
+ if (firstTime) {
334
+ printMsg(msg);
335
+ firstTime = false;
336
+ }
337
+ return fn.apply(this, arguments);
338
+ }, fn);
339
+ }
340
+
341
+ function deprecateSimple(name, msg) {
342
+ if (!deprecations[name]) {
343
+ printMsg(msg);
344
+ deprecations[name] = true;
345
+ }
346
+ }
347
+
348
+ function padToken(func, count) {
349
+ return function (a) {
350
+ return leftZeroFill(func.call(this, a), count);
351
+ };
352
+ }
353
+ function ordinalizeToken(func, period) {
354
+ return function (a) {
355
+ return this.localeData().ordinal(func.call(this, a), period);
356
+ };
357
+ }
358
+
359
+ function monthDiff(a, b) {
360
+ // difference in months
361
+ var wholeMonthDiff = ((b.year() - a.year()) * 12) + (b.month() - a.month()),
362
+ // b is in (anchor - 1 month, anchor + 1 month)
363
+ anchor = a.clone().add(wholeMonthDiff, 'months'),
364
+ anchor2, adjust;
365
+
366
+ if (b - anchor < 0) {
367
+ anchor2 = a.clone().add(wholeMonthDiff - 1, 'months');
368
+ // linear across the month
369
+ adjust = (b - anchor) / (anchor - anchor2);
370
+ } else {
371
+ anchor2 = a.clone().add(wholeMonthDiff + 1, 'months');
372
+ // linear across the month
373
+ adjust = (b - anchor) / (anchor2 - anchor);
374
+ }
375
+
376
+ return -(wholeMonthDiff + adjust);
377
+ }
378
+
379
+ while (ordinalizeTokens.length) {
380
+ i = ordinalizeTokens.pop();
381
+ formatTokenFunctions[i + 'o'] = ordinalizeToken(formatTokenFunctions[i], i);
382
+ }
383
+ while (paddedTokens.length) {
384
+ i = paddedTokens.pop();
385
+ formatTokenFunctions[i + i] = padToken(formatTokenFunctions[i], 2);
386
+ }
387
+ formatTokenFunctions.DDDD = padToken(formatTokenFunctions.DDD, 3);
388
+
389
+
390
+ function meridiemFixWrap(locale, hour, meridiem) {
391
+ var isPm;
392
+
393
+ if (meridiem == null) {
394
+ // nothing to do
395
+ return hour;
396
+ }
397
+ if (locale.meridiemHour != null) {
398
+ return locale.meridiemHour(hour, meridiem);
399
+ } else if (locale.isPM != null) {
400
+ // Fallback
401
+ isPm = locale.isPM(meridiem);
402
+ if (isPm && hour < 12) {
403
+ hour += 12;
404
+ }
405
+ if (!isPm && hour === 12) {
406
+ hour = 0;
407
+ }
408
+ return hour;
409
+ } else {
410
+ // thie is not supposed to happen
411
+ return hour;
412
+ }
413
+ }
414
+
415
+ /************************************
416
+ Constructors
417
+ ************************************/
418
+
419
+ function Locale() {
420
+ }
421
+
422
+ // Moment prototype object
423
+ function Moment(config, skipOverflow) {
424
+ if (skipOverflow !== false) {
425
+ checkOverflow(config);
426
+ }
427
+ copyConfig(this, config);
428
+ this._d = new Date(+config._d);
429
+ // Prevent infinite loop in case updateOffset creates new moment
430
+ // objects.
431
+ if (updateInProgress === false) {
432
+ updateInProgress = true;
433
+ moment.updateOffset(this);
434
+ updateInProgress = false;
435
+ }
436
+ }
437
+
438
+ // Duration Constructor
439
+ function Duration(duration) {
440
+ var normalizedInput = normalizeObjectUnits(duration),
441
+ years = normalizedInput.year || 0,
442
+ quarters = normalizedInput.quarter || 0,
443
+ months = normalizedInput.month || 0,
444
+ weeks = normalizedInput.week || 0,
445
+ days = normalizedInput.day || 0,
446
+ hours = normalizedInput.hour || 0,
447
+ minutes = normalizedInput.minute || 0,
448
+ seconds = normalizedInput.second || 0,
449
+ milliseconds = normalizedInput.millisecond || 0;
450
+
451
+ // representation for dateAddRemove
452
+ this._milliseconds = +milliseconds +
453
+ seconds * 1e3 + // 1000
454
+ minutes * 6e4 + // 1000 * 60
455
+ hours * 36e5; // 1000 * 60 * 60
456
+ // Because of dateAddRemove treats 24 hours as different from a
457
+ // day when working around DST, we need to store them separately
458
+ this._days = +days +
459
+ weeks * 7;
460
+ // It is impossible translate months into days without knowing
461
+ // which months you are are talking about, so we have to store
462
+ // it separately.
463
+ this._months = +months +
464
+ quarters * 3 +
465
+ years * 12;
466
+
467
+ this._data = {};
468
+
469
+ this._locale = moment.localeData();
470
+
471
+ this._bubble();
472
+ }
473
+
474
+ /************************************
475
+ Helpers
476
+ ************************************/
477
+
478
+
479
+ function extend(a, b) {
480
+ for (var i in b) {
481
+ if (hasOwnProp(b, i)) {
482
+ a[i] = b[i];
483
+ }
484
+ }
485
+
486
+ if (hasOwnProp(b, 'toString')) {
487
+ a.toString = b.toString;
488
+ }
489
+
490
+ if (hasOwnProp(b, 'valueOf')) {
491
+ a.valueOf = b.valueOf;
492
+ }
493
+
494
+ return a;
495
+ }
496
+
497
+ function copyConfig(to, from) {
498
+ var i, prop, val;
499
+
500
+ if (typeof from._isAMomentObject !== 'undefined') {
501
+ to._isAMomentObject = from._isAMomentObject;
502
+ }
503
+ if (typeof from._i !== 'undefined') {
504
+ to._i = from._i;
505
+ }
506
+ if (typeof from._f !== 'undefined') {
507
+ to._f = from._f;
508
+ }
509
+ if (typeof from._l !== 'undefined') {
510
+ to._l = from._l;
511
+ }
512
+ if (typeof from._strict !== 'undefined') {
513
+ to._strict = from._strict;
514
+ }
515
+ if (typeof from._tzm !== 'undefined') {
516
+ to._tzm = from._tzm;
517
+ }
518
+ if (typeof from._isUTC !== 'undefined') {
519
+ to._isUTC = from._isUTC;
520
+ }
521
+ if (typeof from._offset !== 'undefined') {
522
+ to._offset = from._offset;
523
+ }
524
+ if (typeof from._pf !== 'undefined') {
525
+ to._pf = from._pf;
526
+ }
527
+ if (typeof from._locale !== 'undefined') {
528
+ to._locale = from._locale;
529
+ }
530
+
531
+ if (momentProperties.length > 0) {
532
+ for (i in momentProperties) {
533
+ prop = momentProperties[i];
534
+ val = from[prop];
535
+ if (typeof val !== 'undefined') {
536
+ to[prop] = val;
537
+ }
538
+ }
539
+ }
540
+
541
+ return to;
542
+ }
543
+
544
+ function absRound(number) {
545
+ if (number < 0) {
546
+ return Math.ceil(number);
547
+ } else {
548
+ return Math.floor(number);
549
+ }
550
+ }
551
+
552
+ // left zero fill a number
553
+ // see http://jsperf.com/left-zero-filling for performance comparison
554
+ function leftZeroFill(number, targetLength, forceSign) {
555
+ var output = '' + Math.abs(number),
556
+ sign = number >= 0;
557
+
558
+ while (output.length < targetLength) {
559
+ output = '0' + output;
560
+ }
561
+ return (sign ? (forceSign ? '+' : '') : '-') + output;
562
+ }
563
+
564
+ function positiveMomentsDifference(base, other) {
565
+ var res = {milliseconds: 0, months: 0};
566
+
567
+ res.months = other.month() - base.month() +
568
+ (other.year() - base.year()) * 12;
569
+ if (base.clone().add(res.months, 'M').isAfter(other)) {
570
+ --res.months;
571
+ }
572
+
573
+ res.milliseconds = +other - +(base.clone().add(res.months, 'M'));
574
+
575
+ return res;
576
+ }
577
+
578
+ function momentsDifference(base, other) {
579
+ var res;
580
+ other = makeAs(other, base);
581
+ if (base.isBefore(other)) {
582
+ res = positiveMomentsDifference(base, other);
583
+ } else {
584
+ res = positiveMomentsDifference(other, base);
585
+ res.milliseconds = -res.milliseconds;
586
+ res.months = -res.months;
587
+ }
588
+
589
+ return res;
590
+ }
591
+
592
+ // TODO: remove 'name' arg after deprecation is removed
593
+ function createAdder(direction, name) {
594
+ return function (val, period) {
595
+ var dur, tmp;
596
+ //invert the arguments, but complain about it
597
+ if (period !== null && !isNaN(+period)) {
598
+ deprecateSimple(name, 'moment().' + name + '(period, number) is deprecated. Please use moment().' + name + '(number, period).');
599
+ tmp = val; val = period; period = tmp;
600
+ }
601
+
602
+ val = typeof val === 'string' ? +val : val;
603
+ dur = moment.duration(val, period);
604
+ addOrSubtractDurationFromMoment(this, dur, direction);
605
+ return this;
606
+ };
607
+ }
608
+
609
+ function addOrSubtractDurationFromMoment(mom, duration, isAdding, updateOffset) {
610
+ var milliseconds = duration._milliseconds,
611
+ days = duration._days,
612
+ months = duration._months;
613
+ updateOffset = updateOffset == null ? true : updateOffset;
614
+
615
+ if (milliseconds) {
616
+ mom._d.setTime(+mom._d + milliseconds * isAdding);
617
+ }
618
+ if (days) {
619
+ rawSetter(mom, 'Date', rawGetter(mom, 'Date') + days * isAdding);
620
+ }
621
+ if (months) {
622
+ rawMonthSetter(mom, rawGetter(mom, 'Month') + months * isAdding);
623
+ }
624
+ if (updateOffset) {
625
+ moment.updateOffset(mom, days || months);
626
+ }
627
+ }
628
+
629
+ // check if is an array
630
+ function isArray(input) {
631
+ return Object.prototype.toString.call(input) === '[object Array]';
632
+ }
633
+
634
+ function isDate(input) {
635
+ return Object.prototype.toString.call(input) === '[object Date]' ||
636
+ input instanceof Date;
637
+ }
638
+
639
+ // compare two arrays, return the number of differences
640
+ function compareArrays(array1, array2, dontConvert) {
641
+ var len = Math.min(array1.length, array2.length),
642
+ lengthDiff = Math.abs(array1.length - array2.length),
643
+ diffs = 0,
644
+ i;
645
+ for (i = 0; i < len; i++) {
646
+ if ((dontConvert && array1[i] !== array2[i]) ||
647
+ (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) {
648
+ diffs++;
649
+ }
650
+ }
651
+ return diffs + lengthDiff;
652
+ }
653
+
654
+ function normalizeUnits(units) {
655
+ if (units) {
656
+ var lowered = units.toLowerCase().replace(/(.)s$/, '$1');
657
+ units = unitAliases[units] || camelFunctions[lowered] || lowered;
658
+ }
659
+ return units;
660
+ }
661
+
662
+ function normalizeObjectUnits(inputObject) {
663
+ var normalizedInput = {},
664
+ normalizedProp,
665
+ prop;
666
+
667
+ for (prop in inputObject) {
668
+ if (hasOwnProp(inputObject, prop)) {
669
+ normalizedProp = normalizeUnits(prop);
670
+ if (normalizedProp) {
671
+ normalizedInput[normalizedProp] = inputObject[prop];
672
+ }
673
+ }
674
+ }
675
+
676
+ return normalizedInput;
677
+ }
678
+
679
+ function makeList(field) {
680
+ var count, setter;
681
+
682
+ if (field.indexOf('week') === 0) {
683
+ count = 7;
684
+ setter = 'day';
685
+ }
686
+ else if (field.indexOf('month') === 0) {
687
+ count = 12;
688
+ setter = 'month';
689
+ }
690
+ else {
691
+ return;
692
+ }
693
+
694
+ moment[field] = function (format, index) {
695
+ var i, getter,
696
+ method = moment._locale[field],
697
+ results = [];
698
+
699
+ if (typeof format === 'number') {
700
+ index = format;
701
+ format = undefined;
702
+ }
703
+
704
+ getter = function (i) {
705
+ var m = moment().utc().set(setter, i);
706
+ return method.call(moment._locale, m, format || '');
707
+ };
708
+
709
+ if (index != null) {
710
+ return getter(index);
711
+ }
712
+ else {
713
+ for (i = 0; i < count; i++) {
714
+ results.push(getter(i));
715
+ }
716
+ return results;
717
+ }
718
+ };
719
+ }
720
+
721
+ function toInt(argumentForCoercion) {
722
+ var coercedNumber = +argumentForCoercion,
723
+ value = 0;
724
+
725
+ if (coercedNumber !== 0 && isFinite(coercedNumber)) {
726
+ if (coercedNumber >= 0) {
727
+ value = Math.floor(coercedNumber);
728
+ } else {
729
+ value = Math.ceil(coercedNumber);
730
+ }
731
+ }
732
+
733
+ return value;
734
+ }
735
+
736
+ function daysInMonth(year, month) {
737
+ return new Date(Date.UTC(year, month + 1, 0)).getUTCDate();
738
+ }
739
+
740
+ function weeksInYear(year, dow, doy) {
741
+ return weekOfYear(moment([year, 11, 31 + dow - doy]), dow, doy).week;
742
+ }
743
+
744
+ function daysInYear(year) {
745
+ return isLeapYear(year) ? 366 : 365;
746
+ }
747
+
748
+ function isLeapYear(year) {
749
+ return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
750
+ }
751
+
752
+ function checkOverflow(m) {
753
+ var overflow;
754
+ if (m._a && m._pf.overflow === -2) {
755
+ overflow =
756
+ m._a[MONTH] < 0 || m._a[MONTH] > 11 ? MONTH :
757
+ m._a[DATE] < 1 || m._a[DATE] > daysInMonth(m._a[YEAR], m._a[MONTH]) ? DATE :
758
+ m._a[HOUR] < 0 || m._a[HOUR] > 24 ||
759
+ (m._a[HOUR] === 24 && (m._a[MINUTE] !== 0 ||
760
+ m._a[SECOND] !== 0 ||
761
+ m._a[MILLISECOND] !== 0)) ? HOUR :
762
+ m._a[MINUTE] < 0 || m._a[MINUTE] > 59 ? MINUTE :
763
+ m._a[SECOND] < 0 || m._a[SECOND] > 59 ? SECOND :
764
+ m._a[MILLISECOND] < 0 || m._a[MILLISECOND] > 999 ? MILLISECOND :
765
+ -1;
766
+
767
+ if (m._pf._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) {
768
+ overflow = DATE;
769
+ }
770
+
771
+ m._pf.overflow = overflow;
772
+ }
773
+ }
774
+
775
+ function isValid(m) {
776
+ if (m._isValid == null) {
777
+ m._isValid = !isNaN(m._d.getTime()) &&
778
+ m._pf.overflow < 0 &&
779
+ !m._pf.empty &&
780
+ !m._pf.invalidMonth &&
781
+ !m._pf.nullInput &&
782
+ !m._pf.invalidFormat &&
783
+ !m._pf.userInvalidated;
784
+
785
+ if (m._strict) {
786
+ m._isValid = m._isValid &&
787
+ m._pf.charsLeftOver === 0 &&
788
+ m._pf.unusedTokens.length === 0 &&
789
+ m._pf.bigHour === undefined;
790
+ }
791
+ }
792
+ return m._isValid;
793
+ }
794
+
795
+ function normalizeLocale(key) {
796
+ return key ? key.toLowerCase().replace('_', '-') : key;
797
+ }
798
+
799
+ // pick the locale from the array
800
+ // try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each
801
+ // substring from most specific to least, but move to the next array item if it's a more specific variant than the current root
802
+ function chooseLocale(names) {
803
+ var i = 0, j, next, locale, split;
804
+
805
+ while (i < names.length) {
806
+ split = normalizeLocale(names[i]).split('-');
807
+ j = split.length;
808
+ next = normalizeLocale(names[i + 1]);
809
+ next = next ? next.split('-') : null;
810
+ while (j > 0) {
811
+ locale = loadLocale(split.slice(0, j).join('-'));
812
+ if (locale) {
813
+ return locale;
814
+ }
815
+ if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) {
816
+ //the next array item is better than a shallower substring of this one
817
+ break;
818
+ }
819
+ j--;
820
+ }
821
+ i++;
822
+ }
823
+ return null;
824
+ }
825
+
826
+ function loadLocale(name) {
827
+ var oldLocale = null;
828
+ if (!locales[name] && hasModule) {
829
+ try {
830
+ oldLocale = moment.locale();
831
+ require('./locale/' + name);
832
+ // because defineLocale currently also sets the global locale, we want to undo that for lazy loaded locales
833
+ moment.locale(oldLocale);
834
+ } catch (e) { }
835
+ }
836
+ return locales[name];
837
+ }
838
+
839
+ // Return a moment from input, that is local/utc/utcOffset equivalent to
840
+ // model.
841
+ function makeAs(input, model) {
842
+ var res, diff;
843
+ if (model._isUTC) {
844
+ res = model.clone();
845
+ diff = (moment.isMoment(input) || isDate(input) ?
846
+ +input : +moment(input)) - (+res);
847
+ // Use low-level api, because this fn is low-level api.
848
+ res._d.setTime(+res._d + diff);
849
+ moment.updateOffset(res, false);
850
+ return res;
851
+ } else {
852
+ return moment(input).local();
853
+ }
854
+ }
855
+
856
+ /************************************
857
+ Locale
858
+ ************************************/
859
+
860
+
861
+ extend(Locale.prototype, {
862
+
863
+ set : function (config) {
864
+ var prop, i;
865
+ for (i in config) {
866
+ prop = config[i];
867
+ if (typeof prop === 'function') {
868
+ this[i] = prop;
869
+ } else {
870
+ this['_' + i] = prop;
871
+ }
872
+ }
873
+ // Lenient ordinal parsing accepts just a number in addition to
874
+ // number + (possibly) stuff coming from _ordinalParseLenient.
875
+ this._ordinalParseLenient = new RegExp(this._ordinalParse.source + '|' + /\d{1,2}/.source);
876
+ },
877
+
878
+ _months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'),
879
+ months : function (m) {
880
+ return this._months[m.month()];
881
+ },
882
+
883
+ _monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'),
884
+ monthsShort : function (m) {
885
+ return this._monthsShort[m.month()];
886
+ },
887
+
888
+ monthsParse : function (monthName, format, strict) {
889
+ var i, mom, regex;
890
+
891
+ if (!this._monthsParse) {
892
+ this._monthsParse = [];
893
+ this._longMonthsParse = [];
894
+ this._shortMonthsParse = [];
895
+ }
896
+
897
+ for (i = 0; i < 12; i++) {
898
+ // make the regex if we don't have it already
899
+ mom = moment.utc([2000, i]);
900
+ if (strict && !this._longMonthsParse[i]) {
901
+ this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i');
902
+ this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i');
903
+ }
904
+ if (!strict && !this._monthsParse[i]) {
905
+ regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, '');
906
+ this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i');
907
+ }
908
+ // test the regex
909
+ if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) {
910
+ return i;
911
+ } else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) {
912
+ return i;
913
+ } else if (!strict && this._monthsParse[i].test(monthName)) {
914
+ return i;
915
+ }
916
+ }
917
+ },
918
+
919
+ _weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'),
920
+ weekdays : function (m) {
921
+ return this._weekdays[m.day()];
922
+ },
923
+
924
+ _weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'),
925
+ weekdaysShort : function (m) {
926
+ return this._weekdaysShort[m.day()];
927
+ },
928
+
929
+ _weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'),
930
+ weekdaysMin : function (m) {
931
+ return this._weekdaysMin[m.day()];
932
+ },
933
+
934
+ weekdaysParse : function (weekdayName) {
935
+ var i, mom, regex;
936
+
937
+ if (!this._weekdaysParse) {
938
+ this._weekdaysParse = [];
939
+ }
940
+
941
+ for (i = 0; i < 7; i++) {
942
+ // make the regex if we don't have it already
943
+ if (!this._weekdaysParse[i]) {
944
+ mom = moment([2000, 1]).day(i);
945
+ regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, '');
946
+ this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i');
947
+ }
948
+ // test the regex
949
+ if (this._weekdaysParse[i].test(weekdayName)) {
950
+ return i;
951
+ }
952
+ }
953
+ },
954
+
955
+ _longDateFormat : {
956
+ LTS : 'h:mm:ss A',
957
+ LT : 'h:mm A',
958
+ L : 'MM/DD/YYYY',
959
+ LL : 'MMMM D, YYYY',
960
+ LLL : 'MMMM D, YYYY LT',
961
+ LLLL : 'dddd, MMMM D, YYYY LT'
962
+ },
963
+ longDateFormat : function (key) {
964
+ var output = this._longDateFormat[key];
965
+ if (!output && this._longDateFormat[key.toUpperCase()]) {
966
+ output = this._longDateFormat[key.toUpperCase()].replace(/MMMM|MM|DD|dddd/g, function (val) {
967
+ return val.slice(1);
968
+ });
969
+ this._longDateFormat[key] = output;
970
+ }
971
+ return output;
972
+ },
973
+
974
+ isPM : function (input) {
975
+ // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays
976
+ // Using charAt should be more compatible.
977
+ return ((input + '').toLowerCase().charAt(0) === 'p');
978
+ },
979
+
980
+ _meridiemParse : /[ap]\.?m?\.?/i,
981
+ meridiem : function (hours, minutes, isLower) {
982
+ if (hours > 11) {
983
+ return isLower ? 'pm' : 'PM';
984
+ } else {
985
+ return isLower ? 'am' : 'AM';
986
+ }
987
+ },
988
+
989
+
990
+ _calendar : {
991
+ sameDay : '[Today at] LT',
992
+ nextDay : '[Tomorrow at] LT',
993
+ nextWeek : 'dddd [at] LT',
994
+ lastDay : '[Yesterday at] LT',
995
+ lastWeek : '[Last] dddd [at] LT',
996
+ sameElse : 'L'
997
+ },
998
+ calendar : function (key, mom, now) {
999
+ var output = this._calendar[key];
1000
+ return typeof output === 'function' ? output.apply(mom, [now]) : output;
1001
+ },
1002
+
1003
+ _relativeTime : {
1004
+ future : 'in %s',
1005
+ past : '%s ago',
1006
+ s : 'a few seconds',
1007
+ m : 'a minute',
1008
+ mm : '%d minutes',
1009
+ h : 'an hour',
1010
+ hh : '%d hours',
1011
+ d : 'a day',
1012
+ dd : '%d days',
1013
+ M : 'a month',
1014
+ MM : '%d months',
1015
+ y : 'a year',
1016
+ yy : '%d years'
1017
+ },
1018
+
1019
+ relativeTime : function (number, withoutSuffix, string, isFuture) {
1020
+ var output = this._relativeTime[string];
1021
+ return (typeof output === 'function') ?
1022
+ output(number, withoutSuffix, string, isFuture) :
1023
+ output.replace(/%d/i, number);
1024
+ },
1025
+
1026
+ pastFuture : function (diff, output) {
1027
+ var format = this._relativeTime[diff > 0 ? 'future' : 'past'];
1028
+ return typeof format === 'function' ? format(output) : format.replace(/%s/i, output);
1029
+ },
1030
+
1031
+ ordinal : function (number) {
1032
+ return this._ordinal.replace('%d', number);
1033
+ },
1034
+ _ordinal : '%d',
1035
+ _ordinalParse : /\d{1,2}/,
1036
+
1037
+ preparse : function (string) {
1038
+ return string;
1039
+ },
1040
+
1041
+ postformat : function (string) {
1042
+ return string;
1043
+ },
1044
+
1045
+ week : function (mom) {
1046
+ return weekOfYear(mom, this._week.dow, this._week.doy).week;
1047
+ },
1048
+
1049
+ _week : {
1050
+ dow : 0, // Sunday is the first day of the week.
1051
+ doy : 6 // The week that contains Jan 1st is the first week of the year.
1052
+ },
1053
+
1054
+ firstDayOfWeek : function () {
1055
+ return this._week.dow;
1056
+ },
1057
+
1058
+ firstDayOfYear : function () {
1059
+ return this._week.doy;
1060
+ },
1061
+
1062
+ _invalidDate: 'Invalid date',
1063
+ invalidDate: function () {
1064
+ return this._invalidDate;
1065
+ }
1066
+ });
1067
+
1068
+ /************************************
1069
+ Formatting
1070
+ ************************************/
1071
+
1072
+
1073
+ function removeFormattingTokens(input) {
1074
+ if (input.match(/\[[\s\S]/)) {
1075
+ return input.replace(/^\[|\]$/g, '');
1076
+ }
1077
+ return input.replace(/\\/g, '');
1078
+ }
1079
+
1080
+ function makeFormatFunction(format) {
1081
+ var array = format.match(formattingTokens), i, length;
1082
+
1083
+ for (i = 0, length = array.length; i < length; i++) {
1084
+ if (formatTokenFunctions[array[i]]) {
1085
+ array[i] = formatTokenFunctions[array[i]];
1086
+ } else {
1087
+ array[i] = removeFormattingTokens(array[i]);
1088
+ }
1089
+ }
1090
+
1091
+ return function (mom) {
1092
+ var output = '';
1093
+ for (i = 0; i < length; i++) {
1094
+ output += array[i] instanceof Function ? array[i].call(mom, format) : array[i];
1095
+ }
1096
+ return output;
1097
+ };
1098
+ }
1099
+
1100
+ // format date using native date object
1101
+ function formatMoment(m, format) {
1102
+ if (!m.isValid()) {
1103
+ return m.localeData().invalidDate();
1104
+ }
1105
+
1106
+ format = expandFormat(format, m.localeData());
1107
+
1108
+ if (!formatFunctions[format]) {
1109
+ formatFunctions[format] = makeFormatFunction(format);
1110
+ }
1111
+
1112
+ return formatFunctions[format](m);
1113
+ }
1114
+
1115
+ function expandFormat(format, locale) {
1116
+ var i = 5;
1117
+
1118
+ function replaceLongDateFormatTokens(input) {
1119
+ return locale.longDateFormat(input) || input;
1120
+ }
1121
+
1122
+ localFormattingTokens.lastIndex = 0;
1123
+ while (i >= 0 && localFormattingTokens.test(format)) {
1124
+ format = format.replace(localFormattingTokens, replaceLongDateFormatTokens);
1125
+ localFormattingTokens.lastIndex = 0;
1126
+ i -= 1;
1127
+ }
1128
+
1129
+ return format;
1130
+ }
1131
+
1132
+
1133
+ /************************************
1134
+ Parsing
1135
+ ************************************/
1136
+
1137
+
1138
+ // get the regex to find the next token
1139
+ function getParseRegexForToken(token, config) {
1140
+ var a, strict = config._strict;
1141
+ switch (token) {
1142
+ case 'Q':
1143
+ return parseTokenOneDigit;
1144
+ case 'DDDD':
1145
+ return parseTokenThreeDigits;
1146
+ case 'YYYY':
1147
+ case 'GGGG':
1148
+ case 'gggg':
1149
+ return strict ? parseTokenFourDigits : parseTokenOneToFourDigits;
1150
+ case 'Y':
1151
+ case 'G':
1152
+ case 'g':
1153
+ return parseTokenSignedNumber;
1154
+ case 'YYYYYY':
1155
+ case 'YYYYY':
1156
+ case 'GGGGG':
1157
+ case 'ggggg':
1158
+ return strict ? parseTokenSixDigits : parseTokenOneToSixDigits;
1159
+ case 'S':
1160
+ if (strict) {
1161
+ return parseTokenOneDigit;
1162
+ }
1163
+ /* falls through */
1164
+ case 'SS':
1165
+ if (strict) {
1166
+ return parseTokenTwoDigits;
1167
+ }
1168
+ /* falls through */
1169
+ case 'SSS':
1170
+ if (strict) {
1171
+ return parseTokenThreeDigits;
1172
+ }
1173
+ /* falls through */
1174
+ case 'DDD':
1175
+ return parseTokenOneToThreeDigits;
1176
+ case 'MMM':
1177
+ case 'MMMM':
1178
+ case 'dd':
1179
+ case 'ddd':
1180
+ case 'dddd':
1181
+ return parseTokenWord;
1182
+ case 'a':
1183
+ case 'A':
1184
+ return config._locale._meridiemParse;
1185
+ case 'x':
1186
+ return parseTokenOffsetMs;
1187
+ case 'X':
1188
+ return parseTokenTimestampMs;
1189
+ case 'Z':
1190
+ case 'ZZ':
1191
+ return parseTokenTimezone;
1192
+ case 'T':
1193
+ return parseTokenT;
1194
+ case 'SSSS':
1195
+ return parseTokenDigits;
1196
+ case 'MM':
1197
+ case 'DD':
1198
+ case 'YY':
1199
+ case 'GG':
1200
+ case 'gg':
1201
+ case 'HH':
1202
+ case 'hh':
1203
+ case 'mm':
1204
+ case 'ss':
1205
+ case 'ww':
1206
+ case 'WW':
1207
+ return strict ? parseTokenTwoDigits : parseTokenOneOrTwoDigits;
1208
+ case 'M':
1209
+ case 'D':
1210
+ case 'd':
1211
+ case 'H':
1212
+ case 'h':
1213
+ case 'm':
1214
+ case 's':
1215
+ case 'w':
1216
+ case 'W':
1217
+ case 'e':
1218
+ case 'E':
1219
+ return parseTokenOneOrTwoDigits;
1220
+ case 'Do':
1221
+ return strict ? config._locale._ordinalParse : config._locale._ordinalParseLenient;
1222
+ default :
1223
+ a = new RegExp(regexpEscape(unescapeFormat(token.replace('\\', '')), 'i'));
1224
+ return a;
1225
+ }
1226
+ }
1227
+
1228
+ function utcOffsetFromString(string) {
1229
+ string = string || '';
1230
+ var possibleTzMatches = (string.match(parseTokenTimezone) || []),
1231
+ tzChunk = possibleTzMatches[possibleTzMatches.length - 1] || [],
1232
+ parts = (tzChunk + '').match(parseTimezoneChunker) || ['-', 0, 0],
1233
+ minutes = +(parts[1] * 60) + toInt(parts[2]);
1234
+
1235
+ return parts[0] === '+' ? minutes : -minutes;
1236
+ }
1237
+
1238
+ // function to convert string input to date
1239
+ function addTimeToArrayFromToken(token, input, config) {
1240
+ var a, datePartArray = config._a;
1241
+
1242
+ switch (token) {
1243
+ // QUARTER
1244
+ case 'Q':
1245
+ if (input != null) {
1246
+ datePartArray[MONTH] = (toInt(input) - 1) * 3;
1247
+ }
1248
+ break;
1249
+ // MONTH
1250
+ case 'M' : // fall through to MM
1251
+ case 'MM' :
1252
+ if (input != null) {
1253
+ datePartArray[MONTH] = toInt(input) - 1;
1254
+ }
1255
+ break;
1256
+ case 'MMM' : // fall through to MMMM
1257
+ case 'MMMM' :
1258
+ a = config._locale.monthsParse(input, token, config._strict);
1259
+ // if we didn't find a month name, mark the date as invalid.
1260
+ if (a != null) {
1261
+ datePartArray[MONTH] = a;
1262
+ } else {
1263
+ config._pf.invalidMonth = input;
1264
+ }
1265
+ break;
1266
+ // DAY OF MONTH
1267
+ case 'D' : // fall through to DD
1268
+ case 'DD' :
1269
+ if (input != null) {
1270
+ datePartArray[DATE] = toInt(input);
1271
+ }
1272
+ break;
1273
+ case 'Do' :
1274
+ if (input != null) {
1275
+ datePartArray[DATE] = toInt(parseInt(
1276
+ input.match(/\d{1,2}/)[0], 10));
1277
+ }
1278
+ break;
1279
+ // DAY OF YEAR
1280
+ case 'DDD' : // fall through to DDDD
1281
+ case 'DDDD' :
1282
+ if (input != null) {
1283
+ config._dayOfYear = toInt(input);
1284
+ }
1285
+
1286
+ break;
1287
+ // YEAR
1288
+ case 'YY' :
1289
+ datePartArray[YEAR] = moment.parseTwoDigitYear(input);
1290
+ break;
1291
+ case 'YYYY' :
1292
+ case 'YYYYY' :
1293
+ case 'YYYYYY' :
1294
+ datePartArray[YEAR] = toInt(input);
1295
+ break;
1296
+ // AM / PM
1297
+ case 'a' : // fall through to A
1298
+ case 'A' :
1299
+ config._meridiem = input;
1300
+ // config._isPm = config._locale.isPM(input);
1301
+ break;
1302
+ // HOUR
1303
+ case 'h' : // fall through to hh
1304
+ case 'hh' :
1305
+ config._pf.bigHour = true;
1306
+ /* falls through */
1307
+ case 'H' : // fall through to HH
1308
+ case 'HH' :
1309
+ datePartArray[HOUR] = toInt(input);
1310
+ break;
1311
+ // MINUTE
1312
+ case 'm' : // fall through to mm
1313
+ case 'mm' :
1314
+ datePartArray[MINUTE] = toInt(input);
1315
+ break;
1316
+ // SECOND
1317
+ case 's' : // fall through to ss
1318
+ case 'ss' :
1319
+ datePartArray[SECOND] = toInt(input);
1320
+ break;
1321
+ // MILLISECOND
1322
+ case 'S' :
1323
+ case 'SS' :
1324
+ case 'SSS' :
1325
+ case 'SSSS' :
1326
+ datePartArray[MILLISECOND] = toInt(('0.' + input) * 1000);
1327
+ break;
1328
+ // UNIX OFFSET (MILLISECONDS)
1329
+ case 'x':
1330
+ config._d = new Date(toInt(input));
1331
+ break;
1332
+ // UNIX TIMESTAMP WITH MS
1333
+ case 'X':
1334
+ config._d = new Date(parseFloat(input) * 1000);
1335
+ break;
1336
+ // TIMEZONE
1337
+ case 'Z' : // fall through to ZZ
1338
+ case 'ZZ' :
1339
+ config._useUTC = true;
1340
+ config._tzm = utcOffsetFromString(input);
1341
+ break;
1342
+ // WEEKDAY - human
1343
+ case 'dd':
1344
+ case 'ddd':
1345
+ case 'dddd':
1346
+ a = config._locale.weekdaysParse(input);
1347
+ // if we didn't get a weekday name, mark the date as invalid
1348
+ if (a != null) {
1349
+ config._w = config._w || {};
1350
+ config._w['d'] = a;
1351
+ } else {
1352
+ config._pf.invalidWeekday = input;
1353
+ }
1354
+ break;
1355
+ // WEEK, WEEK DAY - numeric
1356
+ case 'w':
1357
+ case 'ww':
1358
+ case 'W':
1359
+ case 'WW':
1360
+ case 'd':
1361
+ case 'e':
1362
+ case 'E':
1363
+ token = token.substr(0, 1);
1364
+ /* falls through */
1365
+ case 'gggg':
1366
+ case 'GGGG':
1367
+ case 'GGGGG':
1368
+ token = token.substr(0, 2);
1369
+ if (input) {
1370
+ config._w = config._w || {};
1371
+ config._w[token] = toInt(input);
1372
+ }
1373
+ break;
1374
+ case 'gg':
1375
+ case 'GG':
1376
+ config._w = config._w || {};
1377
+ config._w[token] = moment.parseTwoDigitYear(input);
1378
+ }
1379
+ }
1380
+
1381
+ function dayOfYearFromWeekInfo(config) {
1382
+ var w, weekYear, week, weekday, dow, doy, temp;
1383
+
1384
+ w = config._w;
1385
+ if (w.GG != null || w.W != null || w.E != null) {
1386
+ dow = 1;
1387
+ doy = 4;
1388
+
1389
+ // TODO: We need to take the current isoWeekYear, but that depends on
1390
+ // how we interpret now (local, utc, fixed offset). So create
1391
+ // a now version of current config (take local/utc/offset flags, and
1392
+ // create now).
1393
+ weekYear = dfl(w.GG, config._a[YEAR], weekOfYear(moment(), 1, 4).year);
1394
+ week = dfl(w.W, 1);
1395
+ weekday = dfl(w.E, 1);
1396
+ } else {
1397
+ dow = config._locale._week.dow;
1398
+ doy = config._locale._week.doy;
1399
+
1400
+ weekYear = dfl(w.gg, config._a[YEAR], weekOfYear(moment(), dow, doy).year);
1401
+ week = dfl(w.w, 1);
1402
+
1403
+ if (w.d != null) {
1404
+ // weekday -- low day numbers are considered next week
1405
+ weekday = w.d;
1406
+ if (weekday < dow) {
1407
+ ++week;
1408
+ }
1409
+ } else if (w.e != null) {
1410
+ // local weekday -- counting starts from begining of week
1411
+ weekday = w.e + dow;
1412
+ } else {
1413
+ // default to begining of week
1414
+ weekday = dow;
1415
+ }
1416
+ }
1417
+ temp = dayOfYearFromWeeks(weekYear, week, weekday, doy, dow);
1418
+
1419
+ config._a[YEAR] = temp.year;
1420
+ config._dayOfYear = temp.dayOfYear;
1421
+ }
1422
+
1423
+ // convert an array to a date.
1424
+ // the array should mirror the parameters below
1425
+ // note: all values past the year are optional and will default to the lowest possible value.
1426
+ // [year, month, day , hour, minute, second, millisecond]
1427
+ function dateFromConfig(config) {
1428
+ var i, date, input = [], currentDate, yearToUse;
1429
+
1430
+ if (config._d) {
1431
+ return;
1432
+ }
1433
+
1434
+ currentDate = currentDateArray(config);
1435
+
1436
+ //compute day of the year from weeks and weekdays
1437
+ if (config._w && config._a[DATE] == null && config._a[MONTH] == null) {
1438
+ dayOfYearFromWeekInfo(config);
1439
+ }
1440
+
1441
+ //if the day of the year is set, figure out what it is
1442
+ if (config._dayOfYear) {
1443
+ yearToUse = dfl(config._a[YEAR], currentDate[YEAR]);
1444
+
1445
+ if (config._dayOfYear > daysInYear(yearToUse)) {
1446
+ config._pf._overflowDayOfYear = true;
1447
+ }
1448
+
1449
+ date = makeUTCDate(yearToUse, 0, config._dayOfYear);
1450
+ config._a[MONTH] = date.getUTCMonth();
1451
+ config._a[DATE] = date.getUTCDate();
1452
+ }
1453
+
1454
+ // Default to current date.
1455
+ // * if no year, month, day of month are given, default to today
1456
+ // * if day of month is given, default month and year
1457
+ // * if month is given, default only year
1458
+ // * if year is given, don't default anything
1459
+ for (i = 0; i < 3 && config._a[i] == null; ++i) {
1460
+ config._a[i] = input[i] = currentDate[i];
1461
+ }
1462
+
1463
+ // Zero out whatever was not defaulted, including time
1464
+ for (; i < 7; i++) {
1465
+ config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i];
1466
+ }
1467
+
1468
+ // Check for 24:00:00.000
1469
+ if (config._a[HOUR] === 24 &&
1470
+ config._a[MINUTE] === 0 &&
1471
+ config._a[SECOND] === 0 &&
1472
+ config._a[MILLISECOND] === 0) {
1473
+ config._nextDay = true;
1474
+ config._a[HOUR] = 0;
1475
+ }
1476
+
1477
+ config._d = (config._useUTC ? makeUTCDate : makeDate).apply(null, input);
1478
+ // Apply timezone offset from input. The actual utcOffset can be changed
1479
+ // with parseZone.
1480
+ if (config._tzm != null) {
1481
+ config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
1482
+ }
1483
+
1484
+ if (config._nextDay) {
1485
+ config._a[HOUR] = 24;
1486
+ }
1487
+ }
1488
+
1489
+ function dateFromObject(config) {
1490
+ var normalizedInput;
1491
+
1492
+ if (config._d) {
1493
+ return;
1494
+ }
1495
+
1496
+ normalizedInput = normalizeObjectUnits(config._i);
1497
+ config._a = [
1498
+ normalizedInput.year,
1499
+ normalizedInput.month,
1500
+ normalizedInput.day || normalizedInput.date,
1501
+ normalizedInput.hour,
1502
+ normalizedInput.minute,
1503
+ normalizedInput.second,
1504
+ normalizedInput.millisecond
1505
+ ];
1506
+
1507
+ dateFromConfig(config);
1508
+ }
1509
+
1510
+ function currentDateArray(config) {
1511
+ var now = new Date();
1512
+ if (config._useUTC) {
1513
+ return [
1514
+ now.getUTCFullYear(),
1515
+ now.getUTCMonth(),
1516
+ now.getUTCDate()
1517
+ ];
1518
+ } else {
1519
+ return [now.getFullYear(), now.getMonth(), now.getDate()];
1520
+ }
1521
+ }
1522
+
1523
+ // date from string and format string
1524
+ function makeDateFromStringAndFormat(config) {
1525
+ if (config._f === moment.ISO_8601) {
1526
+ parseISO(config);
1527
+ return;
1528
+ }
1529
+
1530
+ config._a = [];
1531
+ config._pf.empty = true;
1532
+
1533
+ // This array is used to make a Date, either with `new Date` or `Date.UTC`
1534
+ var string = '' + config._i,
1535
+ i, parsedInput, tokens, token, skipped,
1536
+ stringLength = string.length,
1537
+ totalParsedInputLength = 0;
1538
+
1539
+ tokens = expandFormat(config._f, config._locale).match(formattingTokens) || [];
1540
+
1541
+ for (i = 0; i < tokens.length; i++) {
1542
+ token = tokens[i];
1543
+ parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0];
1544
+ if (parsedInput) {
1545
+ skipped = string.substr(0, string.indexOf(parsedInput));
1546
+ if (skipped.length > 0) {
1547
+ config._pf.unusedInput.push(skipped);
1548
+ }
1549
+ string = string.slice(string.indexOf(parsedInput) + parsedInput.length);
1550
+ totalParsedInputLength += parsedInput.length;
1551
+ }
1552
+ // don't parse if it's not a known token
1553
+ if (formatTokenFunctions[token]) {
1554
+ if (parsedInput) {
1555
+ config._pf.empty = false;
1556
+ }
1557
+ else {
1558
+ config._pf.unusedTokens.push(token);
1559
+ }
1560
+ addTimeToArrayFromToken(token, parsedInput, config);
1561
+ }
1562
+ else if (config._strict && !parsedInput) {
1563
+ config._pf.unusedTokens.push(token);
1564
+ }
1565
+ }
1566
+
1567
+ // add remaining unparsed input length to the string
1568
+ config._pf.charsLeftOver = stringLength - totalParsedInputLength;
1569
+ if (string.length > 0) {
1570
+ config._pf.unusedInput.push(string);
1571
+ }
1572
+
1573
+ // clear _12h flag if hour is <= 12
1574
+ if (config._pf.bigHour === true && config._a[HOUR] <= 12) {
1575
+ config._pf.bigHour = undefined;
1576
+ }
1577
+ // handle meridiem
1578
+ config._a[HOUR] = meridiemFixWrap(config._locale, config._a[HOUR],
1579
+ config._meridiem);
1580
+ dateFromConfig(config);
1581
+ checkOverflow(config);
1582
+ }
1583
+
1584
+ function unescapeFormat(s) {
1585
+ return s.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) {
1586
+ return p1 || p2 || p3 || p4;
1587
+ });
1588
+ }
1589
+
1590
+ // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
1591
+ function regexpEscape(s) {
1592
+ return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
1593
+ }
1594
+
1595
+ // date from string and array of format strings
1596
+ function makeDateFromStringAndArray(config) {
1597
+ var tempConfig,
1598
+ bestMoment,
1599
+
1600
+ scoreToBeat,
1601
+ i,
1602
+ currentScore;
1603
+
1604
+ if (config._f.length === 0) {
1605
+ config._pf.invalidFormat = true;
1606
+ config._d = new Date(NaN);
1607
+ return;
1608
+ }
1609
+
1610
+ for (i = 0; i < config._f.length; i++) {
1611
+ currentScore = 0;
1612
+ tempConfig = copyConfig({}, config);
1613
+ if (config._useUTC != null) {
1614
+ tempConfig._useUTC = config._useUTC;
1615
+ }
1616
+ tempConfig._pf = defaultParsingFlags();
1617
+ tempConfig._f = config._f[i];
1618
+ makeDateFromStringAndFormat(tempConfig);
1619
+
1620
+ if (!isValid(tempConfig)) {
1621
+ continue;
1622
+ }
1623
+
1624
+ // if there is any input that was not parsed add a penalty for that format
1625
+ currentScore += tempConfig._pf.charsLeftOver;
1626
+
1627
+ //or tokens
1628
+ currentScore += tempConfig._pf.unusedTokens.length * 10;
1629
+
1630
+ tempConfig._pf.score = currentScore;
1631
+
1632
+ if (scoreToBeat == null || currentScore < scoreToBeat) {
1633
+ scoreToBeat = currentScore;
1634
+ bestMoment = tempConfig;
1635
+ }
1636
+ }
1637
+
1638
+ extend(config, bestMoment || tempConfig);
1639
+ }
1640
+
1641
+ // date from iso format
1642
+ function parseISO(config) {
1643
+ var i, l,
1644
+ string = config._i,
1645
+ match = isoRegex.exec(string);
1646
+
1647
+ if (match) {
1648
+ config._pf.iso = true;
1649
+ for (i = 0, l = isoDates.length; i < l; i++) {
1650
+ if (isoDates[i][1].exec(string)) {
1651
+ // match[5] should be 'T' or undefined
1652
+ config._f = isoDates[i][0] + (match[6] || ' ');
1653
+ break;
1654
+ }
1655
+ }
1656
+ for (i = 0, l = isoTimes.length; i < l; i++) {
1657
+ if (isoTimes[i][1].exec(string)) {
1658
+ config._f += isoTimes[i][0];
1659
+ break;
1660
+ }
1661
+ }
1662
+ if (string.match(parseTokenTimezone)) {
1663
+ config._f += 'Z';
1664
+ }
1665
+ makeDateFromStringAndFormat(config);
1666
+ } else {
1667
+ config._isValid = false;
1668
+ }
1669
+ }
1670
+
1671
+ // date from iso format or fallback
1672
+ function makeDateFromString(config) {
1673
+ parseISO(config);
1674
+ if (config._isValid === false) {
1675
+ delete config._isValid;
1676
+ moment.createFromInputFallback(config);
1677
+ }
1678
+ }
1679
+
1680
+ function map(arr, fn) {
1681
+ var res = [], i;
1682
+ for (i = 0; i < arr.length; ++i) {
1683
+ res.push(fn(arr[i], i));
1684
+ }
1685
+ return res;
1686
+ }
1687
+
1688
+ function makeDateFromInput(config) {
1689
+ var input = config._i, matched;
1690
+ if (input === undefined) {
1691
+ config._d = new Date();
1692
+ } else if (isDate(input)) {
1693
+ config._d = new Date(+input);
1694
+ } else if ((matched = aspNetJsonRegex.exec(input)) !== null) {
1695
+ config._d = new Date(+matched[1]);
1696
+ } else if (typeof input === 'string') {
1697
+ makeDateFromString(config);
1698
+ } else if (isArray(input)) {
1699
+ config._a = map(input.slice(0), function (obj) {
1700
+ return parseInt(obj, 10);
1701
+ });
1702
+ dateFromConfig(config);
1703
+ } else if (typeof(input) === 'object') {
1704
+ dateFromObject(config);
1705
+ } else if (typeof(input) === 'number') {
1706
+ // from milliseconds
1707
+ config._d = new Date(input);
1708
+ } else {
1709
+ moment.createFromInputFallback(config);
1710
+ }
1711
+ }
1712
+
1713
+ function makeDate(y, m, d, h, M, s, ms) {
1714
+ //can't just apply() to create a date:
1715
+ //http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply
1716
+ var date = new Date(y, m, d, h, M, s, ms);
1717
+
1718
+ //the date constructor doesn't accept years < 1970
1719
+ if (y < 1970) {
1720
+ date.setFullYear(y);
1721
+ }
1722
+ return date;
1723
+ }
1724
+
1725
+ function makeUTCDate(y) {
1726
+ var date = new Date(Date.UTC.apply(null, arguments));
1727
+ if (y < 1970) {
1728
+ date.setUTCFullYear(y);
1729
+ }
1730
+ return date;
1731
+ }
1732
+
1733
+ function parseWeekday(input, locale) {
1734
+ if (typeof input === 'string') {
1735
+ if (!isNaN(input)) {
1736
+ input = parseInt(input, 10);
1737
+ }
1738
+ else {
1739
+ input = locale.weekdaysParse(input);
1740
+ if (typeof input !== 'number') {
1741
+ return null;
1742
+ }
1743
+ }
1744
+ }
1745
+ return input;
1746
+ }
1747
+
1748
+ /************************************
1749
+ Relative Time
1750
+ ************************************/
1751
+
1752
+
1753
+ // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize
1754
+ function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) {
1755
+ return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture);
1756
+ }
1757
+
1758
+ function relativeTime(posNegDuration, withoutSuffix, locale) {
1759
+ var duration = moment.duration(posNegDuration).abs(),
1760
+ seconds = round(duration.as('s')),
1761
+ minutes = round(duration.as('m')),
1762
+ hours = round(duration.as('h')),
1763
+ days = round(duration.as('d')),
1764
+ months = round(duration.as('M')),
1765
+ years = round(duration.as('y')),
1766
+
1767
+ args = seconds < relativeTimeThresholds.s && ['s', seconds] ||
1768
+ minutes === 1 && ['m'] ||
1769
+ minutes < relativeTimeThresholds.m && ['mm', minutes] ||
1770
+ hours === 1 && ['h'] ||
1771
+ hours < relativeTimeThresholds.h && ['hh', hours] ||
1772
+ days === 1 && ['d'] ||
1773
+ days < relativeTimeThresholds.d && ['dd', days] ||
1774
+ months === 1 && ['M'] ||
1775
+ months < relativeTimeThresholds.M && ['MM', months] ||
1776
+ years === 1 && ['y'] || ['yy', years];
1777
+
1778
+ args[2] = withoutSuffix;
1779
+ args[3] = +posNegDuration > 0;
1780
+ args[4] = locale;
1781
+ return substituteTimeAgo.apply({}, args);
1782
+ }
1783
+
1784
+
1785
+ /************************************
1786
+ Week of Year
1787
+ ************************************/
1788
+
1789
+
1790
+ // firstDayOfWeek 0 = sun, 6 = sat
1791
+ // the day of the week that starts the week
1792
+ // (usually sunday or monday)
1793
+ // firstDayOfWeekOfYear 0 = sun, 6 = sat
1794
+ // the first week is the week that contains the first
1795
+ // of this day of the week
1796
+ // (eg. ISO weeks use thursday (4))
1797
+ function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) {
1798
+ var end = firstDayOfWeekOfYear - firstDayOfWeek,
1799
+ daysToDayOfWeek = firstDayOfWeekOfYear - mom.day(),
1800
+ adjustedMoment;
1801
+
1802
+
1803
+ if (daysToDayOfWeek > end) {
1804
+ daysToDayOfWeek -= 7;
1805
+ }
1806
+
1807
+ if (daysToDayOfWeek < end - 7) {
1808
+ daysToDayOfWeek += 7;
1809
+ }
1810
+
1811
+ adjustedMoment = moment(mom).add(daysToDayOfWeek, 'd');
1812
+ return {
1813
+ week: Math.ceil(adjustedMoment.dayOfYear() / 7),
1814
+ year: adjustedMoment.year()
1815
+ };
1816
+ }
1817
+
1818
+ //http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday
1819
+ function dayOfYearFromWeeks(year, week, weekday, firstDayOfWeekOfYear, firstDayOfWeek) {
1820
+ var d = makeUTCDate(year, 0, 1).getUTCDay(), daysToAdd, dayOfYear;
1821
+
1822
+ d = d === 0 ? 7 : d;
1823
+ weekday = weekday != null ? weekday : firstDayOfWeek;
1824
+ daysToAdd = firstDayOfWeek - d + (d > firstDayOfWeekOfYear ? 7 : 0) - (d < firstDayOfWeek ? 7 : 0);
1825
+ dayOfYear = 7 * (week - 1) + (weekday - firstDayOfWeek) + daysToAdd + 1;
1826
+
1827
+ return {
1828
+ year: dayOfYear > 0 ? year : year - 1,
1829
+ dayOfYear: dayOfYear > 0 ? dayOfYear : daysInYear(year - 1) + dayOfYear
1830
+ };
1831
+ }
1832
+
1833
+ /************************************
1834
+ Top Level Functions
1835
+ ************************************/
1836
+
1837
+ function makeMoment(config) {
1838
+ var input = config._i,
1839
+ format = config._f,
1840
+ res;
1841
+
1842
+ config._locale = config._locale || moment.localeData(config._l);
1843
+
1844
+ if (input === null || (format === undefined && input === '')) {
1845
+ return moment.invalid({nullInput: true});
1846
+ }
1847
+
1848
+ if (typeof input === 'string') {
1849
+ config._i = input = config._locale.preparse(input);
1850
+ }
1851
+
1852
+ if (moment.isMoment(input)) {
1853
+ return new Moment(input, true);
1854
+ } else if (format) {
1855
+ if (isArray(format)) {
1856
+ makeDateFromStringAndArray(config);
1857
+ } else {
1858
+ makeDateFromStringAndFormat(config);
1859
+ }
1860
+ } else {
1861
+ makeDateFromInput(config);
1862
+ }
1863
+
1864
+ res = new Moment(config);
1865
+ if (res._nextDay) {
1866
+ // Adding is smart enough around DST
1867
+ res.add(1, 'd');
1868
+ res._nextDay = undefined;
1869
+ }
1870
+
1871
+ return res;
1872
+ }
1873
+
1874
+ moment = function (input, format, locale, strict) {
1875
+ var c;
1876
+
1877
+ if (typeof(locale) === 'boolean') {
1878
+ strict = locale;
1879
+ locale = undefined;
1880
+ }
1881
+ // object construction must be done this way.
1882
+ // https://github.com/moment/moment/issues/1423
1883
+ c = {};
1884
+ c._isAMomentObject = true;
1885
+ c._i = input;
1886
+ c._f = format;
1887
+ c._l = locale;
1888
+ c._strict = strict;
1889
+ c._isUTC = false;
1890
+ c._pf = defaultParsingFlags();
1891
+
1892
+ return makeMoment(c);
1893
+ };
1894
+
1895
+ moment.suppressDeprecationWarnings = false;
1896
+
1897
+ moment.createFromInputFallback = deprecate(
1898
+ 'moment construction falls back to js Date. This is ' +
1899
+ 'discouraged and will be removed in upcoming major ' +
1900
+ 'release. Please refer to ' +
1901
+ 'https://github.com/moment/moment/issues/1407 for more info.',
1902
+ function (config) {
1903
+ config._d = new Date(config._i + (config._useUTC ? ' UTC' : ''));
1904
+ }
1905
+ );
1906
+
1907
+ // Pick a moment m from moments so that m[fn](other) is true for all
1908
+ // other. This relies on the function fn to be transitive.
1909
+ //
1910
+ // moments should either be an array of moment objects or an array, whose
1911
+ // first element is an array of moment objects.
1912
+ function pickBy(fn, moments) {
1913
+ var res, i;
1914
+ if (moments.length === 1 && isArray(moments[0])) {
1915
+ moments = moments[0];
1916
+ }
1917
+ if (!moments.length) {
1918
+ return moment();
1919
+ }
1920
+ res = moments[0];
1921
+ for (i = 1; i < moments.length; ++i) {
1922
+ if (moments[i][fn](res)) {
1923
+ res = moments[i];
1924
+ }
1925
+ }
1926
+ return res;
1927
+ }
1928
+
1929
+ moment.min = function () {
1930
+ var args = [].slice.call(arguments, 0);
1931
+
1932
+ return pickBy('isBefore', args);
1933
+ };
1934
+
1935
+ moment.max = function () {
1936
+ var args = [].slice.call(arguments, 0);
1937
+
1938
+ return pickBy('isAfter', args);
1939
+ };
1940
+
1941
+ // creating with utc
1942
+ moment.utc = function (input, format, locale, strict) {
1943
+ var c;
1944
+
1945
+ if (typeof(locale) === 'boolean') {
1946
+ strict = locale;
1947
+ locale = undefined;
1948
+ }
1949
+ // object construction must be done this way.
1950
+ // https://github.com/moment/moment/issues/1423
1951
+ c = {};
1952
+ c._isAMomentObject = true;
1953
+ c._useUTC = true;
1954
+ c._isUTC = true;
1955
+ c._l = locale;
1956
+ c._i = input;
1957
+ c._f = format;
1958
+ c._strict = strict;
1959
+ c._pf = defaultParsingFlags();
1960
+
1961
+ return makeMoment(c).utc();
1962
+ };
1963
+
1964
+ // creating with unix timestamp (in seconds)
1965
+ moment.unix = function (input) {
1966
+ return moment(input * 1000);
1967
+ };
1968
+
1969
+ // duration
1970
+ moment.duration = function (input, key) {
1971
+ var duration = input,
1972
+ // matching against regexp is expensive, do it on demand
1973
+ match = null,
1974
+ sign,
1975
+ ret,
1976
+ parseIso,
1977
+ diffRes;
1978
+
1979
+ if (moment.isDuration(input)) {
1980
+ duration = {
1981
+ ms: input._milliseconds,
1982
+ d: input._days,
1983
+ M: input._months
1984
+ };
1985
+ } else if (typeof input === 'number') {
1986
+ duration = {};
1987
+ if (key) {
1988
+ duration[key] = input;
1989
+ } else {
1990
+ duration.milliseconds = input;
1991
+ }
1992
+ } else if (!!(match = aspNetTimeSpanJsonRegex.exec(input))) {
1993
+ sign = (match[1] === '-') ? -1 : 1;
1994
+ duration = {
1995
+ y: 0,
1996
+ d: toInt(match[DATE]) * sign,
1997
+ h: toInt(match[HOUR]) * sign,
1998
+ m: toInt(match[MINUTE]) * sign,
1999
+ s: toInt(match[SECOND]) * sign,
2000
+ ms: toInt(match[MILLISECOND]) * sign
2001
+ };
2002
+ } else if (!!(match = isoDurationRegex.exec(input))) {
2003
+ sign = (match[1] === '-') ? -1 : 1;
2004
+ parseIso = function (inp) {
2005
+ // We'd normally use ~~inp for this, but unfortunately it also
2006
+ // converts floats to ints.
2007
+ // inp may be undefined, so careful calling replace on it.
2008
+ var res = inp && parseFloat(inp.replace(',', '.'));
2009
+ // apply sign while we're at it
2010
+ return (isNaN(res) ? 0 : res) * sign;
2011
+ };
2012
+ duration = {
2013
+ y: parseIso(match[2]),
2014
+ M: parseIso(match[3]),
2015
+ d: parseIso(match[4]),
2016
+ h: parseIso(match[5]),
2017
+ m: parseIso(match[6]),
2018
+ s: parseIso(match[7]),
2019
+ w: parseIso(match[8])
2020
+ };
2021
+ } else if (duration == null) {// checks for null or undefined
2022
+ duration = {};
2023
+ } else if (typeof duration === 'object' &&
2024
+ ('from' in duration || 'to' in duration)) {
2025
+ diffRes = momentsDifference(moment(duration.from), moment(duration.to));
2026
+
2027
+ duration = {};
2028
+ duration.ms = diffRes.milliseconds;
2029
+ duration.M = diffRes.months;
2030
+ }
2031
+
2032
+ ret = new Duration(duration);
2033
+
2034
+ if (moment.isDuration(input) && hasOwnProp(input, '_locale')) {
2035
+ ret._locale = input._locale;
2036
+ }
2037
+
2038
+ return ret;
2039
+ };
2040
+
2041
+ // version number
2042
+ moment.version = VERSION;
2043
+
2044
+ // default format
2045
+ moment.defaultFormat = isoFormat;
2046
+
2047
+ // constant that refers to the ISO standard
2048
+ moment.ISO_8601 = function () {};
2049
+
2050
+ // Plugins that add properties should also add the key here (null value),
2051
+ // so we can properly clone ourselves.
2052
+ moment.momentProperties = momentProperties;
2053
+
2054
+ // This function will be called whenever a moment is mutated.
2055
+ // It is intended to keep the offset in sync with the timezone.
2056
+ moment.updateOffset = function () {};
2057
+
2058
+ // This function allows you to set a threshold for relative time strings
2059
+ moment.relativeTimeThreshold = function (threshold, limit) {
2060
+ if (relativeTimeThresholds[threshold] === undefined) {
2061
+ return false;
2062
+ }
2063
+ if (limit === undefined) {
2064
+ return relativeTimeThresholds[threshold];
2065
+ }
2066
+ relativeTimeThresholds[threshold] = limit;
2067
+ return true;
2068
+ };
2069
+
2070
+ moment.lang = deprecate(
2071
+ 'moment.lang is deprecated. Use moment.locale instead.',
2072
+ function (key, value) {
2073
+ return moment.locale(key, value);
2074
+ }
2075
+ );
2076
+
2077
+ // This function will load locale and then set the global locale. If
2078
+ // no arguments are passed in, it will simply return the current global
2079
+ // locale key.
2080
+ moment.locale = function (key, values) {
2081
+ var data;
2082
+ if (key) {
2083
+ if (typeof(values) !== 'undefined') {
2084
+ data = moment.defineLocale(key, values);
2085
+ }
2086
+ else {
2087
+ data = moment.localeData(key);
2088
+ }
2089
+
2090
+ if (data) {
2091
+ moment.duration._locale = moment._locale = data;
2092
+ }
2093
+ }
2094
+
2095
+ return moment._locale._abbr;
2096
+ };
2097
+
2098
+ moment.defineLocale = function (name, values) {
2099
+ if (values !== null) {
2100
+ values.abbr = name;
2101
+ if (!locales[name]) {
2102
+ locales[name] = new Locale();
2103
+ }
2104
+ locales[name].set(values);
2105
+
2106
+ // backwards compat for now: also set the locale
2107
+ moment.locale(name);
2108
+
2109
+ return locales[name];
2110
+ } else {
2111
+ // useful for testing
2112
+ delete locales[name];
2113
+ return null;
2114
+ }
2115
+ };
2116
+
2117
+ moment.langData = deprecate(
2118
+ 'moment.langData is deprecated. Use moment.localeData instead.',
2119
+ function (key) {
2120
+ return moment.localeData(key);
2121
+ }
2122
+ );
2123
+
2124
+ // returns locale data
2125
+ moment.localeData = function (key) {
2126
+ var locale;
2127
+
2128
+ if (key && key._locale && key._locale._abbr) {
2129
+ key = key._locale._abbr;
2130
+ }
2131
+
2132
+ if (!key) {
2133
+ return moment._locale;
2134
+ }
2135
+
2136
+ if (!isArray(key)) {
2137
+ //short-circuit everything else
2138
+ locale = loadLocale(key);
2139
+ if (locale) {
2140
+ return locale;
2141
+ }
2142
+ key = [key];
2143
+ }
2144
+
2145
+ return chooseLocale(key);
2146
+ };
2147
+
2148
+ // compare moment object
2149
+ moment.isMoment = function (obj) {
2150
+ return obj instanceof Moment ||
2151
+ (obj != null && hasOwnProp(obj, '_isAMomentObject'));
2152
+ };
2153
+
2154
+ // for typechecking Duration objects
2155
+ moment.isDuration = function (obj) {
2156
+ return obj instanceof Duration;
2157
+ };
2158
+
2159
+ for (i = lists.length - 1; i >= 0; --i) {
2160
+ makeList(lists[i]);
2161
+ }
2162
+
2163
+ moment.normalizeUnits = function (units) {
2164
+ return normalizeUnits(units);
2165
+ };
2166
+
2167
+ moment.invalid = function (flags) {
2168
+ var m = moment.utc(NaN);
2169
+ if (flags != null) {
2170
+ extend(m._pf, flags);
2171
+ }
2172
+ else {
2173
+ m._pf.userInvalidated = true;
2174
+ }
2175
+
2176
+ return m;
2177
+ };
2178
+
2179
+ moment.parseZone = function () {
2180
+ return moment.apply(null, arguments).parseZone();
2181
+ };
2182
+
2183
+ moment.parseTwoDigitYear = function (input) {
2184
+ return toInt(input) + (toInt(input) > 68 ? 1900 : 2000);
2185
+ };
2186
+
2187
+ moment.isDate = isDate;
2188
+
2189
+ /************************************
2190
+ Moment Prototype
2191
+ ************************************/
2192
+
2193
+
2194
+ extend(moment.fn = Moment.prototype, {
2195
+
2196
+ clone : function () {
2197
+ return moment(this);
2198
+ },
2199
+
2200
+ valueOf : function () {
2201
+ return +this._d - ((this._offset || 0) * 60000);
2202
+ },
2203
+
2204
+ unix : function () {
2205
+ return Math.floor(+this / 1000);
2206
+ },
2207
+
2208
+ toString : function () {
2209
+ return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ');
2210
+ },
2211
+
2212
+ toDate : function () {
2213
+ return this._offset ? new Date(+this) : this._d;
2214
+ },
2215
+
2216
+ toISOString : function () {
2217
+ var m = moment(this).utc();
2218
+ if (0 < m.year() && m.year() <= 9999) {
2219
+ if ('function' === typeof Date.prototype.toISOString) {
2220
+ // native implementation is ~50x faster, use it when we can
2221
+ return this.toDate().toISOString();
2222
+ } else {
2223
+ return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
2224
+ }
2225
+ } else {
2226
+ return formatMoment(m, 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
2227
+ }
2228
+ },
2229
+
2230
+ toArray : function () {
2231
+ var m = this;
2232
+ return [
2233
+ m.year(),
2234
+ m.month(),
2235
+ m.date(),
2236
+ m.hours(),
2237
+ m.minutes(),
2238
+ m.seconds(),
2239
+ m.milliseconds()
2240
+ ];
2241
+ },
2242
+
2243
+ isValid : function () {
2244
+ return isValid(this);
2245
+ },
2246
+
2247
+ isDSTShifted : function () {
2248
+ if (this._a) {
2249
+ return this.isValid() && compareArrays(this._a, (this._isUTC ? moment.utc(this._a) : moment(this._a)).toArray()) > 0;
2250
+ }
2251
+
2252
+ return false;
2253
+ },
2254
+
2255
+ parsingFlags : function () {
2256
+ return extend({}, this._pf);
2257
+ },
2258
+
2259
+ invalidAt: function () {
2260
+ return this._pf.overflow;
2261
+ },
2262
+
2263
+ utc : function (keepLocalTime) {
2264
+ return this.utcOffset(0, keepLocalTime);
2265
+ },
2266
+
2267
+ local : function (keepLocalTime) {
2268
+ if (this._isUTC) {
2269
+ this.utcOffset(0, keepLocalTime);
2270
+ this._isUTC = false;
2271
+
2272
+ if (keepLocalTime) {
2273
+ this.subtract(this._dateUtcOffset(), 'm');
2274
+ }
2275
+ }
2276
+ return this;
2277
+ },
2278
+
2279
+ format : function (inputString) {
2280
+ var output = formatMoment(this, inputString || moment.defaultFormat);
2281
+ return this.localeData().postformat(output);
2282
+ },
2283
+
2284
+ add : createAdder(1, 'add'),
2285
+
2286
+ subtract : createAdder(-1, 'subtract'),
2287
+
2288
+ diff : function (input, units, asFloat) {
2289
+ var that = makeAs(input, this),
2290
+ zoneDiff = (that.utcOffset() - this.utcOffset()) * 6e4,
2291
+ anchor, diff, output, daysAdjust;
2292
+
2293
+ units = normalizeUnits(units);
2294
+
2295
+ if (units === 'year' || units === 'month' || units === 'quarter') {
2296
+ output = monthDiff(this, that);
2297
+ if (units === 'quarter') {
2298
+ output = output / 3;
2299
+ } else if (units === 'year') {
2300
+ output = output / 12;
2301
+ }
2302
+ } else {
2303
+ diff = this - that;
2304
+ output = units === 'second' ? diff / 1e3 : // 1000
2305
+ units === 'minute' ? diff / 6e4 : // 1000 * 60
2306
+ units === 'hour' ? diff / 36e5 : // 1000 * 60 * 60
2307
+ units === 'day' ? (diff - zoneDiff) / 864e5 : // 1000 * 60 * 60 * 24, negate dst
2308
+ units === 'week' ? (diff - zoneDiff) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst
2309
+ diff;
2310
+ }
2311
+ return asFloat ? output : absRound(output);
2312
+ },
2313
+
2314
+ from : function (time, withoutSuffix) {
2315
+ return moment.duration({to: this, from: time}).locale(this.locale()).humanize(!withoutSuffix);
2316
+ },
2317
+
2318
+ fromNow : function (withoutSuffix) {
2319
+ return this.from(moment(), withoutSuffix);
2320
+ },
2321
+
2322
+ calendar : function (time) {
2323
+ // We want to compare the start of today, vs this.
2324
+ // Getting start-of-today depends on whether we're locat/utc/offset
2325
+ // or not.
2326
+ var now = time || moment(),
2327
+ sod = makeAs(now, this).startOf('day'),
2328
+ diff = this.diff(sod, 'days', true),
2329
+ format = diff < -6 ? 'sameElse' :
2330
+ diff < -1 ? 'lastWeek' :
2331
+ diff < 0 ? 'lastDay' :
2332
+ diff < 1 ? 'sameDay' :
2333
+ diff < 2 ? 'nextDay' :
2334
+ diff < 7 ? 'nextWeek' : 'sameElse';
2335
+ return this.format(this.localeData().calendar(format, this, moment(now)));
2336
+ },
2337
+
2338
+ isLeapYear : function () {
2339
+ return isLeapYear(this.year());
2340
+ },
2341
+
2342
+ isDST : function () {
2343
+ return (this.utcOffset() > this.clone().month(0).utcOffset() ||
2344
+ this.utcOffset() > this.clone().month(5).utcOffset());
2345
+ },
2346
+
2347
+ day : function (input) {
2348
+ var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay();
2349
+ if (input != null) {
2350
+ input = parseWeekday(input, this.localeData());
2351
+ return this.add(input - day, 'd');
2352
+ } else {
2353
+ return day;
2354
+ }
2355
+ },
2356
+
2357
+ month : makeAccessor('Month', true),
2358
+
2359
+ startOf : function (units) {
2360
+ units = normalizeUnits(units);
2361
+ // the following switch intentionally omits break keywords
2362
+ // to utilize falling through the cases.
2363
+ switch (units) {
2364
+ case 'year':
2365
+ this.month(0);
2366
+ /* falls through */
2367
+ case 'quarter':
2368
+ case 'month':
2369
+ this.date(1);
2370
+ /* falls through */
2371
+ case 'week':
2372
+ case 'isoWeek':
2373
+ case 'day':
2374
+ this.hours(0);
2375
+ /* falls through */
2376
+ case 'hour':
2377
+ this.minutes(0);
2378
+ /* falls through */
2379
+ case 'minute':
2380
+ this.seconds(0);
2381
+ /* falls through */
2382
+ case 'second':
2383
+ this.milliseconds(0);
2384
+ /* falls through */
2385
+ }
2386
+
2387
+ // weeks are a special case
2388
+ if (units === 'week') {
2389
+ this.weekday(0);
2390
+ } else if (units === 'isoWeek') {
2391
+ this.isoWeekday(1);
2392
+ }
2393
+
2394
+ // quarters are also special
2395
+ if (units === 'quarter') {
2396
+ this.month(Math.floor(this.month() / 3) * 3);
2397
+ }
2398
+
2399
+ return this;
2400
+ },
2401
+
2402
+ endOf: function (units) {
2403
+ units = normalizeUnits(units);
2404
+ if (units === undefined || units === 'millisecond') {
2405
+ return this;
2406
+ }
2407
+ return this.startOf(units).add(1, (units === 'isoWeek' ? 'week' : units)).subtract(1, 'ms');
2408
+ },
2409
+
2410
+ isAfter: function (input, units) {
2411
+ var inputMs;
2412
+ units = normalizeUnits(typeof units !== 'undefined' ? units : 'millisecond');
2413
+ if (units === 'millisecond') {
2414
+ input = moment.isMoment(input) ? input : moment(input);
2415
+ return +this > +input;
2416
+ } else {
2417
+ inputMs = moment.isMoment(input) ? +input : +moment(input);
2418
+ return inputMs < +this.clone().startOf(units);
2419
+ }
2420
+ },
2421
+
2422
+ isBefore: function (input, units) {
2423
+ var inputMs;
2424
+ units = normalizeUnits(typeof units !== 'undefined' ? units : 'millisecond');
2425
+ if (units === 'millisecond') {
2426
+ input = moment.isMoment(input) ? input : moment(input);
2427
+ return +this < +input;
2428
+ } else {
2429
+ inputMs = moment.isMoment(input) ? +input : +moment(input);
2430
+ return +this.clone().endOf(units) < inputMs;
2431
+ }
2432
+ },
2433
+
2434
+ isBetween: function (from, to, units) {
2435
+ return this.isAfter(from, units) && this.isBefore(to, units);
2436
+ },
2437
+
2438
+ isSame: function (input, units) {
2439
+ var inputMs;
2440
+ units = normalizeUnits(units || 'millisecond');
2441
+ if (units === 'millisecond') {
2442
+ input = moment.isMoment(input) ? input : moment(input);
2443
+ return +this === +input;
2444
+ } else {
2445
+ inputMs = +moment(input);
2446
+ return +(this.clone().startOf(units)) <= inputMs && inputMs <= +(this.clone().endOf(units));
2447
+ }
2448
+ },
2449
+
2450
+ min: deprecate(
2451
+ 'moment().min is deprecated, use moment.min instead. https://github.com/moment/moment/issues/1548',
2452
+ function (other) {
2453
+ other = moment.apply(null, arguments);
2454
+ return other < this ? this : other;
2455
+ }
2456
+ ),
2457
+
2458
+ max: deprecate(
2459
+ 'moment().max is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548',
2460
+ function (other) {
2461
+ other = moment.apply(null, arguments);
2462
+ return other > this ? this : other;
2463
+ }
2464
+ ),
2465
+
2466
+ zone : deprecate(
2467
+ 'moment().zone is deprecated, use moment().utcOffset instead. ' +
2468
+ 'https://github.com/moment/moment/issues/1779',
2469
+ function (input, keepLocalTime) {
2470
+ if (input != null) {
2471
+ if (typeof input !== 'string') {
2472
+ input = -input;
2473
+ }
2474
+
2475
+ this.utcOffset(input, keepLocalTime);
2476
+
2477
+ return this;
2478
+ } else {
2479
+ return -this.utcOffset();
2480
+ }
2481
+ }
2482
+ ),
2483
+
2484
+ // keepLocalTime = true means only change the timezone, without
2485
+ // affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]-->
2486
+ // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset
2487
+ // +0200, so we adjust the time as needed, to be valid.
2488
+ //
2489
+ // Keeping the time actually adds/subtracts (one hour)
2490
+ // from the actual represented time. That is why we call updateOffset
2491
+ // a second time. In case it wants us to change the offset again
2492
+ // _changeInProgress == true case, then we have to adjust, because
2493
+ // there is no such time in the given timezone.
2494
+ utcOffset : function (input, keepLocalTime) {
2495
+ var offset = this._offset || 0,
2496
+ localAdjust;
2497
+ if (input != null) {
2498
+ if (typeof input === 'string') {
2499
+ input = utcOffsetFromString(input);
2500
+ }
2501
+ if (Math.abs(input) < 16) {
2502
+ input = input * 60;
2503
+ }
2504
+ if (!this._isUTC && keepLocalTime) {
2505
+ localAdjust = this._dateUtcOffset();
2506
+ }
2507
+ this._offset = input;
2508
+ this._isUTC = true;
2509
+ if (localAdjust != null) {
2510
+ this.add(localAdjust, 'm');
2511
+ }
2512
+ if (offset !== input) {
2513
+ if (!keepLocalTime || this._changeInProgress) {
2514
+ addOrSubtractDurationFromMoment(this,
2515
+ moment.duration(input - offset, 'm'), 1, false);
2516
+ } else if (!this._changeInProgress) {
2517
+ this._changeInProgress = true;
2518
+ moment.updateOffset(this, true);
2519
+ this._changeInProgress = null;
2520
+ }
2521
+ }
2522
+
2523
+ return this;
2524
+ } else {
2525
+ return this._isUTC ? offset : this._dateUtcOffset();
2526
+ }
2527
+ },
2528
+
2529
+ isLocal : function () {
2530
+ return !this._isUTC;
2531
+ },
2532
+
2533
+ isUtcOffset : function () {
2534
+ return this._isUTC;
2535
+ },
2536
+
2537
+ isUtc : function () {
2538
+ return this._isUTC && this._offset === 0;
2539
+ },
2540
+
2541
+ zoneAbbr : function () {
2542
+ return this._isUTC ? 'UTC' : '';
2543
+ },
2544
+
2545
+ zoneName : function () {
2546
+ return this._isUTC ? 'Coordinated Universal Time' : '';
2547
+ },
2548
+
2549
+ parseZone : function () {
2550
+ if (this._tzm) {
2551
+ this.utcOffset(this._tzm);
2552
+ } else if (typeof this._i === 'string') {
2553
+ this.utcOffset(utcOffsetFromString(this._i));
2554
+ }
2555
+ return this;
2556
+ },
2557
+
2558
+ hasAlignedHourOffset : function (input) {
2559
+ if (!input) {
2560
+ input = 0;
2561
+ }
2562
+ else {
2563
+ input = moment(input).utcOffset();
2564
+ }
2565
+
2566
+ return (this.utcOffset() - input) % 60 === 0;
2567
+ },
2568
+
2569
+ daysInMonth : function () {
2570
+ return daysInMonth(this.year(), this.month());
2571
+ },
2572
+
2573
+ dayOfYear : function (input) {
2574
+ var dayOfYear = round((moment(this).startOf('day') - moment(this).startOf('year')) / 864e5) + 1;
2575
+ return input == null ? dayOfYear : this.add((input - dayOfYear), 'd');
2576
+ },
2577
+
2578
+ quarter : function (input) {
2579
+ return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3);
2580
+ },
2581
+
2582
+ weekYear : function (input) {
2583
+ var year = weekOfYear(this, this.localeData()._week.dow, this.localeData()._week.doy).year;
2584
+ return input == null ? year : this.add((input - year), 'y');
2585
+ },
2586
+
2587
+ isoWeekYear : function (input) {
2588
+ var year = weekOfYear(this, 1, 4).year;
2589
+ return input == null ? year : this.add((input - year), 'y');
2590
+ },
2591
+
2592
+ week : function (input) {
2593
+ var week = this.localeData().week(this);
2594
+ return input == null ? week : this.add((input - week) * 7, 'd');
2595
+ },
2596
+
2597
+ isoWeek : function (input) {
2598
+ var week = weekOfYear(this, 1, 4).week;
2599
+ return input == null ? week : this.add((input - week) * 7, 'd');
2600
+ },
2601
+
2602
+ weekday : function (input) {
2603
+ var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7;
2604
+ return input == null ? weekday : this.add(input - weekday, 'd');
2605
+ },
2606
+
2607
+ isoWeekday : function (input) {
2608
+ // behaves the same as moment#day except
2609
+ // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6)
2610
+ // as a setter, sunday should belong to the previous week.
2611
+ return input == null ? this.day() || 7 : this.day(this.day() % 7 ? input : input - 7);
2612
+ },
2613
+
2614
+ isoWeeksInYear : function () {
2615
+ return weeksInYear(this.year(), 1, 4);
2616
+ },
2617
+
2618
+ weeksInYear : function () {
2619
+ var weekInfo = this.localeData()._week;
2620
+ return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy);
2621
+ },
2622
+
2623
+ get : function (units) {
2624
+ units = normalizeUnits(units);
2625
+ return this[units]();
2626
+ },
2627
+
2628
+ set : function (units, value) {
2629
+ var unit;
2630
+ if (typeof units === 'object') {
2631
+ for (unit in units) {
2632
+ this.set(unit, units[unit]);
2633
+ }
2634
+ }
2635
+ else {
2636
+ units = normalizeUnits(units);
2637
+ if (typeof this[units] === 'function') {
2638
+ this[units](value);
2639
+ }
2640
+ }
2641
+ return this;
2642
+ },
2643
+
2644
+ // If passed a locale key, it will set the locale for this
2645
+ // instance. Otherwise, it will return the locale configuration
2646
+ // variables for this instance.
2647
+ locale : function (key) {
2648
+ var newLocaleData;
2649
+
2650
+ if (key === undefined) {
2651
+ return this._locale._abbr;
2652
+ } else {
2653
+ newLocaleData = moment.localeData(key);
2654
+ if (newLocaleData != null) {
2655
+ this._locale = newLocaleData;
2656
+ }
2657
+ return this;
2658
+ }
2659
+ },
2660
+
2661
+ lang : deprecate(
2662
+ 'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.',
2663
+ function (key) {
2664
+ if (key === undefined) {
2665
+ return this.localeData();
2666
+ } else {
2667
+ return this.locale(key);
2668
+ }
2669
+ }
2670
+ ),
2671
+
2672
+ localeData : function () {
2673
+ return this._locale;
2674
+ },
2675
+
2676
+ _dateUtcOffset : function () {
2677
+ // On Firefox.24 Date#getTimezoneOffset returns a floating point.
2678
+ // https://github.com/moment/moment/pull/1871
2679
+ return -Math.round(this._d.getTimezoneOffset() / 15) * 15;
2680
+ }
2681
+
2682
+ });
2683
+
2684
+ function rawMonthSetter(mom, value) {
2685
+ var dayOfMonth;
2686
+
2687
+ // TODO: Move this out of here!
2688
+ if (typeof value === 'string') {
2689
+ value = mom.localeData().monthsParse(value);
2690
+ // TODO: Another silent failure?
2691
+ if (typeof value !== 'number') {
2692
+ return mom;
2693
+ }
2694
+ }
2695
+
2696
+ dayOfMonth = Math.min(mom.date(),
2697
+ daysInMonth(mom.year(), value));
2698
+ mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth);
2699
+ return mom;
2700
+ }
2701
+
2702
+ function rawGetter(mom, unit) {
2703
+ return mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]();
2704
+ }
2705
+
2706
+ function rawSetter(mom, unit, value) {
2707
+ if (unit === 'Month') {
2708
+ return rawMonthSetter(mom, value);
2709
+ } else {
2710
+ return mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value);
2711
+ }
2712
+ }
2713
+
2714
+ function makeAccessor(unit, keepTime) {
2715
+ return function (value) {
2716
+ if (value != null) {
2717
+ rawSetter(this, unit, value);
2718
+ moment.updateOffset(this, keepTime);
2719
+ return this;
2720
+ } else {
2721
+ return rawGetter(this, unit);
2722
+ }
2723
+ };
2724
+ }
2725
+
2726
+ moment.fn.millisecond = moment.fn.milliseconds = makeAccessor('Milliseconds', false);
2727
+ moment.fn.second = moment.fn.seconds = makeAccessor('Seconds', false);
2728
+ moment.fn.minute = moment.fn.minutes = makeAccessor('Minutes', false);
2729
+ // Setting the hour should keep the time, because the user explicitly
2730
+ // specified which hour he wants. So trying to maintain the same hour (in
2731
+ // a new timezone) makes sense. Adding/subtracting hours does not follow
2732
+ // this rule.
2733
+ moment.fn.hour = moment.fn.hours = makeAccessor('Hours', true);
2734
+ // moment.fn.month is defined separately
2735
+ moment.fn.date = makeAccessor('Date', true);
2736
+ moment.fn.dates = deprecate('dates accessor is deprecated. Use date instead.', makeAccessor('Date', true));
2737
+ moment.fn.year = makeAccessor('FullYear', true);
2738
+ moment.fn.years = deprecate('years accessor is deprecated. Use year instead.', makeAccessor('FullYear', true));
2739
+
2740
+ // add plural methods
2741
+ moment.fn.days = moment.fn.day;
2742
+ moment.fn.months = moment.fn.month;
2743
+ moment.fn.weeks = moment.fn.week;
2744
+ moment.fn.isoWeeks = moment.fn.isoWeek;
2745
+ moment.fn.quarters = moment.fn.quarter;
2746
+
2747
+ // add aliased format methods
2748
+ moment.fn.toJSON = moment.fn.toISOString;
2749
+
2750
+ // alias isUtc for dev-friendliness
2751
+ moment.fn.isUTC = moment.fn.isUtc;
2752
+
2753
+ /************************************
2754
+ Duration Prototype
2755
+ ************************************/
2756
+
2757
+
2758
+ function daysToYears (days) {
2759
+ // 400 years have 146097 days (taking into account leap year rules)
2760
+ return days * 400 / 146097;
2761
+ }
2762
+
2763
+ function yearsToDays (years) {
2764
+ // years * 365 + absRound(years / 4) -
2765
+ // absRound(years / 100) + absRound(years / 400);
2766
+ return years * 146097 / 400;
2767
+ }
2768
+
2769
+ extend(moment.duration.fn = Duration.prototype, {
2770
+
2771
+ _bubble : function () {
2772
+ var milliseconds = this._milliseconds,
2773
+ days = this._days,
2774
+ months = this._months,
2775
+ data = this._data,
2776
+ seconds, minutes, hours, years = 0;
2777
+
2778
+ // The following code bubbles up values, see the tests for
2779
+ // examples of what that means.
2780
+ data.milliseconds = milliseconds % 1000;
2781
+
2782
+ seconds = absRound(milliseconds / 1000);
2783
+ data.seconds = seconds % 60;
2784
+
2785
+ minutes = absRound(seconds / 60);
2786
+ data.minutes = minutes % 60;
2787
+
2788
+ hours = absRound(minutes / 60);
2789
+ data.hours = hours % 24;
2790
+
2791
+ days += absRound(hours / 24);
2792
+
2793
+ // Accurately convert days to years, assume start from year 0.
2794
+ years = absRound(daysToYears(days));
2795
+ days -= absRound(yearsToDays(years));
2796
+
2797
+ // 30 days to a month
2798
+ // TODO (iskren): Use anchor date (like 1st Jan) to compute this.
2799
+ months += absRound(days / 30);
2800
+ days %= 30;
2801
+
2802
+ // 12 months -> 1 year
2803
+ years += absRound(months / 12);
2804
+ months %= 12;
2805
+
2806
+ data.days = days;
2807
+ data.months = months;
2808
+ data.years = years;
2809
+ },
2810
+
2811
+ abs : function () {
2812
+ this._milliseconds = Math.abs(this._milliseconds);
2813
+ this._days = Math.abs(this._days);
2814
+ this._months = Math.abs(this._months);
2815
+
2816
+ this._data.milliseconds = Math.abs(this._data.milliseconds);
2817
+ this._data.seconds = Math.abs(this._data.seconds);
2818
+ this._data.minutes = Math.abs(this._data.minutes);
2819
+ this._data.hours = Math.abs(this._data.hours);
2820
+ this._data.months = Math.abs(this._data.months);
2821
+ this._data.years = Math.abs(this._data.years);
2822
+
2823
+ return this;
2824
+ },
2825
+
2826
+ weeks : function () {
2827
+ return absRound(this.days() / 7);
2828
+ },
2829
+
2830
+ valueOf : function () {
2831
+ return this._milliseconds +
2832
+ this._days * 864e5 +
2833
+ (this._months % 12) * 2592e6 +
2834
+ toInt(this._months / 12) * 31536e6;
2835
+ },
2836
+
2837
+ humanize : function (withSuffix) {
2838
+ var output = relativeTime(this, !withSuffix, this.localeData());
2839
+
2840
+ if (withSuffix) {
2841
+ output = this.localeData().pastFuture(+this, output);
2842
+ }
2843
+
2844
+ return this.localeData().postformat(output);
2845
+ },
2846
+
2847
+ add : function (input, val) {
2848
+ // supports only 2.0-style add(1, 's') or add(moment)
2849
+ var dur = moment.duration(input, val);
2850
+
2851
+ this._milliseconds += dur._milliseconds;
2852
+ this._days += dur._days;
2853
+ this._months += dur._months;
2854
+
2855
+ this._bubble();
2856
+
2857
+ return this;
2858
+ },
2859
+
2860
+ subtract : function (input, val) {
2861
+ var dur = moment.duration(input, val);
2862
+
2863
+ this._milliseconds -= dur._milliseconds;
2864
+ this._days -= dur._days;
2865
+ this._months -= dur._months;
2866
+
2867
+ this._bubble();
2868
+
2869
+ return this;
2870
+ },
2871
+
2872
+ get : function (units) {
2873
+ units = normalizeUnits(units);
2874
+ return this[units.toLowerCase() + 's']();
2875
+ },
2876
+
2877
+ as : function (units) {
2878
+ var days, months;
2879
+ units = normalizeUnits(units);
2880
+
2881
+ if (units === 'month' || units === 'year') {
2882
+ days = this._days + this._milliseconds / 864e5;
2883
+ months = this._months + daysToYears(days) * 12;
2884
+ return units === 'month' ? months : months / 12;
2885
+ } else {
2886
+ // handle milliseconds separately because of floating point math errors (issue #1867)
2887
+ days = this._days + Math.round(yearsToDays(this._months / 12));
2888
+ switch (units) {
2889
+ case 'week': return days / 7 + this._milliseconds / 6048e5;
2890
+ case 'day': return days + this._milliseconds / 864e5;
2891
+ case 'hour': return days * 24 + this._milliseconds / 36e5;
2892
+ case 'minute': return days * 24 * 60 + this._milliseconds / 6e4;
2893
+ case 'second': return days * 24 * 60 * 60 + this._milliseconds / 1000;
2894
+ // Math.floor prevents floating point math errors here
2895
+ case 'millisecond': return Math.floor(days * 24 * 60 * 60 * 1000) + this._milliseconds;
2896
+ default: throw new Error('Unknown unit ' + units);
2897
+ }
2898
+ }
2899
+ },
2900
+
2901
+ lang : moment.fn.lang,
2902
+ locale : moment.fn.locale,
2903
+
2904
+ toIsoString : deprecate(
2905
+ 'toIsoString() is deprecated. Please use toISOString() instead ' +
2906
+ '(notice the capitals)',
2907
+ function () {
2908
+ return this.toISOString();
2909
+ }
2910
+ ),
2911
+
2912
+ toISOString : function () {
2913
+ // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js
2914
+ var years = Math.abs(this.years()),
2915
+ months = Math.abs(this.months()),
2916
+ days = Math.abs(this.days()),
2917
+ hours = Math.abs(this.hours()),
2918
+ minutes = Math.abs(this.minutes()),
2919
+ seconds = Math.abs(this.seconds() + this.milliseconds() / 1000);
2920
+
2921
+ if (!this.asSeconds()) {
2922
+ // this is the same as C#'s (Noda) and python (isodate)...
2923
+ // but not other JS (goog.date)
2924
+ return 'P0D';
2925
+ }
2926
+
2927
+ return (this.asSeconds() < 0 ? '-' : '') +
2928
+ 'P' +
2929
+ (years ? years + 'Y' : '') +
2930
+ (months ? months + 'M' : '') +
2931
+ (days ? days + 'D' : '') +
2932
+ ((hours || minutes || seconds) ? 'T' : '') +
2933
+ (hours ? hours + 'H' : '') +
2934
+ (minutes ? minutes + 'M' : '') +
2935
+ (seconds ? seconds + 'S' : '');
2936
+ },
2937
+
2938
+ localeData : function () {
2939
+ return this._locale;
2940
+ },
2941
+
2942
+ toJSON : function () {
2943
+ return this.toISOString();
2944
+ }
2945
+ });
2946
+
2947
+ moment.duration.fn.toString = moment.duration.fn.toISOString;
2948
+
2949
+ function makeDurationGetter(name) {
2950
+ moment.duration.fn[name] = function () {
2951
+ return this._data[name];
2952
+ };
2953
+ }
2954
+
2955
+ for (i in unitMillisecondFactors) {
2956
+ if (hasOwnProp(unitMillisecondFactors, i)) {
2957
+ makeDurationGetter(i.toLowerCase());
2958
+ }
2959
+ }
2960
+
2961
+ moment.duration.fn.asMilliseconds = function () {
2962
+ return this.as('ms');
2963
+ };
2964
+ moment.duration.fn.asSeconds = function () {
2965
+ return this.as('s');
2966
+ };
2967
+ moment.duration.fn.asMinutes = function () {
2968
+ return this.as('m');
2969
+ };
2970
+ moment.duration.fn.asHours = function () {
2971
+ return this.as('h');
2972
+ };
2973
+ moment.duration.fn.asDays = function () {
2974
+ return this.as('d');
2975
+ };
2976
+ moment.duration.fn.asWeeks = function () {
2977
+ return this.as('weeks');
2978
+ };
2979
+ moment.duration.fn.asMonths = function () {
2980
+ return this.as('M');
2981
+ };
2982
+ moment.duration.fn.asYears = function () {
2983
+ return this.as('y');
2984
+ };
2985
+
2986
+ /************************************
2987
+ Default Locale
2988
+ ************************************/
2989
+
2990
+
2991
+ // Set default locale, other locale will inherit from English.
2992
+ moment.locale('en', {
2993
+ ordinalParse: /\d{1,2}(th|st|nd|rd)/,
2994
+ ordinal : function (number) {
2995
+ var b = number % 10,
2996
+ output = (toInt(number % 100 / 10) === 1) ? 'th' :
2997
+ (b === 1) ? 'st' :
2998
+ (b === 2) ? 'nd' :
2999
+ (b === 3) ? 'rd' : 'th';
3000
+ return number + output;
3001
+ }
3002
+ });
3003
+
3004
+ /* EMBED_LOCALES */
3005
+
3006
+ /************************************
3007
+ Exposing Moment
3008
+ ************************************/
3009
+
3010
+ function makeGlobal(shouldDeprecate) {
3011
+ /*global ender:false */
3012
+ if (typeof ender !== 'undefined') {
3013
+ return;
3014
+ }
3015
+ oldGlobalMoment = globalScope.moment;
3016
+ if (shouldDeprecate) {
3017
+ globalScope.moment = deprecate(
3018
+ 'Accessing Moment through the global scope is ' +
3019
+ 'deprecated, and will be removed in an upcoming ' +
3020
+ 'release.',
3021
+ moment);
3022
+ } else {
3023
+ globalScope.moment = moment;
3024
+ }
3025
+ }
3026
+
3027
+ // CommonJS module is defined
3028
+ if (hasModule) {
3029
+ module.exports = moment;
3030
+ } else if (typeof define === 'function' && define.amd) {
3031
+ define(function (require, exports, module) {
3032
+ if (module.config && module.config() && module.config().noGlobal === true) {
3033
+ // release the global variable
3034
+ globalScope.moment = oldGlobalMoment;
3035
+ }
3036
+
3037
+ return moment;
3038
+ });
3039
+ makeGlobal(true);
3040
+ } else {
3041
+ makeGlobal();
3042
+ }
3043
+ }).call(this);