cyclical-rails 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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);