cyclical-rails 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,9 @@
1
+ .DS_Store
2
+
3
+ .bundle/
4
+ log/*.log
5
+ pkg/
6
+ test/dummy/db/*.sqlite3
7
+ test/dummy/log/*.log
8
+ test/dummy/tmp/
9
+ test/dummy/.sass-cache
data/Gemfile ADDED
@@ -0,0 +1,17 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Declare your gem's dependencies in cyclical-rails.gemspec.
4
+ # Bundler will treat runtime dependencies like base dependencies, and
5
+ # development dependencies will be added by default to the :development group.
6
+ gemspec
7
+
8
+ # jquery-rails is used by the dummy application
9
+ gem "jquery-rails"
10
+
11
+ # Declare any dependencies that are still in development here instead of in
12
+ # your gemspec. These might include edge Rails or gems from your path or
13
+ # Git. Remember to move these dependencies to your gemspec before releasing
14
+ # your gem to rubygems.org.
15
+
16
+ # To use debugger
17
+ # gem 'debugger'
@@ -0,0 +1,69 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ cyclical-rails (0.0.1)
5
+ cyclical (~> 0.1.0)
6
+ railties (>= 3.1)
7
+
8
+ GEM
9
+ remote: http://rubygems.org/
10
+ specs:
11
+ actionpack (3.2.14)
12
+ activemodel (= 3.2.14)
13
+ activesupport (= 3.2.14)
14
+ builder (~> 3.0.0)
15
+ erubis (~> 2.7.0)
16
+ journey (~> 1.0.4)
17
+ rack (~> 1.4.5)
18
+ rack-cache (~> 1.2)
19
+ rack-test (~> 0.6.1)
20
+ sprockets (~> 2.2.1)
21
+ activemodel (3.2.14)
22
+ activesupport (= 3.2.14)
23
+ builder (~> 3.0.0)
24
+ activesupport (3.2.14)
25
+ i18n (~> 0.6, >= 0.6.4)
26
+ multi_json (~> 1.0)
27
+ builder (3.0.4)
28
+ cyclical (0.1.1)
29
+ activesupport (>= 3.0.0)
30
+ erubis (2.7.0)
31
+ hike (1.2.3)
32
+ i18n (0.6.5)
33
+ journey (1.0.4)
34
+ jquery-rails (3.0.4)
35
+ railties (>= 3.0, < 5.0)
36
+ thor (>= 0.14, < 2.0)
37
+ json (1.8.0)
38
+ multi_json (1.8.1)
39
+ rack (1.4.5)
40
+ rack-cache (1.2)
41
+ rack (>= 0.4)
42
+ rack-ssl (1.3.3)
43
+ rack
44
+ rack-test (0.6.2)
45
+ rack (>= 1.0)
46
+ railties (3.2.14)
47
+ actionpack (= 3.2.14)
48
+ activesupport (= 3.2.14)
49
+ rack-ssl (~> 1.3.2)
50
+ rake (>= 0.8.7)
51
+ rdoc (~> 3.4)
52
+ thor (>= 0.14.6, < 2.0)
53
+ rake (10.1.0)
54
+ rdoc (3.12.2)
55
+ json (~> 1.4)
56
+ sprockets (2.2.2)
57
+ hike (~> 1.2)
58
+ multi_json (~> 1.0)
59
+ rack (~> 1.0)
60
+ tilt (~> 1.1, != 1.3.0)
61
+ thor (0.18.1)
62
+ tilt (1.4.1)
63
+
64
+ PLATFORMS
65
+ ruby
66
+
67
+ DEPENDENCIES
68
+ cyclical-rails!
69
+ jquery-rails
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2011 Viktor Charypar
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,63 @@
1
+ # Cyclical for Rails
2
+
3
+ Integration with [ruby](https://github.com/charypar/cyclcical) and [JavaScript](https://github.com/charypar/cyclical-js) versions of Cyclical recurring events library for yourrails application.
4
+
5
+ ## About
6
+
7
+ Cyclical lets you list recurring events with complex recurrence rules like "every 4 years, the first Tuesday after a Monday in November" in a simple way both in the front-end and the back-end of your application.
8
+
9
+ ## Install
10
+
11
+ Add the ```cyclical-rails``` gem in your Gemfile
12
+
13
+ ```ruby
14
+ gem "cyclical-rails"
15
+ ```
16
+
17
+ The ```cyclical``` JavaScript library will be added to the asset pipeline. To use them add the following to ```app/assets/javascript/application.js```:
18
+
19
+ ```javascript
20
+ //= require cyclical
21
+ ```
22
+
23
+ ## Usage
24
+
25
+ ### Ruby & JavaScript
26
+
27
+ In your controller you do:
28
+
29
+ ```ruby
30
+ schedule = Cyclical::Schedule.new Time.now, Cyclical::Rule.daily(2).count(3)
31
+ schedule.occurrences
32
+ ```
33
+
34
+ in your javascript you do:
35
+
36
+ ```javascript
37
+ var schedule = new Schedule(new Date, Schedule.Rule.daily(2).count(3));
38
+ var occ = schedule.occurrences();
39
+ ```
40
+
41
+ and you get the same results.
42
+
43
+ You can send schedules over the wire as JSON. Serialize in ERB
44
+
45
+ ```
46
+ schedule_json = '<%= @schedule.to_json.html_safe %>';
47
+ ```
48
+
49
+ and load in javascript
50
+
51
+ ```javascript
52
+ var schedule = Schedule.fromJSON(schedule_json);
53
+ ```
54
+
55
+ The same also works the other way round.
56
+
57
+ For more information about [Cyclical](https://github.com/charypar/cyclcical) and [Cyclical.js](https://github.com/charypar/cyclcical-js) see the respective repos.
58
+
59
+ ## License
60
+
61
+ Released under the [MIT License](http://www.opensource.org/licenses/MIT).
62
+
63
+
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env rake
2
+
3
+ begin
4
+ require 'bundler/setup'
5
+ rescue LoadError
6
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
7
+ end
8
+
9
+ Bundler::GemHelper.install_tasks
10
+
@@ -0,0 +1,19 @@
1
+ require File.expand_path('../lib/cyclical/rails/version', __FILE__)
2
+
3
+ # Describe your gem and declare its dependencies:
4
+ Gem::Specification.new do |s|
5
+ s.name = "cyclical-rails"
6
+ s.version = Cyclical::Rails::VERSION
7
+ s.authors = ["Viktor Charypar"]
8
+ s.email = ["charypar@gmail.com"]
9
+ s.homepage = "https://github.com/charypar/cyclical-rails"
10
+ s.summary = "Cyclical support for Rails 3"
11
+ s.description = "Provides integration with ruby and JavaScript versions of Cyclical recurring events library for your rails application."
12
+ s.license = "MIT"
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.require_path = 'lib'
16
+
17
+ s.add_runtime_dependency "railties", ">= 3.1"
18
+ s.add_runtime_dependency "cyclical", "~> 0.1.0"
19
+ end
@@ -0,0 +1,2 @@
1
+ require 'cyclical'
2
+ require 'cyclical/rails'
@@ -0,0 +1,7 @@
1
+ require 'cyclical/rails/version'
2
+ require 'cyclical/rails/engine'
3
+
4
+ module Cyclical
5
+ module Rails
6
+ end
7
+ end
@@ -0,0 +1,6 @@
1
+ module Cyclical
2
+ module Rails
3
+ class Engine < ::Rails::Engine
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ module Cyclical
2
+ module Rails
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :cyclical-rails do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,1813 @@
1
+ (function() {
2
+ Date.parseISO8601 = function(string) {
3
+ var i, minutes, parts, regex, _i, _len, _ref;
4
+ regex = /^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?::(\d{2}))?)?)?$/;
5
+ if (!(parts = regex.exec(string))) {
6
+ return null;
7
+ }
8
+ _ref = [1, 4, 5, 6, 7, 10, 11];
9
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
10
+ i = _ref[_i];
11
+ parts[i] = +parts[i] || 0;
12
+ }
13
+ parts[2] = (+parts[2] || 1) - 1;
14
+ parts[3] = +parts[3] || 1;
15
+ if (parts[8] !== 'Z' && (parts[9] != null)) {
16
+ minutes = parts[10] * 60 + parts[11];
17
+ if (parts[9] === '+') {
18
+ minutes = -minutes;
19
+ }
20
+ parts[5] += minutes;
21
+ }
22
+ return new Date(Date.UTC.apply(Date, parts.slice(1, 8)));
23
+ };
24
+
25
+ }).call(this);
26
+
27
+ (function() {
28
+ var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
29
+ _this = this;
30
+
31
+ window.Schedule = (function() {
32
+ function Schedule(startTime, rule) {
33
+ this.toString = __bind(this.toString, this);
34
+ this.toJSON = __bind(this.toJSON, this);
35
+ this.toObject = __bind(this.toObject, this);
36
+ this.suboccurrencesBetween = __bind(this.suboccurrencesBetween, this);
37
+ this.occurrencesBetween = __bind(this.occurrencesBetween, this);
38
+ this.occurrences = __bind(this.occurrences, this);
39
+ this.previousOccurrence = __bind(this.previousOccurrence, this);
40
+ this.nextOccurrence = __bind(this.nextOccurrence, this);
41
+ this.first = __bind(this.first, this);
42
+ this.setEndTime = __bind(this.setEndTime, this);
43
+ this.rule = __bind(this.rule, this);
44
+ this.setRule = __bind(this.setRule, this);
45
+ if (rule != null) {
46
+ this.occurrence = new Schedule.Occurrence(rule, startTime);
47
+ }
48
+ this.startTime = this.occurrence ? this.occurrence.startTime : startTime;
49
+ }
50
+
51
+ Schedule.prototype.setRule = function(rule) {
52
+ this.occurrence = rule != null ? null : new Schedule.Occurrence(rule, this.startTime);
53
+ return this.occurrence.duration = this.endTime ? this.endTime - this.startTime : 0;
54
+ };
55
+
56
+ Schedule.prototype.rule = function() {
57
+ if (this.occurrence != null) {
58
+ return this.occurrence.rule;
59
+ } else {
60
+ return null;
61
+ }
62
+ };
63
+
64
+ Schedule.prototype.setEndTime = function(time) {
65
+ if (time < this.startTime) {
66
+ throw "End time is before start time";
67
+ }
68
+ this.endTime = time;
69
+ if (this.occurrence != null) {
70
+ this.occurrence.duration = time - this.startTime;
71
+ }
72
+ return time;
73
+ };
74
+
75
+ Schedule.prototype.first = function(n) {
76
+ if (this.occurrence == null) {
77
+ return [this.startTime];
78
+ }
79
+ return this.occurrence.nextOccurrences(n, this.startTime);
80
+ };
81
+
82
+ Schedule.prototype.nextOccurrence = function(time) {
83
+ if (this.occurrence == null) {
84
+ return (this.startTime < time ? null : this.startTime);
85
+ }
86
+ return this.occurrence.nextOccurrence(time);
87
+ };
88
+
89
+ Schedule.prototype.previousOccurrence = function(time) {
90
+ if (this.occurrence == null) {
91
+ return (this.startTime >= time ? null : this.startTime);
92
+ }
93
+ return this.occurrence.previousOccurrence(time);
94
+ };
95
+
96
+ Schedule.prototype.occurrences = function(endTime) {
97
+ if ((endTime == null) && this.occurrence && this.occurrence.rule.isInfinite()) {
98
+ throw "You have to specify end time for an infinite schedule occurrence listing";
99
+ }
100
+ if (endTime != null) {
101
+ return this.occurrencesBetween(this.startTime, endTime);
102
+ } else {
103
+ if (this.occurrence == null) {
104
+ return [this.startTime];
105
+ }
106
+ return this.occurrence.all();
107
+ }
108
+ };
109
+
110
+ Schedule.prototype.occurrencesBetween = function(t1, t2) {
111
+ if (this.occurrence == null) {
112
+ return (this.startTime < t1 || this.startTime >= t2 ? [] : [this.startTime]);
113
+ }
114
+ return this.occurrence.occurrencesBetween(t1, t2);
115
+ };
116
+
117
+ Schedule.prototype.suboccurrencesBetween = function(t1, t2) {
118
+ if (this.endTime == null) {
119
+ throw "Schedule must have an end time to compute suboccurrences";
120
+ }
121
+ if (this.occurrence == null) {
122
+ return [
123
+ Schedule.Suboccurrence.find({
124
+ occurrence: [this.startTime, this.endTime],
125
+ interval: [t1, t2]
126
+ })
127
+ ];
128
+ }
129
+ return this.occurrence.suboccurrencesBetween(t1, t2);
130
+ };
131
+
132
+ Schedule.prototype.toObject = function() {
133
+ var o;
134
+ o = this.occurrence != null ? this.occurrence.toObject() : {};
135
+ o.start = this.startTime;
136
+ if (this.endTime != null) {
137
+ o.end = this.endTime;
138
+ }
139
+ return o;
140
+ };
141
+
142
+ Schedule.prototype.toJSON = function() {
143
+ return JSON.stringify(this.toObject());
144
+ };
145
+
146
+ Schedule.prototype.toString = function() {
147
+ return this.rule().toString();
148
+ };
149
+
150
+ return Schedule;
151
+
152
+ })();
153
+
154
+ Schedule.fromObject = function(object) {
155
+ var endTime, rule, s, startTime;
156
+ startTime = object.start;
157
+ endTime = object.end;
158
+ rule = object.freq && object.interval ? Schedule.Rule.fromObject(object) : null;
159
+ s = new Schedule(startTime, rule);
160
+ s.setEndTime(endTime);
161
+ return s;
162
+ };
163
+
164
+ Schedule.fromJSON = function(json) {
165
+ var o;
166
+ o = JSON.parse(json);
167
+ if (o.start != null) {
168
+ o.start = Date.parseISO8601(o.start);
169
+ }
170
+ if (o.end != null) {
171
+ o.end = Date.parseISO8601(o.end);
172
+ }
173
+ if (o.stop != null) {
174
+ o.stop = Date.parseISO8601(o.stop);
175
+ }
176
+ return Schedule.fromObject(o);
177
+ };
178
+
179
+ Schedule.Rules = {};
180
+
181
+ Schedule.Filters = {};
182
+
183
+ }).call(this);
184
+
185
+ (function() {
186
+ var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
187
+ __slice = [].slice;
188
+
189
+ Schedule.Rule = (function() {
190
+ function Rule(interval) {
191
+ if (interval == null) {
192
+ interval = 1;
193
+ }
194
+ this._minStep = __bind(this._minStep, this);
195
+ this._potentialPrevious = __bind(this._potentialPrevious, this);
196
+ this._potentialNext = __bind(this._potentialNext, this);
197
+ this.toString = __bind(this.toString, this);
198
+ this.toJSON = __bind(this.toJSON, this);
199
+ this.toObject = __bind(this.toObject, this);
200
+ this.step = __bind(this.step, this);
201
+ this.freq = __bind(this.freq, this);
202
+ this.aligned = __bind(this.aligned, this);
203
+ this.previous = __bind(this.previous, this);
204
+ this.next = __bind(this.next, this);
205
+ this.match = __bind(this.match, this);
206
+ this.isInfinite = __bind(this.isInfinite, this);
207
+ this.isFinite = __bind(this.isFinite, this);
208
+ this.filters = __bind(this.filters, this);
209
+ this.yearday = __bind(this.yearday, this);
210
+ this.yeardays = __bind(this.yeardays, this);
211
+ this.monthday = __bind(this.monthday, this);
212
+ this.monthdays = __bind(this.monthdays, this);
213
+ this.weekday = __bind(this.weekday, this);
214
+ this.weekdays = __bind(this.weekdays, this);
215
+ this.month = __bind(this.month, this);
216
+ this.months = __bind(this.months, this);
217
+ this.stop = __bind(this.stop, this);
218
+ this.count = __bind(this.count, this);
219
+ this.interval = interval;
220
+ this._filters = [];
221
+ this._filterMap = {};
222
+ }
223
+
224
+ Rule.prototype.count = function(n) {
225
+ if (!n) {
226
+ return this._count;
227
+ }
228
+ this._count = n;
229
+ return this;
230
+ };
231
+
232
+ Rule.prototype.stop = function(t) {
233
+ if (!t) {
234
+ return this._stop;
235
+ }
236
+ this._stop = t;
237
+ return this;
238
+ };
239
+
240
+ Rule.prototype.months = function() {
241
+ var f, months;
242
+ months = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
243
+ if (this._filterMap.month != null) {
244
+ throw "Months filter already set";
245
+ }
246
+ f = (function(func, args, ctor) {
247
+ ctor.prototype = func.prototype;
248
+ var child = new ctor, result = func.apply(child, args);
249
+ return Object(result) === result ? result : child;
250
+ })(Schedule.Filters.MonthsFilter, months, function(){});
251
+ this._filters.push(f);
252
+ this._filterMap.months = f;
253
+ return this;
254
+ };
255
+
256
+ Rule.prototype.month = function() {
257
+ var months;
258
+ months = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
259
+ return this.months.apply(this, months);
260
+ };
261
+
262
+ Rule.prototype.weekdays = function() {
263
+ var f, weekdays;
264
+ weekdays = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
265
+ if (this._filterMap.weekdays != null) {
266
+ throw "weekdays filter already set";
267
+ }
268
+ weekdays = [this].concat(weekdays);
269
+ f = (function(func, args, ctor) {
270
+ ctor.prototype = func.prototype;
271
+ var child = new ctor, result = func.apply(child, args);
272
+ return Object(result) === result ? result : child;
273
+ })(Schedule.Filters.WeekdaysFilter, weekdays, function(){});
274
+ this._filters.push(f);
275
+ this._filterMap.weekdays = f;
276
+ return this;
277
+ };
278
+
279
+ Rule.prototype.weekday = function() {
280
+ var weekdays;
281
+ weekdays = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
282
+ return this.weekdays.apply(this, weekdays);
283
+ };
284
+
285
+ Rule.prototype.monthdays = function() {
286
+ var f, monthdays;
287
+ monthdays = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
288
+ if (this._filterMap.monthdays != null) {
289
+ throw "monthdays filter already set";
290
+ }
291
+ f = (function(func, args, ctor) {
292
+ ctor.prototype = func.prototype;
293
+ var child = new ctor, result = func.apply(child, args);
294
+ return Object(result) === result ? result : child;
295
+ })(Schedule.Filters.MonthdaysFilter, monthdays, function(){});
296
+ this._filters.push(f);
297
+ this._filterMap.monthdays = f;
298
+ return this;
299
+ };
300
+
301
+ Rule.prototype.monthday = function() {
302
+ var monthdays;
303
+ monthdays = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
304
+ return this.monthdays.apply(this, monthdays);
305
+ };
306
+
307
+ Rule.prototype.yeardays = function() {
308
+ var f, yeardays;
309
+ yeardays = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
310
+ if (this._filterMap.yeardays != null) {
311
+ throw "yeardays filter already set";
312
+ }
313
+ f = (function(func, args, ctor) {
314
+ ctor.prototype = func.prototype;
315
+ var child = new ctor, result = func.apply(child, args);
316
+ return Object(result) === result ? result : child;
317
+ })(Schedule.Filters.YeardaysFilter, yeardays, function(){});
318
+ this._filters.push(f);
319
+ this._filterMap.yeardays = f;
320
+ return this;
321
+ };
322
+
323
+ Rule.prototype.yearday = function() {
324
+ var yeardays;
325
+ yeardays = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
326
+ return yeardays.apply(null, yeardays);
327
+ };
328
+
329
+ Rule.prototype.filters = function(kind) {
330
+ if (kind == null) {
331
+ return this._filters;
332
+ }
333
+ return this._filterMap[kind];
334
+ };
335
+
336
+ Rule.prototype.isFinite = function() {
337
+ return (this.count() != null) || (this.stop() != null);
338
+ };
339
+
340
+ Rule.prototype.isInfinite = function() {
341
+ return !this.isFinite();
342
+ };
343
+
344
+ Rule.prototype.match = function(time, base) {
345
+ var filter, _i, _len, _ref;
346
+ _ref = this._filters;
347
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
348
+ filter = _ref[_i];
349
+ if (!filter.match(time)) {
350
+ return false;
351
+ }
352
+ }
353
+ return this.aligned(time, base);
354
+ };
355
+
356
+ Rule.prototype.next = function(time, base) {
357
+ var MAX_ITERATIONS, current, minStep, potNext;
358
+ current = new Date(time);
359
+ minStep = this._minStep();
360
+ MAX_ITERATIONS = 1000;
361
+ while (!(this.match(current, base) && current > time)) {
362
+ if (!(MAX_ITERATIONS-- > 0)) {
363
+ throw "Maximum iterations reached when getting next rule occurrence...";
364
+ }
365
+ potNext = this._align(this._potentialNext(current, base), base);
366
+ if (Date.equals(potNext, current)) {
367
+ potNext.add(minStep.length)[minStep.unit]();
368
+ }
369
+ current = potNext;
370
+ }
371
+ return current;
372
+ };
373
+
374
+ Rule.prototype.previous = function(time, base) {
375
+ var MAX_ITERATIONS, current, minStep, potNext;
376
+ current = new Date(time);
377
+ minStep = this._minStep();
378
+ MAX_ITERATIONS = 1000;
379
+ while (!(this.match(current, base) && current < time)) {
380
+ if (!(MAX_ITERATIONS-- > 0)) {
381
+ throw "Maximum iterations reached when getting previous occurrence...";
382
+ }
383
+ potNext = this._align(this._potentialPrevious(current, base), base);
384
+ if (Date.equals(potNext, current)) {
385
+ potNext.add(-minStep.length)[minStep.unit]();
386
+ }
387
+ current = potNext;
388
+ }
389
+ return current;
390
+ };
391
+
392
+ Rule.prototype.aligned = function(time, base) {};
393
+
394
+ Rule.prototype.freq = function() {};
395
+
396
+ Rule.prototype.step = function() {};
397
+
398
+ Rule.prototype.toObject = function() {
399
+ var object;
400
+ object = {
401
+ freq: this.freq(),
402
+ interval: this.interval
403
+ };
404
+ if (this.count() != null) {
405
+ object.count = this.count();
406
+ }
407
+ if (this.stop() != null) {
408
+ object.stop = this.stop();
409
+ }
410
+ if (this.filters('weekdays') != null) {
411
+ object.weekdays = this.filters('weekdays').weekdays.concat(this.filters('weekdays').orderedWeekdays);
412
+ }
413
+ if (this.filters('monthdays') != null) {
414
+ object.monthdays = this.filters('monthdays').monthdays;
415
+ }
416
+ if (this.filters('yeardays') != null) {
417
+ object.yeardays = this.filters('yeardays').yeardays;
418
+ }
419
+ if (this.filters('months') != null) {
420
+ object.months = this.filters('months').months;
421
+ }
422
+ return object;
423
+ };
424
+
425
+ Rule.prototype.toJSON = function() {
426
+ return JSON.stringify(this.toObject());
427
+ };
428
+
429
+ Rule.prototype.toString = function() {
430
+ var dayNames, monthNames, strings;
431
+ dayNames = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"];
432
+ monthNames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
433
+ strings = [];
434
+ if (this.filters('months')) {
435
+ strings.push(this.filters('months').toString());
436
+ }
437
+ if (this.filters('weekdays')) {
438
+ strings.push(this.filters('weekdays').toString());
439
+ }
440
+ if (this.filters('monthdays')) {
441
+ strings.push(this.filters('monthdays').toString());
442
+ }
443
+ if (this.filters('yeardays')) {
444
+ strings.push(this.filters('yeardays').toString());
445
+ }
446
+ if (this.count()) {
447
+ strings.push("end after " + (this.count()) + " times");
448
+ }
449
+ if (this.stop()) {
450
+ strings.push("until " + monthNames[this.stop().getMonth()] + " " + (this.stop().getDate()) + ", " + (this.stop().getFullYear()));
451
+ }
452
+ return strings.join(", ");
453
+ };
454
+
455
+ Rule.prototype._potentialNext = function(current, base) {
456
+ var fNext, filter;
457
+ fNext = (function() {
458
+ var _i, _len, _ref, _results;
459
+ _ref = this.filters();
460
+ _results = [];
461
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
462
+ filter = _ref[_i];
463
+ _results.push(filter.next(current));
464
+ }
465
+ return _results;
466
+ }).call(this);
467
+ if (fNext.length > 0) {
468
+ return new Date(Math.max.apply(Math, fNext));
469
+ } else {
470
+ return current;
471
+ }
472
+ };
473
+
474
+ Rule.prototype._potentialPrevious = function(current, base) {
475
+ var fNext, filter;
476
+ fNext = (function() {
477
+ var _i, _len, _ref, _results;
478
+ _ref = this.filters();
479
+ _results = [];
480
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
481
+ filter = _ref[_i];
482
+ _results.push(filter.previous(current));
483
+ }
484
+ return _results;
485
+ }).call(this);
486
+ if (fNext.length > 0) {
487
+ return new Date(Math.max.apply(Math, fNext));
488
+ } else {
489
+ return current;
490
+ }
491
+ };
492
+
493
+ Rule.prototype._align = function(time, base) {
494
+ throw "" + (typeof this) + ".align should be overriden and return a time in the period of time parameter, aligned to base";
495
+ };
496
+
497
+ Rule.prototype._minStep = function() {
498
+ var filter, i, steps, _i, _ref;
499
+ if (this.__minStep != null) {
500
+ return this.__minStep;
501
+ }
502
+ steps = (function() {
503
+ var _i, _len, _ref, _results;
504
+ _ref = this.filters();
505
+ _results = [];
506
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
507
+ filter = _ref[_i];
508
+ _results.push(filter.step());
509
+ }
510
+ return _results;
511
+ }).call(this);
512
+ steps.push(this.step());
513
+ this.__minStep = steps[0];
514
+ for (i = _i = 1, _ref = steps.length; 1 <= _ref ? _i < _ref : _i > _ref; i = 1 <= _ref ? ++_i : --_i) {
515
+ if (steps[i].seconds < this.__minStep.seconds) {
516
+ this.__minStep = steps[i];
517
+ }
518
+ }
519
+ return this.__minStep;
520
+ };
521
+
522
+ return Rule;
523
+
524
+ })();
525
+
526
+ Schedule.Rule.daily = function(interval) {
527
+ if (interval == null) {
528
+ interval = 1;
529
+ }
530
+ return new Schedule.Rules.DailyRule(interval);
531
+ };
532
+
533
+ Schedule.Rule.yearly = function(interval) {
534
+ if (interval == null) {
535
+ interval = 1;
536
+ }
537
+ return new Schedule.Rules.YearlyRule(interval);
538
+ };
539
+
540
+ Schedule.Rule.weekly = function(interval) {
541
+ if (interval == null) {
542
+ interval = 1;
543
+ }
544
+ return new Schedule.Rules.WeeklyRule(interval);
545
+ };
546
+
547
+ Schedule.Rule.monthly = function(interval) {
548
+ if (interval == null) {
549
+ interval = 1;
550
+ }
551
+ return new Schedule.Rules.MonthlyRule(interval);
552
+ };
553
+
554
+ Schedule.Rule.fromObject = function(object) {
555
+ var rule;
556
+ if (!(object.freq && object.interval)) {
557
+ throw "Bad object format";
558
+ }
559
+ rule = Schedule.Rule[object.freq](+object.interval);
560
+ if (object.count != null) {
561
+ rule.count(object.count);
562
+ }
563
+ if (object.stop != null) {
564
+ rule.stop(object.stop);
565
+ }
566
+ if (object.weekdays != null) {
567
+ rule.weekdays.apply(rule, object.weekdays);
568
+ }
569
+ if (object.monthdays != null) {
570
+ rule.monthdays.apply(rule, object.monthdays);
571
+ }
572
+ if (object.yeardays != null) {
573
+ rule.yeardays.apply(rule, object.yeardays);
574
+ }
575
+ if (object.months != null) {
576
+ rule.months.apply(rule, object.months);
577
+ }
578
+ return rule;
579
+ };
580
+
581
+ Schedule.Rule.fromJSON = function(json) {
582
+ var o;
583
+ o = JSON.parse(json);
584
+ if (o.stop) {
585
+ o.stop = Date.parseISO8601(o.stop);
586
+ }
587
+ return Schedule.Rule.fromObject(o);
588
+ };
589
+
590
+ }).call(this);
591
+
592
+ (function() {
593
+ var _ref,
594
+ __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
595
+ __hasProp = {}.hasOwnProperty,
596
+ __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
597
+
598
+ Schedule.Rules.DailyRule = (function(_super) {
599
+ __extends(DailyRule, _super);
600
+
601
+ function DailyRule() {
602
+ this._align = __bind(this._align, this);
603
+ this._potential_previous = __bind(this._potential_previous, this);
604
+ this._potentialNext = __bind(this._potentialNext, this);
605
+ this.toString = __bind(this.toString, this);
606
+ this.step = __bind(this.step, this);
607
+ this.freq = __bind(this.freq, this);
608
+ this.aligned = __bind(this.aligned, this);
609
+ _ref = DailyRule.__super__.constructor.apply(this, arguments);
610
+ return _ref;
611
+ }
612
+
613
+ DailyRule.prototype.aligned = function(time, base) {
614
+ var _ref1;
615
+ _ref1 = [new Date(time), new Date(base)], time = _ref1[0], base = _ref1[1];
616
+ if (((new Date(base)).at({
617
+ hour: 0,
618
+ minute: 0,
619
+ second: 0
620
+ }) - (new Date(time)).at({
621
+ hour: 0,
622
+ minute: 0,
623
+ second: 0
624
+ })) % this.interval !== 0) {
625
+ return false;
626
+ }
627
+ if (!(time.getHours() === base.getHours() && time.getMinutes() === base.getMinutes() && time.getSeconds() === base.getSeconds())) {
628
+ return false;
629
+ }
630
+ return true;
631
+ };
632
+
633
+ DailyRule.prototype.freq = function() {
634
+ return 'daily';
635
+ };
636
+
637
+ DailyRule.prototype.step = function() {
638
+ return {
639
+ length: this.interval,
640
+ unit: 'days',
641
+ seconds: this.interval * 86400
642
+ };
643
+ };
644
+
645
+ DailyRule.prototype.toString = function() {
646
+ var string, sup;
647
+ sup = DailyRule.__super__.toString.call(this);
648
+ string = this.interval > 1 ? "Every " + this.interval + " days" : "Daily";
649
+ if (sup) {
650
+ string += ", " + sup;
651
+ }
652
+ return string;
653
+ };
654
+
655
+ DailyRule.prototype._potentialNext = function(current, base) {
656
+ var candidate, rem;
657
+ candidate = DailyRule.__super__._potentialNext.call(this, current, base);
658
+ rem = ((new Date(base)).at({
659
+ hour: 0,
660
+ minute: 0,
661
+ second: 0
662
+ }) - (new Date(candidate)).at({
663
+ hour: 0,
664
+ minute: 0,
665
+ second: 0
666
+ })) % this.interval;
667
+ if (rem === 0) {
668
+ return candidate;
669
+ }
670
+ return (new Date(candidate)).add(rem).days().at({
671
+ hour: 0,
672
+ minute: 0,
673
+ second: 0
674
+ });
675
+ };
676
+
677
+ DailyRule.prototype._potential_previous = function(current, base) {
678
+ var candidate, rem;
679
+ candidate = DailyRule.__super__._potential_previous.call(this, current, base);
680
+ rem = ((new Date(base)).at({
681
+ hour: 0,
682
+ minute: 0,
683
+ second: 0
684
+ }) - (new Date(candidate)).at({
685
+ hour: 0,
686
+ minute: 0,
687
+ second: 0
688
+ })) % this.interval;
689
+ if (rem === 0) {
690
+ return candidate;
691
+ }
692
+ return (new Date(candidate)).add(rem - this.interval).days().at({
693
+ hour: 0,
694
+ minute: 0
695
+ });
696
+ };
697
+
698
+ DailyRule.prototype._align = function(time, base) {
699
+ return time = (new Date(time)).at({
700
+ hour: 0,
701
+ minute: 0,
702
+ second: 0
703
+ }).add({
704
+ hours: base.getHours(),
705
+ minutes: base.getMinutes(),
706
+ seconds: base.getSeconds()
707
+ });
708
+ };
709
+
710
+ return DailyRule;
711
+
712
+ })(Schedule.Rule);
713
+
714
+ }).call(this);
715
+
716
+ (function() {
717
+ var _ref,
718
+ __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
719
+ __hasProp = {}.hasOwnProperty,
720
+ __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
721
+
722
+ Schedule.Rules.MonthlyRule = (function(_super) {
723
+ __extends(MonthlyRule, _super);
724
+
725
+ function MonthlyRule() {
726
+ this._monthdayFilters = __bind(this._monthdayFilters, this);
727
+ this._align = __bind(this._align, this);
728
+ this._potentialPrevious = __bind(this._potentialPrevious, this);
729
+ this._potentialNext = __bind(this._potentialNext, this);
730
+ this.toString = __bind(this.toString, this);
731
+ this.step = __bind(this.step, this);
732
+ this.freq = __bind(this.freq, this);
733
+ this.aligned = __bind(this.aligned, this);
734
+ _ref = MonthlyRule.__super__.constructor.apply(this, arguments);
735
+ return _ref;
736
+ }
737
+
738
+ MonthlyRule.prototype.aligned = function(time, base) {
739
+ if (((12 * base.getFullYear() + base.getMonth()) - (12 * time.getFullYear() + time.getMonth())) % this.interval !== 0) {
740
+ return false;
741
+ }
742
+ if (!(time.getHours() === base.getHours() && time.getMinutes() === base.getMinutes() && time.getSeconds() === base.getSeconds())) {
743
+ return false;
744
+ }
745
+ if (!(base.getDate() === time.getDate() || this._monthdayFilters())) {
746
+ return false;
747
+ }
748
+ return true;
749
+ };
750
+
751
+ MonthlyRule.prototype.freq = function() {
752
+ return 'monthly';
753
+ };
754
+
755
+ MonthlyRule.prototype.step = function() {
756
+ return {
757
+ length: this.interval,
758
+ unit: 'months',
759
+ seconds: this.interval * 2592000
760
+ };
761
+ };
762
+
763
+ MonthlyRule.prototype.toString = function() {
764
+ var string, sup;
765
+ sup = MonthlyRule.__super__.toString.call(this);
766
+ string = this.interval > 1 ? "Every " + this.interval + " months" : "Every month";
767
+ if (sup) {
768
+ string += ", " + sup;
769
+ }
770
+ return string;
771
+ };
772
+
773
+ MonthlyRule.prototype._potentialNext = function(current, base) {
774
+ var candidate, rem;
775
+ candidate = MonthlyRule.__super__._potentialNext.call(this, current, base);
776
+ rem = ((12 * base.getFullYear() + base.getMonth()) - (12 * candidate.getFullYear() + candidate.getMonth())) % this.interval;
777
+ if (rem === 0) {
778
+ return candidate;
779
+ }
780
+ if (rem < 0) {
781
+ rem += this.interval;
782
+ }
783
+ return (new Date(candidate)).add(rem).months().set({
784
+ day: 1
785
+ }).at({
786
+ hour: 0,
787
+ minute: 0,
788
+ second: 0
789
+ });
790
+ };
791
+
792
+ MonthlyRule.prototype._potentialPrevious = function(current, base) {
793
+ var candidate, rem;
794
+ candidate = MonthlyRule.__super__._potentialPrevious.call(this, current, base);
795
+ rem = ((12 * base.getFullYear() + base.getMonth()) - (12 * candidate.getFullYear() + candidate.getMonth())) % this.interval;
796
+ if (rem === 0) {
797
+ return candidate;
798
+ }
799
+ if (rem < 0) {
800
+ rem += this.interval;
801
+ }
802
+ return (new Date(candidate)).add(rem - this.interval + 1).months().set({
803
+ day: 1
804
+ }).add(-1).day().at({
805
+ hour: 0,
806
+ minute: 0,
807
+ second: 0
808
+ });
809
+ };
810
+
811
+ MonthlyRule.prototype._align = function(time, base) {
812
+ if (!(time.getDate() === base.getDate() || this._monthdayFilters())) {
813
+ time = (new Date(time)).set({
814
+ day: 1
815
+ }).add(base.getDate() - 1).days();
816
+ }
817
+ return time = time.at({
818
+ hour: 0,
819
+ minute: 0,
820
+ second: 0
821
+ }).add({
822
+ hours: base.getHours(),
823
+ minutes: base.getMinutes(),
824
+ seconds: base.getSeconds()
825
+ });
826
+ };
827
+
828
+ MonthlyRule.prototype._monthdayFilters = function() {
829
+ return (this.filters('weekdays') != null) || (this.filters('monthdays') != null) || (this.filters('yeardays') != null) || (this.filters('weeks') != null) || (this.filters('months') != null);
830
+ };
831
+
832
+ return MonthlyRule;
833
+
834
+ })(Schedule.Rule);
835
+
836
+ }).call(this);
837
+
838
+ (function() {
839
+ var _ref,
840
+ __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
841
+ __hasProp = {}.hasOwnProperty,
842
+ __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
843
+
844
+ Schedule.Rules.WeeklyRule = (function(_super) {
845
+ __extends(WeeklyRule, _super);
846
+
847
+ function WeeklyRule() {
848
+ this._weekdayFilters = __bind(this._weekdayFilters, this);
849
+ this._align = __bind(this._align, this);
850
+ this._potentialPrevious = __bind(this._potentialPrevious, this);
851
+ this._potentialNext = __bind(this._potentialNext, this);
852
+ this.toString = __bind(this.toString, this);
853
+ this.step = __bind(this.step, this);
854
+ this.freq = __bind(this.freq, this);
855
+ this.aligned = __bind(this.aligned, this);
856
+ _ref = WeeklyRule.__super__.constructor.apply(this, arguments);
857
+ return _ref;
858
+ }
859
+
860
+ WeeklyRule.prototype.aligned = function(time, base) {
861
+ var base_mm, time_mm;
862
+ base_mm = (new Date(base)).add(-base.getDay()).days().at({
863
+ hour: 0,
864
+ minute: 0,
865
+ second: 0
866
+ });
867
+ time_mm = (new Date(time)).add(-time.getDay()).days().at({
868
+ hour: 0,
869
+ minute: 0,
870
+ second: 0
871
+ });
872
+ if ((~~((base_mm - time_mm) / 604800000) % this.interval) !== 0) {
873
+ return false;
874
+ }
875
+ if (!(time.getHours() === base.getHours() && time.getMinutes() === base.getMinutes() && time.getSeconds() === base.getSeconds())) {
876
+ return false;
877
+ }
878
+ if (!(base.getDay() === time.getDay() || this._weekdayFilters())) {
879
+ return false;
880
+ }
881
+ return true;
882
+ };
883
+
884
+ WeeklyRule.prototype.freq = function() {
885
+ return 'weekly';
886
+ };
887
+
888
+ WeeklyRule.prototype.step = function() {
889
+ return {
890
+ length: this.interval,
891
+ unit: 'weeks',
892
+ seconds: this.interval * 604800000
893
+ };
894
+ };
895
+
896
+ WeeklyRule.prototype.toString = function() {
897
+ var string, sup;
898
+ sup = WeeklyRule.__super__.toString.call(this);
899
+ string = this.interval > 1 ? "Every " + this.interval + " weeks" : "Weekly";
900
+ if (sup) {
901
+ string += ", " + sup;
902
+ }
903
+ return string;
904
+ };
905
+
906
+ WeeklyRule.prototype._potentialNext = function(current, base) {
907
+ var base_mm, candidate, candidate_mm, next, rem;
908
+ candidate = WeeklyRule.__super__._potentialNext.call(this, current, base);
909
+ base_mm = (new Date(base)).add(-base.getDay()).days().at({
910
+ hour: 0,
911
+ minute: 0,
912
+ second: 0
913
+ });
914
+ candidate_mm = (new Date(candidate)).add(-candidate.getDay()).days().at({
915
+ hour: 0,
916
+ minute: 0,
917
+ second: 0
918
+ });
919
+ rem = (~~((base_mm - candidate_mm) / 604800000)) % this.interval;
920
+ if (rem === 0) {
921
+ return candidate;
922
+ }
923
+ if (rem < 0) {
924
+ rem += this.interval;
925
+ }
926
+ next = new Date(candidate).add(rem).weeks();
927
+ return next.add(-next.getDay()).days().at({
928
+ hour: 0,
929
+ minute: 0,
930
+ second: 0
931
+ });
932
+ };
933
+
934
+ WeeklyRule.prototype._potentialPrevious = function(current, base) {
935
+ var base_mm, candidate, candidate_mm, next, rem;
936
+ candidate = WeeklyRule.__super__._potentialPrevious.call(this, current, base);
937
+ base_mm = (new Date(base)).add(-base.getDay()).days().at({
938
+ hour: 0,
939
+ minute: 0,
940
+ second: 0
941
+ });
942
+ candidate_mm = (new Date(candidate)).add(-candidate.getDay()).days().at({
943
+ hour: 0,
944
+ minute: 0,
945
+ second: 0
946
+ });
947
+ rem = (~~((base_mm - candidate_mm) / 604800000)) % this.interval;
948
+ if (rem === 0) {
949
+ return candidate;
950
+ }
951
+ if (rem < 0) {
952
+ rem += this.interval;
953
+ }
954
+ next = (new Date(candidate)).add(rem).weeks().add(-this.interval).weeks();
955
+ return next.add(-next.getDay()).days().at({
956
+ hour: 0,
957
+ minute: 0,
958
+ second: 0
959
+ }).add(1).week().add(-1).second();
960
+ };
961
+
962
+ WeeklyRule.prototype._align = function(time, base) {
963
+ if (!(time.getDay() === base.getDay() || this._weekdayFilters())) {
964
+ time = (new Date(time)).add(-time.getDay()).days().at({
965
+ hour: 0,
966
+ minute: 0,
967
+ second: 0
968
+ }).add(base.getDay()).days();
969
+ }
970
+ return time = (new Date(time)).at({
971
+ hour: 0,
972
+ minute: 0,
973
+ second: 0
974
+ }).add({
975
+ hours: base.getHours(),
976
+ minutes: base.getMinutes(),
977
+ seconds: base.getSeconds()
978
+ });
979
+ };
980
+
981
+ WeeklyRule.prototype._weekdayFilters = function() {
982
+ return (this.filters('weekdays') != null) || (this.filters('monthdays') != null) || (this.filters('yeardays') != null) || (this.filters('yeardays') != null) || (this.filters('weeks') != null) || (this.filters('months') != null);
983
+ };
984
+
985
+ return WeeklyRule;
986
+
987
+ })(Schedule.Rule);
988
+
989
+ }).call(this);
990
+
991
+ (function() {
992
+ var _ref,
993
+ __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
994
+ __hasProp = {}.hasOwnProperty,
995
+ __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
996
+
997
+ Schedule.Rules.YearlyRule = (function(_super) {
998
+ __extends(YearlyRule, _super);
999
+
1000
+ function YearlyRule() {
1001
+ this._monthFilters = __bind(this._monthFilters, this);
1002
+ this._dayFilters = __bind(this._dayFilters, this);
1003
+ this._align = __bind(this._align, this);
1004
+ this._potentialPrevious = __bind(this._potentialPrevious, this);
1005
+ this._potentialNext = __bind(this._potentialNext, this);
1006
+ this.toString = __bind(this.toString, this);
1007
+ this.freq = __bind(this.freq, this);
1008
+ this.aligned = __bind(this.aligned, this);
1009
+ _ref = YearlyRule.__super__.constructor.apply(this, arguments);
1010
+ return _ref;
1011
+ }
1012
+
1013
+ YearlyRule.prototype.aligned = function(time, base) {
1014
+ if ((base.getFullYear() - time.getFullYear()) % this.interval !== 0) {
1015
+ return false;
1016
+ }
1017
+ if (!(time.getHours() === base.getHours() && time.getMinutes() === base.getMinutes() && time.getSeconds() === base.getSeconds())) {
1018
+ return false;
1019
+ }
1020
+ if (!(time.getDate() === base.getDate() || this._dayFilters())) {
1021
+ return false;
1022
+ }
1023
+ if (!(time.getMonth() === base.getMonth() || this._monthFilters())) {
1024
+ return false;
1025
+ }
1026
+ return true;
1027
+ };
1028
+
1029
+ YearlyRule.prototype.freq = function() {
1030
+ return 'yearly';
1031
+ };
1032
+
1033
+ YearlyRule.prototype.step = function() {
1034
+ return {
1035
+ length: this.interval,
1036
+ unit: 'years',
1037
+ seconds: this.interval * 31536000
1038
+ };
1039
+ };
1040
+
1041
+ YearlyRule.prototype.toString = function() {
1042
+ var string, sup;
1043
+ sup = YearlyRule.__super__.toString.call(this);
1044
+ string = this.interval > 1 ? "Every " + this.interval + " years" : "Every year";
1045
+ if (sup) {
1046
+ string += ", " + sup;
1047
+ }
1048
+ return string;
1049
+ };
1050
+
1051
+ YearlyRule.prototype._potentialNext = function(current, base) {
1052
+ var candidate, years;
1053
+ candidate = YearlyRule.__super__._potentialNext.call(this, current, base);
1054
+ if ((base.getFullYear() - candidate.getFullYear()) % this.interval === 0) {
1055
+ return candidate;
1056
+ }
1057
+ years = (base.getFullYear() - candidate.getFullYear()) % this.interval;
1058
+ if (years < 0) {
1059
+ years += this.interval;
1060
+ }
1061
+ return (new Date(candidate)).add(years).years().set({
1062
+ month: 0,
1063
+ day: 1
1064
+ });
1065
+ };
1066
+
1067
+ YearlyRule.prototype._potentialPrevious = function(current, base) {
1068
+ var candidate, years;
1069
+ candidate = YearlyRule.__super__._potentialPrevious.call(this, current, base);
1070
+ if ((base.getFullYear() - candidate.getFullYear()) % this.interval === 0) {
1071
+ return candidate;
1072
+ }
1073
+ years = (base.getFullYear() - candidate.getFullYear()) % this.interval;
1074
+ if (years < 0) {
1075
+ years += this.interval;
1076
+ }
1077
+ return (new Date(candidate)).add(years - this.interval).years().set({
1078
+ month: 0,
1079
+ day: 1
1080
+ });
1081
+ };
1082
+
1083
+ YearlyRule.prototype._align = function(time, base) {
1084
+ var day, mon;
1085
+ day = (this._dayFilters() ? time.getDate() : base.getDate());
1086
+ mon = (this._monthFilters() ? time.getMonth() : base.getMonth());
1087
+ time = (new Date(time)).set({
1088
+ month: 0,
1089
+ day: 1
1090
+ }).add(mon).months().add(day - 1).days();
1091
+ return time.at({
1092
+ hour: 0,
1093
+ minute: 0,
1094
+ second: 0
1095
+ }).add({
1096
+ hours: base.getHours(),
1097
+ minutes: base.getMinutes(),
1098
+ seconds: base.getSeconds()
1099
+ });
1100
+ };
1101
+
1102
+ YearlyRule.prototype._dayFilters = function() {
1103
+ return (this.filters('weekdays') != null) || (this.filters('monthdays') != null) || (this.filters('yeardays') != null);
1104
+ };
1105
+
1106
+ YearlyRule.prototype._monthFilters = function() {
1107
+ return (this.filters('weekdays') != null) || (this.filters('yeardays') != null) || (this.filters('weeks') != null) || (this.filters('months') != null);
1108
+ };
1109
+
1110
+ return YearlyRule;
1111
+
1112
+ })(Schedule.Rule);
1113
+
1114
+ }).call(this);
1115
+
1116
+ (function() {
1117
+ var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
1118
+ __slice = [].slice;
1119
+
1120
+ Schedule.Filters.MonthdaysFilter = (function() {
1121
+ function MonthdaysFilter() {
1122
+ var monthdays;
1123
+ monthdays = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
1124
+ this.toString = __bind(this.toString, this);
1125
+ this.previous = __bind(this.previous, this);
1126
+ this.next = __bind(this.next, this);
1127
+ this.step = __bind(this.step, this);
1128
+ this.match = __bind(this.match, this);
1129
+ if (monthdays.length < 1) {
1130
+ throw "Specify at least one day of the month";
1131
+ }
1132
+ this.monthdays = monthdays.sort(function(a, b) {
1133
+ return a - b;
1134
+ });
1135
+ }
1136
+
1137
+ MonthdaysFilter.prototype.match = function(date) {
1138
+ var last;
1139
+ last = (new Date(date)).add(1).month().set({
1140
+ day: 1
1141
+ }).add(-1).day().getDate();
1142
+ return this.monthdays.indexOf(date.getDate()) >= 0 || this.monthdays.indexOf(date.getDate() - last - 1) >= 0;
1143
+ };
1144
+
1145
+ MonthdaysFilter.prototype.step = function() {
1146
+ return {
1147
+ length: 1,
1148
+ unit: 'day',
1149
+ seconds: 86400
1150
+ };
1151
+ };
1152
+
1153
+ MonthdaysFilter.prototype.next = function(date) {
1154
+ date = new Date(date);
1155
+ while (!this.match(date)) {
1156
+ date.add(1).day();
1157
+ }
1158
+ return date;
1159
+ };
1160
+
1161
+ MonthdaysFilter.prototype.previous = function(date) {
1162
+ date = new Date(date);
1163
+ while (!this.match(date)) {
1164
+ date.add(-1).day();
1165
+ }
1166
+ return date;
1167
+ };
1168
+
1169
+ MonthdaysFilter.prototype.toString = function() {
1170
+ var days, last;
1171
+ days = _.map(this.monthdays, function(d) {
1172
+ return "" + d + ".";
1173
+ });
1174
+ last = days.pop();
1175
+ if (days.length > 0) {
1176
+ return "on " + (days.join(", ")) + " and " + last + " day";
1177
+ } else {
1178
+ return "on " + last + " day";
1179
+ }
1180
+ };
1181
+
1182
+ return MonthdaysFilter;
1183
+
1184
+ })();
1185
+
1186
+ }).call(this);
1187
+
1188
+ (function() {
1189
+ var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
1190
+ __slice = [].slice;
1191
+
1192
+ Schedule.Filters.MonthsFilter = (function() {
1193
+ MonthsFilter.prototype.MONTH_NAMES = {
1194
+ jan: 1,
1195
+ january: 1,
1196
+ feb: 2,
1197
+ february: 2,
1198
+ mar: 3,
1199
+ march: 3,
1200
+ apr: 4,
1201
+ april: 4,
1202
+ may: 5,
1203
+ jun: 6,
1204
+ june: 6,
1205
+ jul: 7,
1206
+ july: 7,
1207
+ aug: 8,
1208
+ august: 8,
1209
+ sep: 9,
1210
+ sept: 9,
1211
+ september: 9,
1212
+ oct: 10,
1213
+ october: 10,
1214
+ nov: 11,
1215
+ november: 11,
1216
+ dec: 12,
1217
+ december: 12
1218
+ };
1219
+
1220
+ function MonthsFilter() {
1221
+ var month, months;
1222
+ months = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
1223
+ this.toString = __bind(this.toString, this);
1224
+ this.previous = __bind(this.previous, this);
1225
+ this.next = __bind(this.next, this);
1226
+ this.match = __bind(this.match, this);
1227
+ if (months.length < 1) {
1228
+ throw "Specify at least one month";
1229
+ }
1230
+ this.months = (function() {
1231
+ var _i, _len, _results;
1232
+ _results = [];
1233
+ for (_i = 0, _len = months.length; _i < _len; _i++) {
1234
+ month = months[_i];
1235
+ _results.push(!isNaN(parseFloat(month)) ? month : this.MONTH_NAMES[month]);
1236
+ }
1237
+ return _results;
1238
+ }).call(this);
1239
+ this.months = this.months.sort();
1240
+ }
1241
+
1242
+ MonthsFilter.prototype.match = function(date) {
1243
+ return this.months.indexOf(date.getMonth() + 1) >= 0;
1244
+ };
1245
+
1246
+ MonthsFilter.prototype.step = function() {
1247
+ return {
1248
+ length: 1,
1249
+ unit: 'month',
1250
+ seconds: 2592000
1251
+ };
1252
+ };
1253
+
1254
+ MonthsFilter.prototype.next = function(date) {
1255
+ var d, m, month, _i, _len, _ref;
1256
+ if (this.match(date)) {
1257
+ return date;
1258
+ }
1259
+ month = null;
1260
+ _ref = this.months;
1261
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
1262
+ m = _ref[_i];
1263
+ if (m > date.getMonth() + 1) {
1264
+ month = m;
1265
+ }
1266
+ }
1267
+ if (month != null) {
1268
+ return (new Date(date)).set({
1269
+ month: 0,
1270
+ day: 1
1271
+ }).add(month - 1).months().at({
1272
+ hour: date.getHours(),
1273
+ minute: date.getMinutes(),
1274
+ second: date.getSeconds()
1275
+ });
1276
+ } else {
1277
+ d = (new Date(date)).set({
1278
+ month: 0,
1279
+ day: 1
1280
+ }).add(1).year().add(this.months[0] - 1).months();
1281
+ return d.at({
1282
+ hour: date.getHours(),
1283
+ minute: date.getMinutes(),
1284
+ second: date.getSeconds()
1285
+ });
1286
+ }
1287
+ };
1288
+
1289
+ MonthsFilter.prototype.previous = function(date) {
1290
+ var d, m, month, _i, _len, _ref;
1291
+ if (match(date)) {
1292
+ return date;
1293
+ }
1294
+ month = null;
1295
+ _ref = this.months.reverse();
1296
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
1297
+ m = _ref[_i];
1298
+ if (m < date.getMonth() + 1) {
1299
+ month = m;
1300
+ }
1301
+ }
1302
+ if (month != null) {
1303
+ d = (new Date(date)).set({
1304
+ month: 0,
1305
+ day: 1
1306
+ }).add(month).months().add(-1).day();
1307
+ return d.at({
1308
+ hour: date.getHours(),
1309
+ minute: date.getMinutes(),
1310
+ second: date.getSeconds()
1311
+ });
1312
+ } else {
1313
+ d = (new Date(date)).set({
1314
+ month: 0,
1315
+ day: 1
1316
+ }).add(-1).year().add(this.months.last).months().add(-1).day();
1317
+ return d.at({
1318
+ hour: date.getHours(),
1319
+ minute: date.getMinutes(),
1320
+ second: date.getSeconds()
1321
+ });
1322
+ }
1323
+ };
1324
+
1325
+ MonthsFilter.prototype.toString = function() {
1326
+ var last, monthNames, months;
1327
+ monthNames = [null, "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
1328
+ months = _.map(this.months, function(m) {
1329
+ return monthNames[m];
1330
+ });
1331
+ last = months.pop();
1332
+ if (months.length > 0) {
1333
+ return "in " + (months.join(", ")) + " and " + last;
1334
+ } else {
1335
+ return "in " + last;
1336
+ }
1337
+ };
1338
+
1339
+ return MonthsFilter;
1340
+
1341
+ })();
1342
+
1343
+ }).call(this);
1344
+
1345
+ (function() {
1346
+ var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
1347
+ __slice = [].slice;
1348
+
1349
+ Schedule.Filters.WeekdaysFilter = (function() {
1350
+ WeekdaysFilter.prototype.WEEKDAYS = {
1351
+ su: 0,
1352
+ sun: 0,
1353
+ sunday: 0,
1354
+ mo: 1,
1355
+ mon: 1,
1356
+ monday: 1,
1357
+ tu: 2,
1358
+ tue: 2,
1359
+ tuesday: 2,
1360
+ we: 3,
1361
+ wed: 3,
1362
+ wednesday: 3,
1363
+ th: 4,
1364
+ thu: 4,
1365
+ thursday: 4,
1366
+ fr: 5,
1367
+ fri: 5,
1368
+ friday: 5,
1369
+ sa: 6,
1370
+ sat: 6,
1371
+ saturday: 6
1372
+ };
1373
+
1374
+ WeekdaysFilter.prototype.WEEKDAY_NAMES = ['su', 'mo', 'tu', 'we', 'th', 'fr', 'sa'];
1375
+
1376
+ function WeekdaysFilter() {
1377
+ var day, orders, w, weekdays, _ref;
1378
+ weekdays = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
1379
+ this.toString = __bind(this.toString, this);
1380
+ this._orderInInterval = __bind(this._orderInInterval, this);
1381
+ this.previous = __bind(this.previous, this);
1382
+ this.next = __bind(this.next, this);
1383
+ this.step = __bind(this.step, this);
1384
+ this.match = __bind(this.match, this);
1385
+ if (weekdays[0] instanceof Schedule.Rule) {
1386
+ this.rule = weekdays.shift();
1387
+ }
1388
+ if (weekdays.length < 1) {
1389
+ throw "Specify at least one weekday";
1390
+ }
1391
+ this.orderedWeekdays = {};
1392
+ if (weekdays[weekdays.length - 1] instanceof Object) {
1393
+ if (this.rule == null) {
1394
+ throw "No recurrence rule given for ordered weekdays filter";
1395
+ }
1396
+ _ref = weekdays[weekdays.length - 1];
1397
+ for (day in _ref) {
1398
+ orders = _ref[day];
1399
+ day = !isNaN(parseFloat(day)) ? day : this.WEEKDAYS[day];
1400
+ if (orders.length == null) {
1401
+ orders = [orders];
1402
+ }
1403
+ this.orderedWeekdays[this.WEEKDAY_NAMES[day]] = orders.sort();
1404
+ }
1405
+ weekdays = weekdays.slice(0, -1);
1406
+ }
1407
+ this.weekdays = (function() {
1408
+ var _i, _len, _results;
1409
+ _results = [];
1410
+ for (_i = 0, _len = weekdays.length; _i < _len; _i++) {
1411
+ w = weekdays[_i];
1412
+ _results.push(!isNaN(parseFloat(w)) ? w : this.WEEKDAYS[w]);
1413
+ }
1414
+ return _results;
1415
+ }).call(this);
1416
+ this.weekdays.sort();
1417
+ }
1418
+
1419
+ WeekdaysFilter.prototype.match = function(date) {
1420
+ var day, first, max, occ, _ref;
1421
+ if (this.weekdays.indexOf(date.getDay()) >= 0) {
1422
+ return true;
1423
+ }
1424
+ day = this.WEEKDAY_NAMES[date.getDay()];
1425
+ if (this.orderedWeekdays[day] == null) {
1426
+ return false;
1427
+ }
1428
+ _ref = this._orderInInterval(date), first = _ref[0], occ = _ref[1], max = _ref[2];
1429
+ return this.orderedWeekdays[day].indexOf(occ) >= 0 || this.orderedWeekdays[day].indexOf(occ - max - 1) >= 0;
1430
+ };
1431
+
1432
+ WeekdaysFilter.prototype.step = function() {
1433
+ return {
1434
+ length: 1,
1435
+ unit: 'day',
1436
+ seconds: 846000
1437
+ };
1438
+ };
1439
+
1440
+ WeekdaysFilter.prototype.next = function(date) {
1441
+ var MAX_ITERATIONS;
1442
+ date = new Date(date);
1443
+ MAX_ITERATIONS = 10000;
1444
+ while (!this.match(date)) {
1445
+ if (!(MAX_ITERATIONS-- > 0)) {
1446
+ throw "Maximum iterations reached in WeekdaysFilter.next";
1447
+ }
1448
+ date.add(1).day();
1449
+ }
1450
+ return date;
1451
+ };
1452
+
1453
+ WeekdaysFilter.prototype.previous = function(date) {
1454
+ var MAX_ITERATIONS;
1455
+ date = new Date(date);
1456
+ MAX_ITERATIONS = 10000;
1457
+ while (!this.match(date)) {
1458
+ if (!(MAX_ITERATIONS-- > 0)) {
1459
+ throw "Maximum iterations reached in WeekdaysFilter.previous";
1460
+ }
1461
+ date.add(-1).day();
1462
+ }
1463
+ return date;
1464
+ };
1465
+
1466
+ WeekdaysFilter.prototype._orderInInterval = function(date) {
1467
+ var eoy, eyday, first, janfirst, max, occ, yday;
1468
+ janfirst = (new Date(date)).set({
1469
+ month: 0,
1470
+ day: 1
1471
+ });
1472
+ if (this.rule instanceof Schedule.Rules.YearlyRule) {
1473
+ first = (7 + date.getDay() - janfirst.getDay()) % 7 + 1;
1474
+ yday = Math.ceil((date - janfirst) / 1000 / 60 / 60 / 24) + 1;
1475
+ occ = ~~((yday - first) / 7) + 1;
1476
+ eoy = (new Date(date)).add(1).year().set({
1477
+ month: 0,
1478
+ day: 1
1479
+ }).add(-1).day();
1480
+ eyday = Math.ceil((eoy - janfirst) / 1000 / 60 / 60 / 24) + 1;
1481
+ max = ~~((eyday - first) / 7) + 1;
1482
+ } else if (this.rule instanceof Schedule.Rules.MonthlyRule) {
1483
+ first = (7 + date.getDay() - (new Date(date)).set({
1484
+ day: 1
1485
+ }).getDay()) % 7 + 1;
1486
+ occ = ~~((date.getDate() - first) / 7) + 1;
1487
+ max = ~~(((new Date(date)).add(1).month().set({
1488
+ day: 1
1489
+ }).add(-1).day().getDate() - first) / 7) + 1;
1490
+ } else {
1491
+ throw "Ordered weekdays filter only supports monthy and yearly rules. (" + this.rule["class"] + " given)";
1492
+ }
1493
+ return [first, occ, max];
1494
+ };
1495
+
1496
+ WeekdaysFilter.prototype.toString = function() {
1497
+ var dayNames, days, last, owdays, wdays,
1498
+ _this = this;
1499
+ dayNames = ["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"];
1500
+ wdays = _.map(this.weekdays, function(w) {
1501
+ return dayNames[w];
1502
+ });
1503
+ owdays = _.map(this.orderedWeekdays, function(ord, d) {
1504
+ return "" + (_.map(ord, function(o) {
1505
+ return "" + o + ".";
1506
+ }).join(", ")) + " " + dayNames[_this.WEEKDAYS[d]];
1507
+ });
1508
+ days = wdays.concat(owdays);
1509
+ last = days.pop();
1510
+ if (days.length > 0) {
1511
+ return "on " + (days.join(", ")) + " and " + last;
1512
+ } else {
1513
+ return "on " + last;
1514
+ }
1515
+ };
1516
+
1517
+ return WeekdaysFilter;
1518
+
1519
+ })();
1520
+
1521
+ }).call(this);
1522
+
1523
+ (function() {
1524
+ var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
1525
+ __slice = [].slice;
1526
+
1527
+ Schedule.Filters.YeardaysFilter = (function() {
1528
+ function YeardaysFilter() {
1529
+ var yeardays;
1530
+ yeardays = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
1531
+ this.toString = __bind(this.toString, this);
1532
+ this.yearDay = __bind(this.yearDay, this);
1533
+ this.previous = __bind(this.previous, this);
1534
+ this.next = __bind(this.next, this);
1535
+ this.step = __bind(this.step, this);
1536
+ this.match = __bind(this.match, this);
1537
+ if (yeardays.length < 1) {
1538
+ throw "Specify at least one day of the month";
1539
+ }
1540
+ this.yeardays = yeardays.sort();
1541
+ }
1542
+
1543
+ YeardaysFilter.prototype.match = function(date) {
1544
+ var eoy, last;
1545
+ eoy = (new Date(date)).set({
1546
+ month: 0,
1547
+ day: 1
1548
+ }).add(1).year().add(-1).day();
1549
+ last = this.yearDay(eoy);
1550
+ return (this.yeardays.indexOf(this.yearDay(date)) >= 0) || (this.yeardays.indexOf(this.yearDay(date) - last - 1) >= 0);
1551
+ };
1552
+
1553
+ YeardaysFilter.prototype.step = function() {
1554
+ return {
1555
+ length: 1,
1556
+ unit: 'day',
1557
+ seconds: 86400
1558
+ };
1559
+ };
1560
+
1561
+ YeardaysFilter.prototype.next = function(date) {
1562
+ date = new Date(date);
1563
+ while (!this.match(date)) {
1564
+ date.add(1).day();
1565
+ }
1566
+ return date;
1567
+ };
1568
+
1569
+ YeardaysFilter.prototype.previous = function(date) {
1570
+ date = new Date(date);
1571
+ while (!this.match(date)) {
1572
+ date.add(-1).day();
1573
+ }
1574
+ return date;
1575
+ };
1576
+
1577
+ YeardaysFilter.prototype.yearDay = function(date) {
1578
+ var janFirst;
1579
+ date = new Date(date);
1580
+ janFirst = (new Date(date)).set({
1581
+ month: 0,
1582
+ day: 1
1583
+ });
1584
+ return Math.ceil((date - janFirst) / 86400000) + 1;
1585
+ };
1586
+
1587
+ YeardaysFilter.prototype.toString = function() {
1588
+ var days, last;
1589
+ days = _.map(this.yeardays, function(d) {
1590
+ return "" + d + ".";
1591
+ });
1592
+ last = days.pop();
1593
+ if (days.length > 0) {
1594
+ return "on " + (days.join(", ")) + " and " + last + " day";
1595
+ } else {
1596
+ return "on " + last + " day";
1597
+ }
1598
+ };
1599
+
1600
+ return YeardaysFilter;
1601
+
1602
+ })();
1603
+
1604
+ }).call(this);
1605
+
1606
+ (function() {
1607
+ Schedule.Suboccurrence = (function() {
1608
+ function Suboccurrence(attrs) {
1609
+ this.start = attrs.start;
1610
+ this.end = attrs.end;
1611
+ this.isOccurrenceStart = attrs.isOccurrenceStart;
1612
+ this.isOccurrenceEnd = attrs.isOccurrenceEnd;
1613
+ }
1614
+
1615
+ return Suboccurrence;
1616
+
1617
+ })();
1618
+
1619
+ Schedule.Suboccurrence.find = function(attrs) {
1620
+ var interval, occurrence, suboccurrence;
1621
+ if ((occurrence = attrs.occurrence).length == null) {
1622
+ throw "Missing occurrence";
1623
+ }
1624
+ if ((interval = attrs.interval).length == null) {
1625
+ throw "Missing interval";
1626
+ }
1627
+ if (occurrence[1] <= interval[0] || occurrence[0] >= interval[2]) {
1628
+ return null;
1629
+ }
1630
+ suboccurrence = {};
1631
+ if (occurrence[0] < interval[0]) {
1632
+ suboccurrence.start = interval[0];
1633
+ suboccurrence.isOccurrenceStart = false;
1634
+ } else {
1635
+ suboccurrence.start = occurrence[0];
1636
+ suboccurrence.isOccurrenceStart = true;
1637
+ }
1638
+ if (occurrence[1] > interval[1]) {
1639
+ suboccurrence.end = interval[1];
1640
+ suboccurrence.isOccurrenceEnd = false;
1641
+ } else {
1642
+ suboccurrence.end = occurrence[1];
1643
+ suboccurrence.isOccurrenceEnd = true;
1644
+ }
1645
+ return new Schedule.Suboccurrence(suboccurrence);
1646
+ };
1647
+
1648
+ }).call(this);
1649
+
1650
+ (function() {
1651
+ var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
1652
+
1653
+ Schedule.Occurrence = (function() {
1654
+ function Occurrence(rule, startTime) {
1655
+ this._initLoop = __bind(this._initLoop, this);
1656
+ this._listOccurrences = __bind(this._listOccurrences, this);
1657
+ this.toObject = __bind(this.toObject, this);
1658
+ this.all = __bind(this.all, this);
1659
+ this.suboccurrencesBetween = __bind(this.suboccurrencesBetween, this);
1660
+ this.occurrencesBetween = __bind(this.occurrencesBetween, this);
1661
+ this.previousOccurrences = __bind(this.previousOccurrences, this);
1662
+ this.previousOccurrence = __bind(this.previousOccurrence, this);
1663
+ this.nextOccurrences = __bind(this.nextOccurrences, this);
1664
+ this.nextOccurrence = __bind(this.nextOccurrence, this);
1665
+ this.rule = rule;
1666
+ this.startTime = this.rule.match(startTime, startTime) ? startTime : this.rule.next(startTime, startTime);
1667
+ }
1668
+
1669
+ Occurrence.prototype.nextOccurrence = function(after) {
1670
+ return this.nextOccurrences(1, after)[0];
1671
+ };
1672
+
1673
+ Occurrence.prototype.nextOccurrences = function(n, after) {
1674
+ var time;
1675
+ if ((this.rule.stop() != null) && after > this.rule.stop()) {
1676
+ return [];
1677
+ }
1678
+ time = (after <= this.startTime ? this.startTime : after);
1679
+ if (!this.rule.match(time, this.startTime)) {
1680
+ time = this.rule.next(time, this.startTime);
1681
+ }
1682
+ return this._listOccurrences(time, function() {
1683
+ return (n -= 1) >= 0;
1684
+ });
1685
+ };
1686
+
1687
+ Occurrence.prototype.previousOccurrence = function(before) {
1688
+ return this.previousOccurrences(1, before)[0];
1689
+ };
1690
+
1691
+ Occurrence.prototype.previousOccurrences = function(n, before) {
1692
+ var time;
1693
+ if (before <= this.startTime) {
1694
+ return [];
1695
+ }
1696
+ time = ((this.rule.stop() == null) || before < this.rule.stop() ? before : this.rule.stop());
1697
+ time = this.rule.previous(time, this.startTime);
1698
+ return this._listOccurrences(time, 'back', function() {
1699
+ return (n -= 1) >= 0;
1700
+ }).reverse();
1701
+ };
1702
+
1703
+ Occurrence.prototype.occurrencesBetween = function(t1, t2) {
1704
+ var time;
1705
+ if (!(t2 > t1)) {
1706
+ throw "Empty time interval";
1707
+ }
1708
+ if (t2 <= this.startTime || (this.rule.stop() != null) && t1 >= this.rule.stop()) {
1709
+ return [];
1710
+ }
1711
+ time = (t1 <= this.startTime ? this.startTime : t1);
1712
+ if (!this.rule.match(time, this.startTime)) {
1713
+ time = this.rule.next(time, this.startTime);
1714
+ }
1715
+ return this._listOccurrences(time, function(t) {
1716
+ return t < t2;
1717
+ });
1718
+ };
1719
+
1720
+ Occurrence.prototype.suboccurrencesBetween = function(t1, t2) {
1721
+ var occ, occurrences, _i, _len, _results;
1722
+ occurrences = this.occurrencesBetween(new Date(t1 - this.duration), t2);
1723
+ _results = [];
1724
+ for (_i = 0, _len = occurrences.length; _i < _len; _i++) {
1725
+ occ = occurrences[_i];
1726
+ _results.push(Schedule.Suboccurrence.find({
1727
+ occurrence: [occ, new Date(+occ + this.duration)],
1728
+ interval: [t1, t2]
1729
+ }));
1730
+ }
1731
+ return _results;
1732
+ };
1733
+
1734
+ Occurrence.prototype.all = function() {
1735
+ var n, rule;
1736
+ if (this.rule.stop() != null) {
1737
+ rule = this.rule;
1738
+ return this._listOccurrences(this.startTime, function(t) {
1739
+ return t < rule.stop();
1740
+ });
1741
+ } else {
1742
+ n = this.rule.count();
1743
+ return this._listOccurrences(this.startTime, function() {
1744
+ return (n -= 1) >= 0;
1745
+ });
1746
+ }
1747
+ };
1748
+
1749
+ Occurrence.prototype.toObject = function() {
1750
+ return this.rule.toObject();
1751
+ };
1752
+
1753
+ Occurrence.prototype._listOccurrences = function(from, direction_or_func, func) {
1754
+ var MAX_ITERATIONS, current, direction, n, results, _ref;
1755
+ if (!this.rule.match(from, this.startTime)) {
1756
+ throw "From " + from + " not matching the rule " + this.rule + " and start time " + this.startTime;
1757
+ }
1758
+ if (func != null) {
1759
+ direction = direction_or_func;
1760
+ } else {
1761
+ direction = 'forward';
1762
+ func = direction_or_func;
1763
+ }
1764
+ results = [];
1765
+ _ref = this._initLoop(from, direction), n = _ref[0], current = _ref[1];
1766
+ MAX_ITERATIONS = 10000;
1767
+ while (true) {
1768
+ if (!(MAX_ITERATIONS-- > 0)) {
1769
+ throw "Maximum iterations reached when listing occurrences...";
1770
+ }
1771
+ if (!((current >= this.startTime) && ((this.rule.stop() == null) || current < this.rule.stop()) && ((this.rule.count() == null) || (n -= 1) >= 0))) {
1772
+ return results;
1773
+ }
1774
+ if (!func(current)) {
1775
+ return results;
1776
+ }
1777
+ results.push(current);
1778
+ if (direction === 'forward') {
1779
+ current = this.rule.next(current, this.startTime);
1780
+ } else {
1781
+ current = this.rule.previous(current, this.startTime);
1782
+ }
1783
+ }
1784
+ };
1785
+
1786
+ Occurrence.prototype._initLoop = function(from, direction) {
1787
+ var current, n;
1788
+ if (this.rule.count() == null) {
1789
+ return [0, from];
1790
+ }
1791
+ if (direction === 'forward') {
1792
+ n = 0;
1793
+ current = this.startTime;
1794
+ while (current < from) {
1795
+ n += 1;
1796
+ current = this.rule.next(current, this.startTime);
1797
+ }
1798
+ return [this.rule.count() - n, current];
1799
+ } else {
1800
+ n = 0;
1801
+ current = this.startTime;
1802
+ while (current < from && (n += 1) < this.rule.count()) {
1803
+ current = this.rule.next(current, this.startTime);
1804
+ }
1805
+ return [this.rule.count(), current];
1806
+ }
1807
+ };
1808
+
1809
+ return Occurrence;
1810
+
1811
+ })();
1812
+
1813
+ }).call(this);