tent-status 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. data/.gitignore +21 -0
  2. data/.kick +8 -0
  3. data/Gemfile +12 -0
  4. data/Gemfile.lock +232 -0
  5. data/LICENSE.txt +22 -0
  6. data/Procfile +1 -0
  7. data/README.md +14 -0
  8. data/Rakefile +43 -0
  9. data/assets/images/.gitkeep +0 -0
  10. data/assets/images/chosen-sprite.png +0 -0
  11. data/assets/images/glyphicons-halflings-white.png +0 -0
  12. data/assets/images/glyphicons-halflings.png +0 -0
  13. data/assets/javascripts/.gitkeep +0 -0
  14. data/assets/javascripts/application.js.coffee +122 -0
  15. data/assets/javascripts/backbone.js +1443 -0
  16. data/assets/javascripts/backbone_sync.js.coffee +60 -0
  17. data/assets/javascripts/boot.js.coffee +3 -0
  18. data/assets/javascripts/chosen.jquery.js +1129 -0
  19. data/assets/javascripts/collections/.gitkeep +0 -0
  20. data/assets/javascripts/collections/followers.js.coffee +5 -0
  21. data/assets/javascripts/collections/followings.js.coffee +5 -0
  22. data/assets/javascripts/collections/groups.js.coffee +5 -0
  23. data/assets/javascripts/collections/posts.js.coffee +5 -0
  24. data/assets/javascripts/fetch_pool.js.coffee +25 -0
  25. data/assets/javascripts/helpers/.gitkeep +0 -0
  26. data/assets/javascripts/helpers/formatting.js.coffee +17 -0
  27. data/assets/javascripts/hogan.js +706 -0
  28. data/assets/javascripts/http.js.coffee +18 -0
  29. data/assets/javascripts/jquery.js +9301 -0
  30. data/assets/javascripts/models/.gitkeep +0 -0
  31. data/assets/javascripts/models/follower.js.coffee +27 -0
  32. data/assets/javascripts/models/following.js.coffee +27 -0
  33. data/assets/javascripts/models/group.js.coffee +4 -0
  34. data/assets/javascripts/models/post.js.coffee +32 -0
  35. data/assets/javascripts/models/profile.js.coffee +30 -0
  36. data/assets/javascripts/moment.js +1106 -0
  37. data/assets/javascripts/paginator.js.coffee +67 -0
  38. data/assets/javascripts/router.js.coffee +71 -0
  39. data/assets/javascripts/routers/.gitkeep +0 -0
  40. data/assets/javascripts/routers/followers.js.coffee +14 -0
  41. data/assets/javascripts/routers/followings.js.coffee +14 -0
  42. data/assets/javascripts/routers/posts.js.coffee +98 -0
  43. data/assets/javascripts/templates/.gitkeep +0 -0
  44. data/assets/javascripts/templates/_follower.js.mustache.slim +17 -0
  45. data/assets/javascripts/templates/_following.js.mustache.slim +17 -0
  46. data/assets/javascripts/templates/_new_post_form.js.mustache.slim +10 -0
  47. data/assets/javascripts/templates/_post.js.mustache.slim +10 -0
  48. data/assets/javascripts/templates/_post_inner.js.mustache.slim +71 -0
  49. data/assets/javascripts/templates/_profile_stats.js.mustache.slim +11 -0
  50. data/assets/javascripts/templates/_reply_form.js.mustache.slim +13 -0
  51. data/assets/javascripts/templates/conversation.js.mustache.slim +13 -0
  52. data/assets/javascripts/templates/followers.js.mustache.slim +19 -0
  53. data/assets/javascripts/templates/followings.js.mustache.slim +22 -0
  54. data/assets/javascripts/templates/posts.js.mustache.slim +25 -0
  55. data/assets/javascripts/templates/profile.js.mustache.slim +39 -0
  56. data/assets/javascripts/underscore.js +1059 -0
  57. data/assets/javascripts/view.js.coffee +140 -0
  58. data/assets/javascripts/views/.gitkeep +0 -0
  59. data/assets/javascripts/views/container.js.coffee +6 -0
  60. data/assets/javascripts/views/expanding_textarea.js.coffee +14 -0
  61. data/assets/javascripts/views/fetch_posts_pool.js.coffee +61 -0
  62. data/assets/javascripts/views/follower_groups_form.js.coffee +26 -0
  63. data/assets/javascripts/views/followers.js.coffee +28 -0
  64. data/assets/javascripts/views/following_groups_form.js.coffee +25 -0
  65. data/assets/javascripts/views/followings.js.coffee +27 -0
  66. data/assets/javascripts/views/new_following_form.js.coffee +15 -0
  67. data/assets/javascripts/views/new_post_form.js.coffee +178 -0
  68. data/assets/javascripts/views/post.js.coffee +139 -0
  69. data/assets/javascripts/views/posts.js.coffee +55 -0
  70. data/assets/javascripts/views/posts/conversation.js.coffee +18 -0
  71. data/assets/javascripts/views/profile.js.coffee +29 -0
  72. data/assets/javascripts/views/profile_follow_button.js.coffee +29 -0
  73. data/assets/javascripts/views/profile_stats.js.coffee +38 -0
  74. data/assets/javascripts/views/remove_follower_btn.js.coffee +18 -0
  75. data/assets/javascripts/views/reply_post_form.js.coffee +30 -0
  76. data/assets/javascripts/views/unfollow_btn.js.coffee +18 -0
  77. data/assets/stylesheets/.gitkeep +0 -0
  78. data/assets/stylesheets/application.css.sass +117 -0
  79. data/assets/stylesheets/bootstrap-responsive.css +1040 -0
  80. data/assets/stylesheets/bootstrap.css.erb +5624 -0
  81. data/assets/stylesheets/chosen.css.erb +397 -0
  82. data/config.ru +14 -0
  83. data/config/asset_sync.rb +12 -0
  84. data/config/evergreen.rb +16 -0
  85. data/lib/tent-status.rb +6 -0
  86. data/lib/tent-status/app.rb +263 -0
  87. data/lib/tent-status/models/user.rb +39 -0
  88. data/lib/tent-status/sprockets/environment.rb +25 -0
  89. data/lib/tent-status/sprockets/helpers.rb +5 -0
  90. data/lib/tent-status/views/application.slim +69 -0
  91. data/lib/tent-status/views/auth.slim +8 -0
  92. data/tent-status.gemspec +34 -0
  93. metadata +415 -0
File without changes
@@ -0,0 +1,27 @@
1
+ class TentStatus.Models.Follower extends Backbone.Model
2
+ model: 'follower'
3
+ url: => "#{TentStatus.api_root}/followers#{ if @id then "/#{@id}" else ''}"
4
+
5
+ initialize: ->
6
+ @on 'sync', @updateProfile
7
+ @updateProfile()
8
+
9
+ updateProfile: =>
10
+ profile = @get('profile')
11
+ core_profile = {}
12
+ basic_profile = {}
13
+ for type, content of profile
14
+ basic_profile = content if type.match(/types\/info\/basic/)
15
+ core_profile = content if type.match(/types\/info\/core/)
16
+ @set 'core_profile', core_profile
17
+ @set 'basic_profile', basic_profile
18
+
19
+ name: =>
20
+ @get('basic_profile')['name'] || @get('core_profile')['entity']
21
+
22
+ hasName: =>
23
+ !!(@get('basic_profile')['name'])
24
+
25
+ avatar: =>
26
+ @get('basic_profile')['avatar_url']
27
+
@@ -0,0 +1,27 @@
1
+ class TentStatus.Models.Following extends Backbone.Model
2
+ model: 'following'
3
+ url: => "#{TentStatus.api_root}/followings#{ if @id then "/#{@id}" else ''}#{ if @get('guest') then '?guest=true' else '' }"
4
+
5
+ initialize: ->
6
+ @on 'sync', @updateProfile
7
+ @updateProfile()
8
+
9
+ updateProfile: =>
10
+ profile = @get('profile')
11
+ core_profile = {}
12
+ basic_profile = {}
13
+ for type, content of profile
14
+ basic_profile = content if type.match(/types\/info\/basic/)
15
+ core_profile = content if type.match(/types\/info\/core/)
16
+ @set 'core_profile', core_profile
17
+ @set 'basic_profile', basic_profile
18
+
19
+ name: =>
20
+ @get('basic_profile')['name'] || @get('core_profile')['entity']
21
+
22
+ hasName: =>
23
+ !!(@get('basic_profile')['name'])
24
+
25
+ avatar: =>
26
+ @get('basic_profile')['avatar_url']
27
+
@@ -0,0 +1,4 @@
1
+ class TentStatus.Models.Group extends Backbone.Model
2
+ model: 'group'
3
+ url: => "#{TentStatus.api_root}/groups#{ if @id then "/#{@id}" else ''}"
4
+
@@ -0,0 +1,32 @@
1
+ class TentStatus.Models.Post extends Backbone.Model
2
+ model: 'post'
3
+ url: => "#{TentStatus.api_root}/posts#{ if @id then "/#{@id}" else ''}"
4
+
5
+ isRepost: =>
6
+ !!(@get('type') || '').match(/repost/)
7
+
8
+ entity: =>
9
+ return TentStatus.Models.profile if TentStatus.Models.profile.entity() == @get('entity')
10
+ (TentStatus.Collections.followings.find (following) => following.get('entity') == @get('entity')) ||
11
+ (TentStatus.Collections.followers.find (follower) => follower.get('entity') == @get('entity'))
12
+
13
+ name: =>
14
+ @entity()?.name() || @get('entity')
15
+
16
+ hasName: =>
17
+ !!(@entity()?.hasName())
18
+
19
+ avatar: =>
20
+ @entity()?.avatar()
21
+
22
+ validate: (attrs) =>
23
+ errors = []
24
+
25
+ if attrs.text and attrs.text.match /^[\s\r]*$/
26
+ errors.push { text: 'Status must not be empty' }
27
+
28
+ if attrs.text and attrs.text.length > 140
29
+ errors.push { text: 'Status must be no more than 140 characters' }
30
+
31
+ return errors if errors.length
32
+ null
@@ -0,0 +1,30 @@
1
+ class Profile extends Backbone.Model
2
+ model: 'profile'
3
+ url: => "#{TentStatus.api_root}/profile"
4
+
5
+ core_profile: =>
6
+ @get('https://tent.io/types/info/core/v0.1.0')
7
+
8
+ basic_profile: =>
9
+ @get('https://tent.io/types/info/basic/v0.1.0')
10
+
11
+ entity: =>
12
+ @core_profile()?['entity']
13
+
14
+ bio: =>
15
+ @basic_profile()?['bio']
16
+
17
+ name: =>
18
+ @basic_profile()?['name'] || TentStatus.Helpers.formatUrl(@core_profile()?['entity'] || '')
19
+
20
+ hasName: =>
21
+ !!(@basic_profile()?['name'])
22
+
23
+ avatar: =>
24
+ @basic_profile()?['avatar_url']
25
+
26
+ TentStatus.Models.profile = new Profile
27
+
28
+ class TentStatus.Models.Profile extends Profile
29
+ url: => "#{TentStatus.api_root}/#{@get('follow_type')}/#{@get('id')}/profile"
30
+
@@ -0,0 +1,1106 @@
1
+ // moment.js
2
+ // version : 1.7.0
3
+ // author : Tim Wood
4
+ // license : MIT
5
+ // momentjs.com
6
+
7
+ (function (Date, undefined) {
8
+
9
+ /************************************
10
+ Constants
11
+ ************************************/
12
+
13
+ var moment,
14
+ VERSION = "1.7.0",
15
+ round = Math.round, i,
16
+ // internal storage for language config files
17
+ languages = {},
18
+ currentLanguage = 'en',
19
+
20
+ // check for nodeJS
21
+ hasModule = (typeof module !== 'undefined' && module.exports),
22
+
23
+ // Parameters to check for on the lang config. This list of properties
24
+ // will be inherited from English if not provided in a language
25
+ // definition. monthsParse is also a lang config property, but it
26
+ // cannot be inherited and as such cannot be enumerated here.
27
+ langConfigProperties = 'months|monthsShort|weekdays|weekdaysShort|weekdaysMin|longDateFormat|calendar|relativeTime|ordinal|meridiem'.split('|'),
28
+
29
+ // ASP.NET json date format regex
30
+ aspNetJsonRegex = /^\/?Date\((\-?\d+)/i,
31
+
32
+ // format tokens
33
+ formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|YYYY|YY|a|A|hh?|HH?|mm?|ss?|SS?S?|zz?|ZZ?)/g,
34
+ localFormattingTokens = /(LT|LL?L?L?)/g,
35
+ formattingRemoveEscapes = /(^\[)|(\\)|\]$/g,
36
+
37
+ // parsing tokens
38
+ parseMultipleFormatChunker = /([0-9a-zA-Z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+)/gi,
39
+
40
+ // parsing token regexes
41
+ parseTokenOneOrTwoDigits = /\d\d?/, // 0 - 99
42
+ parseTokenOneToThreeDigits = /\d{1,3}/, // 0 - 999
43
+ parseTokenThreeDigits = /\d{3}/, // 000 - 999
44
+ parseTokenFourDigits = /\d{1,4}/, // 0 - 9999
45
+ parseTokenWord = /[0-9a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+/i, // any word characters or numbers
46
+ parseTokenTimezone = /Z|[\+\-]\d\d:?\d\d/i, // +00:00 -00:00 +0000 -0000 or Z
47
+ parseTokenT = /T/i, // T (ISO seperator)
48
+
49
+ // preliminary iso regex
50
+ // 0000-00-00 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000
51
+ isoRegex = /^\s*\d{4}-\d\d-\d\d(T(\d\d(:\d\d(:\d\d(\.\d\d?\d?)?)?)?)?([\+\-]\d\d:?\d\d)?)?/,
52
+ isoFormat = 'YYYY-MM-DDTHH:mm:ssZ',
53
+
54
+ // iso time formats and regexes
55
+ isoTimes = [
56
+ ['HH:mm:ss.S', /T\d\d:\d\d:\d\d\.\d{1,3}/],
57
+ ['HH:mm:ss', /T\d\d:\d\d:\d\d/],
58
+ ['HH:mm', /T\d\d:\d\d/],
59
+ ['HH', /T\d\d/]
60
+ ],
61
+
62
+ // timezone chunker "+10:00" > ["10", "00"] or "-1530" > ["-15", "30"]
63
+ parseTimezoneChunker = /([\+\-]|\d\d)/gi,
64
+
65
+ // getter and setter names
66
+ proxyGettersAndSetters = 'Month|Date|Hours|Minutes|Seconds|Milliseconds'.split('|'),
67
+ unitMillisecondFactors = {
68
+ 'Milliseconds' : 1,
69
+ 'Seconds' : 1e3,
70
+ 'Minutes' : 6e4,
71
+ 'Hours' : 36e5,
72
+ 'Days' : 864e5,
73
+ 'Months' : 2592e6,
74
+ 'Years' : 31536e6
75
+ },
76
+
77
+ // format function strings
78
+ formatFunctions = {},
79
+
80
+ /*
81
+ * moment.fn.format uses new Function() to create an inlined formatting function.
82
+ * Results are a 3x speed boost
83
+ * http://jsperf.com/momentjs-cached-format-functions
84
+ *
85
+ * These strings are appended into a function using replaceFormatTokens and makeFormatFunction
86
+ */
87
+ formatFunctionStrings = {
88
+ // a = placeholder
89
+ // b = placeholder
90
+ // t = the current moment being formatted
91
+ // v = getValueAtKey function
92
+ // o = language.ordinal function
93
+ // p = leftZeroFill function
94
+ // m = language.meridiem value or function
95
+ M : '(a=t.month()+1)',
96
+ MMM : 'v("monthsShort",t.month())',
97
+ MMMM : 'v("months",t.month())',
98
+ D : '(a=t.date())',
99
+ DDD : '(a=new Date(t.year(),t.month(),t.date()),b=new Date(t.year(),0,1),a=~~(((a-b)/864e5)+1.5))',
100
+ d : '(a=t.day())',
101
+ dd : 'v("weekdaysMin",t.day())',
102
+ ddd : 'v("weekdaysShort",t.day())',
103
+ dddd : 'v("weekdays",t.day())',
104
+ w : '(a=new Date(t.year(),t.month(),t.date()-t.day()+5),b=new Date(a.getFullYear(),0,4),a=~~((a-b)/864e5/7+1.5))',
105
+ YY : 'p(t.year()%100,2)',
106
+ YYYY : 'p(t.year(),4)',
107
+ a : 'm(t.hours(),t.minutes(),!0)',
108
+ A : 'm(t.hours(),t.minutes(),!1)',
109
+ H : 't.hours()',
110
+ h : 't.hours()%12||12',
111
+ m : 't.minutes()',
112
+ s : 't.seconds()',
113
+ S : '~~(t.milliseconds()/100)',
114
+ SS : 'p(~~(t.milliseconds()/10),2)',
115
+ SSS : 'p(t.milliseconds(),3)',
116
+ Z : '((a=-t.zone())<0?((a=-a),"-"):"+")+p(~~(a/60),2)+":"+p(~~a%60,2)',
117
+ ZZ : '((a=-t.zone())<0?((a=-a),"-"):"+")+p(~~(10*a/6),4)'
118
+ },
119
+
120
+ ordinalizeTokens = 'DDD w M D d'.split(' '),
121
+ paddedTokens = 'M D H h m s w'.split(' ');
122
+
123
+ while (ordinalizeTokens.length) {
124
+ i = ordinalizeTokens.pop();
125
+ formatFunctionStrings[i + 'o'] = formatFunctionStrings[i] + '+o(a)';
126
+ }
127
+ while (paddedTokens.length) {
128
+ i = paddedTokens.pop();
129
+ formatFunctionStrings[i + i] = 'p(' + formatFunctionStrings[i] + ',2)';
130
+ }
131
+ formatFunctionStrings.DDDD = 'p(' + formatFunctionStrings.DDD + ',3)';
132
+
133
+
134
+ /************************************
135
+ Constructors
136
+ ************************************/
137
+
138
+
139
+ // Moment prototype object
140
+ function Moment(date, isUTC, lang) {
141
+ this._d = date;
142
+ this._isUTC = !!isUTC;
143
+ this._a = date._a || null;
144
+ date._a = null;
145
+ this._lang = lang || false;
146
+ }
147
+
148
+ // Duration Constructor
149
+ function Duration(duration) {
150
+ var data = this._data = {},
151
+ years = duration.years || duration.y || 0,
152
+ months = duration.months || duration.M || 0,
153
+ weeks = duration.weeks || duration.w || 0,
154
+ days = duration.days || duration.d || 0,
155
+ hours = duration.hours || duration.h || 0,
156
+ minutes = duration.minutes || duration.m || 0,
157
+ seconds = duration.seconds || duration.s || 0,
158
+ milliseconds = duration.milliseconds || duration.ms || 0;
159
+
160
+ // representation for dateAddRemove
161
+ this._milliseconds = milliseconds +
162
+ seconds * 1e3 + // 1000
163
+ minutes * 6e4 + // 1000 * 60
164
+ hours * 36e5; // 1000 * 60 * 60
165
+ // Because of dateAddRemove treats 24 hours as different from a
166
+ // day when working around DST, we need to store them separately
167
+ this._days = days +
168
+ weeks * 7;
169
+ // It is impossible translate months into days without knowing
170
+ // which months you are are talking about, so we have to store
171
+ // it separately.
172
+ this._months = months +
173
+ years * 12;
174
+
175
+ // The following code bubbles up values, see the tests for
176
+ // examples of what that means.
177
+ data.milliseconds = milliseconds % 1000;
178
+ seconds += absRound(milliseconds / 1000);
179
+
180
+ data.seconds = seconds % 60;
181
+ minutes += absRound(seconds / 60);
182
+
183
+ data.minutes = minutes % 60;
184
+ hours += absRound(minutes / 60);
185
+
186
+ data.hours = hours % 24;
187
+ days += absRound(hours / 24);
188
+
189
+ days += weeks * 7;
190
+ data.days = days % 30;
191
+
192
+ months += absRound(days / 30);
193
+
194
+ data.months = months % 12;
195
+ years += absRound(months / 12);
196
+
197
+ data.years = years;
198
+
199
+ this._lang = false;
200
+ }
201
+
202
+
203
+ /************************************
204
+ Helpers
205
+ ************************************/
206
+
207
+
208
+ function absRound(number) {
209
+ if (number < 0) {
210
+ return Math.ceil(number);
211
+ } else {
212
+ return Math.floor(number);
213
+ }
214
+ }
215
+
216
+ // left zero fill a number
217
+ // see http://jsperf.com/left-zero-filling for performance comparison
218
+ function leftZeroFill(number, targetLength) {
219
+ var output = number + '';
220
+ while (output.length < targetLength) {
221
+ output = '0' + output;
222
+ }
223
+ return output;
224
+ }
225
+
226
+ // helper function for _.addTime and _.subtractTime
227
+ function addOrSubtractDurationFromMoment(mom, duration, isAdding) {
228
+ var ms = duration._milliseconds,
229
+ d = duration._days,
230
+ M = duration._months,
231
+ currentDate;
232
+
233
+ if (ms) {
234
+ mom._d.setTime(+mom + ms * isAdding);
235
+ }
236
+ if (d) {
237
+ mom.date(mom.date() + d * isAdding);
238
+ }
239
+ if (M) {
240
+ currentDate = mom.date();
241
+ mom.date(1)
242
+ .month(mom.month() + M * isAdding)
243
+ .date(Math.min(currentDate, mom.daysInMonth()));
244
+ }
245
+ }
246
+
247
+ // check if is an array
248
+ function isArray(input) {
249
+ return Object.prototype.toString.call(input) === '[object Array]';
250
+ }
251
+
252
+ // compare two arrays, return the number of differences
253
+ function compareArrays(array1, array2) {
254
+ var len = Math.min(array1.length, array2.length),
255
+ lengthDiff = Math.abs(array1.length - array2.length),
256
+ diffs = 0,
257
+ i;
258
+ for (i = 0; i < len; i++) {
259
+ if (~~array1[i] !== ~~array2[i]) {
260
+ diffs++;
261
+ }
262
+ }
263
+ return diffs + lengthDiff;
264
+ }
265
+
266
+ // convert an array to a date.
267
+ // the array should mirror the parameters below
268
+ // note: all values past the year are optional and will default to the lowest possible value.
269
+ // [year, month, day , hour, minute, second, millisecond]
270
+ function dateFromArray(input, asUTC) {
271
+ var i, date;
272
+ for (i = 1; i < 7; i++) {
273
+ input[i] = (input[i] == null) ? (i === 2 ? 1 : 0) : input[i];
274
+ }
275
+ // we store whether we used utc or not in the input array
276
+ input[7] = asUTC;
277
+ date = new Date(0);
278
+ if (asUTC) {
279
+ date.setUTCFullYear(input[0], input[1], input[2]);
280
+ date.setUTCHours(input[3], input[4], input[5], input[6]);
281
+ } else {
282
+ date.setFullYear(input[0], input[1], input[2]);
283
+ date.setHours(input[3], input[4], input[5], input[6]);
284
+ }
285
+ date._a = input;
286
+ return date;
287
+ }
288
+
289
+ // Loads a language definition into the `languages` cache. The function
290
+ // takes a key and optionally values. If not in the browser and no values
291
+ // are provided, it will load the language file module. As a convenience,
292
+ // this function also returns the language values.
293
+ function loadLang(key, values) {
294
+ var i, m,
295
+ parse = [];
296
+
297
+ if (!values && hasModule) {
298
+ values = require('./lang/' + key);
299
+ }
300
+
301
+ for (i = 0; i < langConfigProperties.length; i++) {
302
+ // If a language definition does not provide a value, inherit
303
+ // from English
304
+ values[langConfigProperties[i]] = values[langConfigProperties[i]] ||
305
+ languages.en[langConfigProperties[i]];
306
+ }
307
+
308
+ for (i = 0; i < 12; i++) {
309
+ m = moment([2000, i]);
310
+ parse[i] = new RegExp('^' + (values.months[i] || values.months(m, '')) +
311
+ '|^' + (values.monthsShort[i] || values.monthsShort(m, '')).replace('.', ''), 'i');
312
+ }
313
+ values.monthsParse = values.monthsParse || parse;
314
+
315
+ languages[key] = values;
316
+
317
+ return values;
318
+ }
319
+
320
+ // Determines which language definition to use and returns it.
321
+ //
322
+ // With no parameters, it will return the global language. If you
323
+ // pass in a language key, such as 'en', it will return the
324
+ // definition for 'en', so long as 'en' has already been loaded using
325
+ // moment.lang. If you pass in a moment or duration instance, it
326
+ // will decide the language based on that, or default to the global
327
+ // language.
328
+ function getLangDefinition(m) {
329
+ var langKey = (typeof m === 'string') && m ||
330
+ m && m._lang ||
331
+ null;
332
+
333
+ return langKey ? (languages[langKey] || loadLang(langKey)) : moment;
334
+ }
335
+
336
+
337
+ /************************************
338
+ Formatting
339
+ ************************************/
340
+
341
+
342
+ // helper for building inline formatting functions
343
+ function replaceFormatTokens(token) {
344
+ return formatFunctionStrings[token] ?
345
+ ("'+(" + formatFunctionStrings[token] + ")+'") :
346
+ token.replace(formattingRemoveEscapes, "").replace(/\\?'/g, "\\'");
347
+ }
348
+
349
+ // helper for recursing long date formatting tokens
350
+ function replaceLongDateFormatTokens(input) {
351
+ return getLangDefinition().longDateFormat[input] || input;
352
+ }
353
+
354
+ function makeFormatFunction(format) {
355
+ var output = "var a,b;return '" +
356
+ format.replace(formattingTokens, replaceFormatTokens) + "';",
357
+ Fn = Function; // get around jshint
358
+ // t = the current moment being formatted
359
+ // v = getValueAtKey function
360
+ // o = language.ordinal function
361
+ // p = leftZeroFill function
362
+ // m = language.meridiem value or function
363
+ return new Fn('t', 'v', 'o', 'p', 'm', output);
364
+ }
365
+
366
+ function makeOrGetFormatFunction(format) {
367
+ if (!formatFunctions[format]) {
368
+ formatFunctions[format] = makeFormatFunction(format);
369
+ }
370
+ return formatFunctions[format];
371
+ }
372
+
373
+ // format date using native date object
374
+ function formatMoment(m, format) {
375
+ var lang = getLangDefinition(m);
376
+
377
+ function getValueFromArray(key, index) {
378
+ return lang[key].call ? lang[key](m, format) : lang[key][index];
379
+ }
380
+
381
+ while (localFormattingTokens.test(format)) {
382
+ format = format.replace(localFormattingTokens, replaceLongDateFormatTokens);
383
+ }
384
+
385
+ if (!formatFunctions[format]) {
386
+ formatFunctions[format] = makeFormatFunction(format);
387
+ }
388
+
389
+ return formatFunctions[format](m, getValueFromArray, lang.ordinal, leftZeroFill, lang.meridiem);
390
+ }
391
+
392
+
393
+ /************************************
394
+ Parsing
395
+ ************************************/
396
+
397
+
398
+ // get the regex to find the next token
399
+ function getParseRegexForToken(token) {
400
+ switch (token) {
401
+ case 'DDDD':
402
+ return parseTokenThreeDigits;
403
+ case 'YYYY':
404
+ return parseTokenFourDigits;
405
+ case 'S':
406
+ case 'SS':
407
+ case 'SSS':
408
+ case 'DDD':
409
+ return parseTokenOneToThreeDigits;
410
+ case 'MMM':
411
+ case 'MMMM':
412
+ case 'dd':
413
+ case 'ddd':
414
+ case 'dddd':
415
+ case 'a':
416
+ case 'A':
417
+ return parseTokenWord;
418
+ case 'Z':
419
+ case 'ZZ':
420
+ return parseTokenTimezone;
421
+ case 'T':
422
+ return parseTokenT;
423
+ case 'MM':
424
+ case 'DD':
425
+ case 'YY':
426
+ case 'HH':
427
+ case 'hh':
428
+ case 'mm':
429
+ case 'ss':
430
+ case 'M':
431
+ case 'D':
432
+ case 'd':
433
+ case 'H':
434
+ case 'h':
435
+ case 'm':
436
+ case 's':
437
+ return parseTokenOneOrTwoDigits;
438
+ default :
439
+ return new RegExp(token.replace('\\', ''));
440
+ }
441
+ }
442
+
443
+ // function to convert string input to date
444
+ function addTimeToArrayFromToken(token, input, datePartArray, config) {
445
+ var a;
446
+ //console.log('addTime', format, input);
447
+ switch (token) {
448
+ // MONTH
449
+ case 'M' : // fall through to MM
450
+ case 'MM' :
451
+ datePartArray[1] = (input == null) ? 0 : ~~input - 1;
452
+ break;
453
+ case 'MMM' : // fall through to MMMM
454
+ case 'MMMM' :
455
+ for (a = 0; a < 12; a++) {
456
+ if (getLangDefinition().monthsParse[a].test(input)) {
457
+ datePartArray[1] = a;
458
+ break;
459
+ }
460
+ }
461
+ break;
462
+ // DAY OF MONTH
463
+ case 'D' : // fall through to DDDD
464
+ case 'DD' : // fall through to DDDD
465
+ case 'DDD' : // fall through to DDDD
466
+ case 'DDDD' :
467
+ if (input != null) {
468
+ datePartArray[2] = ~~input;
469
+ }
470
+ break;
471
+ // YEAR
472
+ case 'YY' :
473
+ input = ~~input;
474
+ datePartArray[0] = input + (input > 70 ? 1900 : 2000);
475
+ break;
476
+ case 'YYYY' :
477
+ datePartArray[0] = ~~Math.abs(input);
478
+ break;
479
+ // AM / PM
480
+ case 'a' : // fall through to A
481
+ case 'A' :
482
+ config.isPm = ((input + '').toLowerCase() === 'pm');
483
+ break;
484
+ // 24 HOUR
485
+ case 'H' : // fall through to hh
486
+ case 'HH' : // fall through to hh
487
+ case 'h' : // fall through to hh
488
+ case 'hh' :
489
+ datePartArray[3] = ~~input;
490
+ break;
491
+ // MINUTE
492
+ case 'm' : // fall through to mm
493
+ case 'mm' :
494
+ datePartArray[4] = ~~input;
495
+ break;
496
+ // SECOND
497
+ case 's' : // fall through to ss
498
+ case 'ss' :
499
+ datePartArray[5] = ~~input;
500
+ break;
501
+ // MILLISECOND
502
+ case 'S' :
503
+ case 'SS' :
504
+ case 'SSS' :
505
+ datePartArray[6] = ~~ (('0.' + input) * 1000);
506
+ break;
507
+ // TIMEZONE
508
+ case 'Z' : // fall through to ZZ
509
+ case 'ZZ' :
510
+ config.isUTC = true;
511
+ a = (input + '').match(parseTimezoneChunker);
512
+ if (a && a[1]) {
513
+ config.tzh = ~~a[1];
514
+ }
515
+ if (a && a[2]) {
516
+ config.tzm = ~~a[2];
517
+ }
518
+ // reverse offsets
519
+ if (a && a[0] === '+') {
520
+ config.tzh = -config.tzh;
521
+ config.tzm = -config.tzm;
522
+ }
523
+ break;
524
+ }
525
+ }
526
+
527
+ // date from string and format string
528
+ function makeDateFromStringAndFormat(string, format) {
529
+ var datePartArray = [0, 0, 1, 0, 0, 0, 0],
530
+ config = {
531
+ tzh : 0, // timezone hour offset
532
+ tzm : 0 // timezone minute offset
533
+ },
534
+ tokens = format.match(formattingTokens),
535
+ i, parsedInput;
536
+
537
+ for (i = 0; i < tokens.length; i++) {
538
+ parsedInput = (getParseRegexForToken(tokens[i]).exec(string) || [])[0];
539
+ string = string.replace(getParseRegexForToken(tokens[i]), '');
540
+ addTimeToArrayFromToken(tokens[i], parsedInput, datePartArray, config);
541
+ }
542
+ // handle am pm
543
+ if (config.isPm && datePartArray[3] < 12) {
544
+ datePartArray[3] += 12;
545
+ }
546
+ // if is 12 am, change hours to 0
547
+ if (config.isPm === false && datePartArray[3] === 12) {
548
+ datePartArray[3] = 0;
549
+ }
550
+ // handle timezone
551
+ datePartArray[3] += config.tzh;
552
+ datePartArray[4] += config.tzm;
553
+ // return
554
+ return dateFromArray(datePartArray, config.isUTC);
555
+ }
556
+
557
+ // date from string and array of format strings
558
+ function makeDateFromStringAndArray(string, formats) {
559
+ var output,
560
+ inputParts = string.match(parseMultipleFormatChunker) || [],
561
+ formattedInputParts,
562
+ scoreToBeat = 99,
563
+ i,
564
+ currentDate,
565
+ currentScore;
566
+ for (i = 0; i < formats.length; i++) {
567
+ currentDate = makeDateFromStringAndFormat(string, formats[i]);
568
+ formattedInputParts = formatMoment(new Moment(currentDate), formats[i]).match(parseMultipleFormatChunker) || [];
569
+ currentScore = compareArrays(inputParts, formattedInputParts);
570
+ if (currentScore < scoreToBeat) {
571
+ scoreToBeat = currentScore;
572
+ output = currentDate;
573
+ }
574
+ }
575
+ return output;
576
+ }
577
+
578
+ // date from iso format
579
+ function makeDateFromString(string) {
580
+ var format = 'YYYY-MM-DDT',
581
+ i;
582
+ if (isoRegex.exec(string)) {
583
+ for (i = 0; i < 4; i++) {
584
+ if (isoTimes[i][1].exec(string)) {
585
+ format += isoTimes[i][0];
586
+ break;
587
+ }
588
+ }
589
+ return parseTokenTimezone.exec(string) ?
590
+ makeDateFromStringAndFormat(string, format + ' Z') :
591
+ makeDateFromStringAndFormat(string, format);
592
+ }
593
+ return new Date(string);
594
+ }
595
+
596
+
597
+ /************************************
598
+ Relative Time
599
+ ************************************/
600
+
601
+
602
+ // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize
603
+ function substituteTimeAgo(string, number, withoutSuffix, isFuture, lang) {
604
+ var rt = lang.relativeTime[string];
605
+ return (typeof rt === 'function') ?
606
+ rt(number || 1, !!withoutSuffix, string, isFuture) :
607
+ rt.replace(/%d/i, number || 1);
608
+ }
609
+
610
+ function relativeTime(milliseconds, withoutSuffix, lang) {
611
+ var seconds = round(Math.abs(milliseconds) / 1000),
612
+ minutes = round(seconds / 60),
613
+ hours = round(minutes / 60),
614
+ days = round(hours / 24),
615
+ years = round(days / 365),
616
+ args = seconds < 45 && ['s', seconds] ||
617
+ minutes === 1 && ['m'] ||
618
+ minutes < 45 && ['mm', minutes] ||
619
+ hours === 1 && ['h'] ||
620
+ hours < 22 && ['hh', hours] ||
621
+ days === 1 && ['d'] ||
622
+ days <= 25 && ['dd', days] ||
623
+ days <= 45 && ['M'] ||
624
+ days < 345 && ['MM', round(days / 30)] ||
625
+ years === 1 && ['y'] || ['yy', years];
626
+ args[2] = withoutSuffix;
627
+ args[3] = milliseconds > 0;
628
+ args[4] = lang;
629
+ return substituteTimeAgo.apply({}, args);
630
+ }
631
+
632
+
633
+ /************************************
634
+ Top Level Functions
635
+ ************************************/
636
+
637
+
638
+ moment = function (input, format) {
639
+ if (input === null || input === '') {
640
+ return null;
641
+ }
642
+ var date,
643
+ matched;
644
+ // parse Moment object
645
+ if (moment.isMoment(input)) {
646
+ return new Moment(new Date(+input._d), input._isUTC, input._lang);
647
+ // parse string and format
648
+ } else if (format) {
649
+ if (isArray(format)) {
650
+ date = makeDateFromStringAndArray(input, format);
651
+ } else {
652
+ date = makeDateFromStringAndFormat(input, format);
653
+ }
654
+ // evaluate it as a JSON-encoded date
655
+ } else {
656
+ matched = aspNetJsonRegex.exec(input);
657
+ date = input === undefined ? new Date() :
658
+ matched ? new Date(+matched[1]) :
659
+ input instanceof Date ? input :
660
+ isArray(input) ? dateFromArray(input) :
661
+ typeof input === 'string' ? makeDateFromString(input) :
662
+ new Date(input);
663
+ }
664
+
665
+ return new Moment(date);
666
+ };
667
+
668
+ // creating with utc
669
+ moment.utc = function (input, format) {
670
+ if (isArray(input)) {
671
+ return new Moment(dateFromArray(input, true), true);
672
+ }
673
+ // if we don't have a timezone, we need to add one to trigger parsing into utc
674
+ if (typeof input === 'string' && !parseTokenTimezone.exec(input)) {
675
+ input += ' +0000';
676
+ if (format) {
677
+ format += ' Z';
678
+ }
679
+ }
680
+ return moment(input, format).utc();
681
+ };
682
+
683
+ // creating with unix timestamp (in seconds)
684
+ moment.unix = function (input) {
685
+ return moment(input * 1000);
686
+ };
687
+
688
+ // duration
689
+ moment.duration = function (input, key) {
690
+ var isDuration = moment.isDuration(input),
691
+ isNumber = (typeof input === 'number'),
692
+ duration = (isDuration ? input._data : (isNumber ? {} : input)),
693
+ ret;
694
+
695
+ if (isNumber) {
696
+ if (key) {
697
+ duration[key] = input;
698
+ } else {
699
+ duration.milliseconds = input;
700
+ }
701
+ }
702
+
703
+ ret = new Duration(duration);
704
+
705
+ if (isDuration) {
706
+ ret._lang = input._lang;
707
+ }
708
+
709
+ return ret;
710
+ };
711
+
712
+ // humanizeDuration
713
+ // This method is deprecated in favor of the new Duration object. Please
714
+ // see the moment.duration method.
715
+ moment.humanizeDuration = function (num, type, withSuffix) {
716
+ return moment.duration(num, type === true ? null : type).humanize(type === true ? true : withSuffix);
717
+ };
718
+
719
+ // version number
720
+ moment.version = VERSION;
721
+
722
+ // default format
723
+ moment.defaultFormat = isoFormat;
724
+
725
+ // This function will load languages and then set the global language. If
726
+ // no arguments are passed in, it will simply return the current global
727
+ // language key.
728
+ moment.lang = function (key, values) {
729
+ var i;
730
+
731
+ if (!key) {
732
+ return currentLanguage;
733
+ }
734
+ if (values || !languages[key]) {
735
+ loadLang(key, values);
736
+ }
737
+ if (languages[key]) {
738
+ // deprecated, to get the language definition variables, use the
739
+ // moment.fn.lang method or the getLangDefinition function.
740
+ for (i = 0; i < langConfigProperties.length; i++) {
741
+ moment[langConfigProperties[i]] = languages[key][langConfigProperties[i]];
742
+ }
743
+ moment.monthsParse = languages[key].monthsParse;
744
+ currentLanguage = key;
745
+ }
746
+ };
747
+
748
+ // returns language data
749
+ moment.langData = getLangDefinition;
750
+
751
+ // compare moment object
752
+ moment.isMoment = function (obj) {
753
+ return obj instanceof Moment;
754
+ };
755
+
756
+ // for typechecking Duration objects
757
+ moment.isDuration = function (obj) {
758
+ return obj instanceof Duration;
759
+ };
760
+
761
+ // Set default language, other languages will inherit from English.
762
+ moment.lang('en', {
763
+ months : "January_February_March_April_May_June_July_August_September_October_November_December".split("_"),
764
+ monthsShort : "Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),
765
+ weekdays : "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),
766
+ weekdaysShort : "Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),
767
+ weekdaysMin : "Su_Mo_Tu_We_Th_Fr_Sa".split("_"),
768
+ longDateFormat : {
769
+ LT : "h:mm A",
770
+ L : "MM/DD/YYYY",
771
+ LL : "MMMM D YYYY",
772
+ LLL : "MMMM D YYYY LT",
773
+ LLLL : "dddd, MMMM D YYYY LT"
774
+ },
775
+ meridiem : function (hours, minutes, isLower) {
776
+ if (hours > 11) {
777
+ return isLower ? 'pm' : 'PM';
778
+ } else {
779
+ return isLower ? 'am' : 'AM';
780
+ }
781
+ },
782
+ calendar : {
783
+ sameDay : '[Today at] LT',
784
+ nextDay : '[Tomorrow at] LT',
785
+ nextWeek : 'dddd [at] LT',
786
+ lastDay : '[Yesterday at] LT',
787
+ lastWeek : '[last] dddd [at] LT',
788
+ sameElse : 'L'
789
+ },
790
+ relativeTime : {
791
+ future : "in %s",
792
+ past : "%s ago",
793
+ s : "a few seconds",
794
+ m : "a minute",
795
+ mm : "%d minutes",
796
+ h : "an hour",
797
+ hh : "%d hours",
798
+ d : "a day",
799
+ dd : "%d days",
800
+ M : "a month",
801
+ MM : "%d months",
802
+ y : "a year",
803
+ yy : "%d years"
804
+ },
805
+ ordinal : function (number) {
806
+ var b = number % 10;
807
+ return (~~ (number % 100 / 10) === 1) ? 'th' :
808
+ (b === 1) ? 'st' :
809
+ (b === 2) ? 'nd' :
810
+ (b === 3) ? 'rd' : 'th';
811
+ }
812
+ });
813
+
814
+
815
+ /************************************
816
+ Moment Prototype
817
+ ************************************/
818
+
819
+
820
+ moment.fn = Moment.prototype = {
821
+
822
+ clone : function () {
823
+ return moment(this);
824
+ },
825
+
826
+ valueOf : function () {
827
+ return +this._d;
828
+ },
829
+
830
+ unix : function () {
831
+ return Math.floor(+this._d / 1000);
832
+ },
833
+
834
+ toString : function () {
835
+ return this._d.toString();
836
+ },
837
+
838
+ toDate : function () {
839
+ return this._d;
840
+ },
841
+
842
+ toArray : function () {
843
+ var m = this;
844
+ return [
845
+ m.year(),
846
+ m.month(),
847
+ m.date(),
848
+ m.hours(),
849
+ m.minutes(),
850
+ m.seconds(),
851
+ m.milliseconds(),
852
+ !!this._isUTC
853
+ ];
854
+ },
855
+
856
+ isValid : function () {
857
+ if (this._a) {
858
+ return !compareArrays(this._a, (this._a[7] ? moment.utc(this) : this).toArray());
859
+ }
860
+ return !isNaN(this._d.getTime());
861
+ },
862
+
863
+ utc : function () {
864
+ this._isUTC = true;
865
+ return this;
866
+ },
867
+
868
+ local : function () {
869
+ this._isUTC = false;
870
+ return this;
871
+ },
872
+
873
+ format : function (inputString) {
874
+ return formatMoment(this, inputString ? inputString : moment.defaultFormat);
875
+ },
876
+
877
+ add : function (input, val) {
878
+ var dur = val ? moment.duration(+val, input) : moment.duration(input);
879
+ addOrSubtractDurationFromMoment(this, dur, 1);
880
+ return this;
881
+ },
882
+
883
+ subtract : function (input, val) {
884
+ var dur = val ? moment.duration(+val, input) : moment.duration(input);
885
+ addOrSubtractDurationFromMoment(this, dur, -1);
886
+ return this;
887
+ },
888
+
889
+ diff : function (input, val, asFloat) {
890
+ var inputMoment = this._isUTC ? moment(input).utc() : moment(input).local(),
891
+ zoneDiff = (this.zone() - inputMoment.zone()) * 6e4,
892
+ diff = this._d - inputMoment._d - zoneDiff,
893
+ year = this.year() - inputMoment.year(),
894
+ month = this.month() - inputMoment.month(),
895
+ date = this.date() - inputMoment.date(),
896
+ output;
897
+ if (val === 'months') {
898
+ output = year * 12 + month + date / 30;
899
+ } else if (val === 'years') {
900
+ output = year + (month + date / 30) / 12;
901
+ } else {
902
+ output = val === 'seconds' ? diff / 1e3 : // 1000
903
+ val === 'minutes' ? diff / 6e4 : // 1000 * 60
904
+ val === 'hours' ? diff / 36e5 : // 1000 * 60 * 60
905
+ val === 'days' ? diff / 864e5 : // 1000 * 60 * 60 * 24
906
+ val === 'weeks' ? diff / 6048e5 : // 1000 * 60 * 60 * 24 * 7
907
+ diff;
908
+ }
909
+ return asFloat ? output : round(output);
910
+ },
911
+
912
+ from : function (time, withoutSuffix) {
913
+ return moment.duration(this.diff(time)).lang(this._lang).humanize(!withoutSuffix);
914
+ },
915
+
916
+ fromNow : function (withoutSuffix) {
917
+ return this.from(moment(), withoutSuffix);
918
+ },
919
+
920
+ calendar : function () {
921
+ var diff = this.diff(moment().sod(), 'days', true),
922
+ calendar = this.lang().calendar,
923
+ allElse = calendar.sameElse,
924
+ format = diff < -6 ? allElse :
925
+ diff < -1 ? calendar.lastWeek :
926
+ diff < 0 ? calendar.lastDay :
927
+ diff < 1 ? calendar.sameDay :
928
+ diff < 2 ? calendar.nextDay :
929
+ diff < 7 ? calendar.nextWeek : allElse;
930
+ return this.format(typeof format === 'function' ? format.apply(this) : format);
931
+ },
932
+
933
+ isLeapYear : function () {
934
+ var year = this.year();
935
+ return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
936
+ },
937
+
938
+ isDST : function () {
939
+ return (this.zone() < moment([this.year()]).zone() ||
940
+ this.zone() < moment([this.year(), 5]).zone());
941
+ },
942
+
943
+ day : function (input) {
944
+ var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay();
945
+ return input == null ? day :
946
+ this.add({ d : input - day });
947
+ },
948
+
949
+ startOf: function (val) {
950
+ // the following switch intentionally omits break keywords
951
+ // to utilize falling through the cases.
952
+ switch (val.replace(/s$/, '')) {
953
+ case 'year':
954
+ this.month(0);
955
+ /* falls through */
956
+ case 'month':
957
+ this.date(1);
958
+ /* falls through */
959
+ case 'day':
960
+ this.hours(0);
961
+ /* falls through */
962
+ case 'hour':
963
+ this.minutes(0);
964
+ /* falls through */
965
+ case 'minute':
966
+ this.seconds(0);
967
+ /* falls through */
968
+ case 'second':
969
+ this.milliseconds(0);
970
+ /* falls through */
971
+ }
972
+ return this;
973
+ },
974
+
975
+ endOf: function (val) {
976
+ return this.startOf(val).add(val.replace(/s?$/, 's'), 1).subtract('ms', 1);
977
+ },
978
+
979
+ sod: function () {
980
+ return this.clone().startOf('day');
981
+ },
982
+
983
+ eod: function () {
984
+ // end of day = start of day plus 1 day, minus 1 millisecond
985
+ return this.clone().endOf('day');
986
+ },
987
+
988
+ zone : function () {
989
+ return this._isUTC ? 0 : this._d.getTimezoneOffset();
990
+ },
991
+
992
+ daysInMonth : function () {
993
+ return moment.utc([this.year(), this.month() + 1, 0]).date();
994
+ },
995
+
996
+ // If passed a language key, it will set the language for this
997
+ // instance. Otherwise, it will return the language configuration
998
+ // variables for this instance.
999
+ lang : function (lang) {
1000
+ if (lang === undefined) {
1001
+ return getLangDefinition(this);
1002
+ } else {
1003
+ this._lang = lang;
1004
+ return this;
1005
+ }
1006
+ }
1007
+ };
1008
+
1009
+ // helper for adding shortcuts
1010
+ function makeGetterAndSetter(name, key) {
1011
+ moment.fn[name] = function (input) {
1012
+ var utc = this._isUTC ? 'UTC' : '';
1013
+ if (input != null) {
1014
+ this._d['set' + utc + key](input);
1015
+ return this;
1016
+ } else {
1017
+ return this._d['get' + utc + key]();
1018
+ }
1019
+ };
1020
+ }
1021
+
1022
+ // loop through and add shortcuts (Month, Date, Hours, Minutes, Seconds, Milliseconds)
1023
+ for (i = 0; i < proxyGettersAndSetters.length; i ++) {
1024
+ makeGetterAndSetter(proxyGettersAndSetters[i].toLowerCase(), proxyGettersAndSetters[i]);
1025
+ }
1026
+
1027
+ // add shortcut for year (uses different syntax than the getter/setter 'year' == 'FullYear')
1028
+ makeGetterAndSetter('year', 'FullYear');
1029
+
1030
+
1031
+ /************************************
1032
+ Duration Prototype
1033
+ ************************************/
1034
+
1035
+
1036
+ moment.duration.fn = Duration.prototype = {
1037
+ weeks : function () {
1038
+ return absRound(this.days() / 7);
1039
+ },
1040
+
1041
+ valueOf : function () {
1042
+ return this._milliseconds +
1043
+ this._days * 864e5 +
1044
+ this._months * 2592e6;
1045
+ },
1046
+
1047
+ humanize : function (withSuffix) {
1048
+ var difference = +this,
1049
+ rel = this.lang().relativeTime,
1050
+ output = relativeTime(difference, !withSuffix, this.lang());
1051
+
1052
+ if (withSuffix) {
1053
+ output = (difference <= 0 ? rel.past : rel.future).replace(/%s/i, output);
1054
+ }
1055
+
1056
+ return output;
1057
+ },
1058
+
1059
+ lang : moment.fn.lang
1060
+ };
1061
+
1062
+ function makeDurationGetter(name) {
1063
+ moment.duration.fn[name] = function () {
1064
+ return this._data[name];
1065
+ };
1066
+ }
1067
+
1068
+ function makeDurationAsGetter(name, factor) {
1069
+ moment.duration.fn['as' + name] = function () {
1070
+ return +this / factor;
1071
+ };
1072
+ }
1073
+
1074
+ for (i in unitMillisecondFactors) {
1075
+ if (unitMillisecondFactors.hasOwnProperty(i)) {
1076
+ makeDurationAsGetter(i, unitMillisecondFactors[i]);
1077
+ makeDurationGetter(i.toLowerCase());
1078
+ }
1079
+ }
1080
+
1081
+ makeDurationAsGetter('Weeks', 6048e5);
1082
+
1083
+
1084
+ /************************************
1085
+ Exposing Moment
1086
+ ************************************/
1087
+
1088
+
1089
+ // CommonJS module is defined
1090
+ if (hasModule) {
1091
+ module.exports = moment;
1092
+ }
1093
+ /*global ender:false */
1094
+ if (typeof ender === 'undefined') {
1095
+ // here, `this` means `window` in the browser, or `global` on the server
1096
+ // add `moment` as a global object via a string identifier,
1097
+ // for Closure Compiler "advanced" mode
1098
+ this['moment'] = moment;
1099
+ }
1100
+ /*global define:false */
1101
+ if (typeof define === "function" && define.amd) {
1102
+ define("moment", [], function () {
1103
+ return moment;
1104
+ });
1105
+ }
1106
+ }).call(this, Date);