tent-status 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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);