diff options
Diffstat (limited to 'radicale_web/web/infcloud/lib/rrule.js')
-rw-r--r-- | radicale_web/web/infcloud/lib/rrule.js | 1910 |
1 files changed, 0 insertions, 1910 deletions
diff --git a/radicale_web/web/infcloud/lib/rrule.js b/radicale_web/web/infcloud/lib/rrule.js deleted file mode 100644 index ed2689e..0000000 --- a/radicale_web/web/infcloud/lib/rrule.js +++ /dev/null @@ -1,1910 +0,0 @@ -/*! - * rrule.js - Library for working with recurrence rules for calendar dates. - * https://github.com/jakubroztocil/rrule - * - * Copyright 2010, Jakub Roztocil and Lars Schoning - * Licenced under the BSD licence. - * https://github.com/jakubroztocil/rrule/blob/master/LICENCE - * - * Based on: - * python-dateutil - Extensions to the standard Python datetime module. - * Copyright (c) 2003-2011 - Gustavo Niemeyer <gustavo@niemeyer.net> - * Copyright (c) 2012 - Tomi Pieviläinen <tomi.pievilainen@iki.fi> - * https://github.com/jakubroztocil/rrule/blob/master/LICENCE - * - */ -(function(root){ - -var serverSide = typeof module !== 'undefined' && module.exports; - - -var getnlp = function() { - if (!getnlp._nlp) { - if (serverSide) { - // Lazy, runtime import to avoid circular refs. - getnlp._nlp = require('./nlp') - } else if (!(getnlp._nlp = root._RRuleNLP)) { - throw new Error( - 'You need to include rrule/nlp.js for fromText/toText to work.' - ) - } - } - return getnlp._nlp; -}; - - -//============================================================================= -// Date utilities -//============================================================================= - -/** - * General date-related utilities. - * Also handles several incompatibilities between JavaScript and Python - * - */ -var dateutil = { - - MONTH_DAYS: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], - - /** - * Number of milliseconds of one day - */ - ONE_DAY: 1000 * 60 * 60 * 24, - - /** - * @see: <http://docs.python.org/library/datetime.html#datetime.MAXYEAR> - */ - MAXYEAR: 9999, - - /** - * Python uses 1-Jan-1 as the base for calculating ordinals but we don't - * want to confuse the JS engine with milliseconds > Number.MAX_NUMBER, - * therefore we use 1-Jan-1970 instead - */ - ORDINAL_BASE: new Date(1970, 0, 1), - - /** - * Python: MO-SU: 0 - 6 - * JS: SU-SAT 0 - 6 - */ - PY_WEEKDAYS: [6, 0, 1, 2, 3, 4, 5], - - /** - * py_date.timetuple()[7] - */ - getYearDay: function(date) { - var dateNoTime = new Date( - date.getFullYear(), date.getMonth(), date.getDate()); - return Math.ceil( - (dateNoTime - new Date(date.getFullYear(), 0, 1)) - / dateutil.ONE_DAY) + 1; - }, - - isLeapYear: function(year) { - if (year instanceof Date) { - year = year.getFullYear(); - } - return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0); - }, - - /** - * @return {Number} the date's timezone offset in ms - */ - tzOffset: function(date) { - return date.getTimezoneOffset() * 60 * 1000 - }, - - /** - * @see: <http://www.mcfedries.com/JavaScript/DaysBetween.asp> - */ - daysBetween: function(date1, date2) { - // The number of milliseconds in one day - // Convert both dates to milliseconds - var date1_ms = date1.getTime() - dateutil.tzOffset(date1); - var date2_ms = date2.getTime() - dateutil.tzOffset(date2); - // Calculate the difference in milliseconds - var difference_ms = Math.abs(date1_ms - date2_ms); - // Convert back to days and return - return Math.round(difference_ms / dateutil.ONE_DAY); - }, - - /** - * @see: <http://docs.python.org/library/datetime.html#datetime.date.toordinal> - */ - toOrdinal: function(date) { - return dateutil.daysBetween(date, dateutil.ORDINAL_BASE); - }, - - /** - * @see - <http://docs.python.org/library/datetime.html#datetime.date.fromordinal> - */ - fromOrdinal: function(ordinal) { - var millisecsFromBase = ordinal * dateutil.ONE_DAY; - return new Date(dateutil.ORDINAL_BASE.getTime() - - dateutil.tzOffset(dateutil.ORDINAL_BASE) - + millisecsFromBase - + dateutil.tzOffset(new Date(millisecsFromBase))); - }, - - /** - * @see: <http://docs.python.org/library/calendar.html#calendar.monthrange> - */ - monthRange: function(year, month) { - var date = new Date(year, month, 1); - return [dateutil.getWeekday(date), dateutil.getMonthDays(date)]; - }, - - getMonthDays: function(date) { - var month = date.getMonth(); - return month == 1 && dateutil.isLeapYear(date) - ? 29 - : dateutil.MONTH_DAYS[month]; - }, - - /** - * @return {Number} python-like weekday - */ - getWeekday: function(date) { - return dateutil.PY_WEEKDAYS[date.getDay()]; - }, - - /** - * @see: <http://docs.python.org/library/datetime.html#datetime.datetime.combine> - */ - combine: function(date, time) { - time = time || date; - return new Date( - date.getFullYear(), date.getMonth(), date.getDate(), - time.getHours(), time.getMinutes(), time.getSeconds() - ); - }, - - clone: function(date) { - var dolly = new Date(date.getTime()); - dolly.setMilliseconds(0); - return dolly; - }, - - cloneDates: function(dates) { - var clones = []; - for (var i = 0; i < dates.length; i++) { - clones.push(dateutil.clone(dates[i])); - } - return clones; - }, - - /** - * Sorts an array of Date or dateutil.Time objects - */ - sort: function(dates) { - dates.sort(function(a, b){ - return a.getTime() - b.getTime(); - }); - }, - - timeToUntilString: function(time) { - var date = new Date(time); - var comp, comps = [ - date.getUTCFullYear(), - date.getUTCMonth() + 1, - date.getUTCDate(), - 'T', - date.getUTCHours(), - date.getUTCMinutes(), - date.getUTCSeconds(), - 'Z' - ]; - for (var i = 0; i < comps.length; i++) { - comp = comps[i]; - if (!/[TZ]/.test(comp) && comp < 10) { - comps[i] = '0' + String(comp); - } - } - return comps.join(''); - }, - - untilStringToDate: function(until) { - var re = /^(\d{4})(\d{2})(\d{2})(T(\d{2})(\d{2})(\d{2})Z)?$/; - var bits = re.exec(until); - if (!bits) { - throw new Error('Invalid UNTIL value: ' + until) - } - return new Date( - Date.UTC(bits[1], - bits[2] - 1, - bits[3], - bits[5] || 0, - bits[6] || 0, - bits[7] || 0 - )); - } - -}; - -dateutil.Time = function(hour, minute, second) { - this.hour = hour; - this.minute = minute; - this.second = second; -}; - -dateutil.Time.prototype = { - getHours: function() { - return this.hour; - }, - getMinutes: function() { - return this.minute; - }, - getSeconds: function() { - return this.second; - }, - getTime: function() { - return ((this.hour * 60 * 60) - + (this.minute * 60) - + this.second) - * 1000; - } -}; - - -//============================================================================= -// Helper functions -//============================================================================= - - -/** - * Simplified version of python's range() - */ -var range = function(start, end) { - if (arguments.length === 1) { - end = start; - start = 0; - } - var rang = []; - for (var i = start; i < end; i++) { - rang.push(i); - } - return rang; -}; -var repeat = function(value, times) { - var i = 0, array = []; - if (value instanceof Array) { - for (; i < times; i++) { - array[i] = [].concat(value); - } - } else { - for (; i < times; i++) { - array[i] = value; - } - } - return array; -}; - - -/** - * closure/goog/math/math.js:modulo - * Copyright 2006 The Closure Library Authors. - * The % operator in JavaScript returns the remainder of a / b, but differs from - * some other languages in that the result will have the same sign as the - * dividend. For example, -1 % 8 == -1, whereas in some other languages - * (such as Python) the result would be 7. This function emulates the more - * correct modulo behavior, which is useful for certain applications such as - * calculating an offset index in a circular list. - * - * @param {number} a The dividend. - * @param {number} b The divisor. - * @return {number} a % b where the result is between 0 and b (either 0 <= x < b - * or b < x <= 0, depending on the sign of b). - */ -var pymod = function(a, b) { - var r = a % b; - // If r and b differ in sign, add b to wrap the result to the correct sign. - return (r * b < 0) ? r + b : r; -}; - - -/** - * @see: <http://docs.python.org/library/functions.html#divmod> - */ -var divmod = function(a, b) { - return {div: Math.floor(a / b), mod: pymod(a, b)}; -}; - - -/** - * Python-like boolean - * @return {Boolean} value of an object/primitive, taking into account - * the fact that in Python an empty list's/tuple's - * boolean value is False, whereas in JS it's true - */ -var plb = function(obj) { - return (obj instanceof Array && obj.length == 0) - ? false - : Boolean(obj); -}; - - -/** - * Return true if a value is in an array - */ -var contains = function(arr, val) { - return arr.indexOf(val) != -1; -}; - - -//============================================================================= -// Date masks -//============================================================================= - -// Every mask is 7 days longer to handle cross-year weekly periods. - -var M365MASK = [].concat( - repeat(1, 31), repeat(2, 28), repeat(3, 31), - repeat(4, 30), repeat(5, 31), repeat(6, 30), - repeat(7, 31), repeat(8, 31), repeat(9, 30), - repeat(10, 31), repeat(11, 30), repeat(12, 31), - repeat(1, 7) -); -var M366MASK = [].concat( - repeat(1, 31), repeat(2, 29), repeat(3, 31), - repeat(4, 30), repeat(5, 31), repeat(6, 30), - repeat(7, 31), repeat(8, 31), repeat(9, 30), - repeat(10, 31), repeat(11, 30), repeat(12, 31), - repeat(1, 7) -); - -var - M28 = range(1, 29), - M29 = range(1, 30), - M30 = range(1, 31), - M31 = range(1, 32); -var MDAY366MASK = [].concat( - M31, M29, M31, - M30, M31, M30, - M31, M31, M30, - M31, M30, M31, - M31.slice(0, 7) -); -var MDAY365MASK = [].concat( - M31, M28, M31, - M30, M31, M30, - M31, M31, M30, - M31, M30, M31, - M31.slice(0, 7) -); - -M28 = range(-28, 0); -M29 = range(-29, 0); -M30 = range(-30, 0); -M31 = range(-31, 0); -var NMDAY366MASK = [].concat( - M31, M29, M31, - M30, M31, M30, - M31, M31, M30, - M31, M30, M31, - M31.slice(0, 7) -); -var NMDAY365MASK = [].concat( - M31, M28, M31, - M30, M31, M30, - M31, M31, M30, - M31, M30, M31, - M31.slice(0, 7) -); - -var M366RANGE = [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366]; -var M365RANGE = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365]; - -var WDAYMASK = (function() { - for (var wdaymask = [], i = 0; i < 55; i++) { - wdaymask = wdaymask.concat(range(7)); - } - return wdaymask; -}()); - - -//============================================================================= -// Weekday -//============================================================================= - -var Weekday = function(weekday, n) { - if (n === 0) { - throw new Error('Can\'t create weekday with n == 0'); - } - this.weekday = weekday; - this.n = n; -}; - -Weekday.prototype = { - - // __call__ - Cannot call the object directly, do it through - // e.g. RRule.TH.nth(-1) instead, - nth: function(n) { - return this.n == n ? this : new Weekday(this.weekday, n); - }, - - // __eq__ - equals: function(other) { - return this.weekday == other.weekday && this.n == other.n; - }, - - // __repr__ - toString: function() { - var s = ['MO', 'TU', 'WE', 'TH', 'FR', 'SA', 'SU'][this.weekday]; - if (this.n) { - s = (this.n > 0 ? '+' : '') + String(this.n) + s; - } - return s; - }, - - getJsWeekday: function() { - return this.weekday == 6 ? 0 : this.weekday + 1; - } - -}; - - -//============================================================================= -// RRule -//============================================================================= - -/** - * - * @param {Object?} options - see <http://labix.org/python-dateutil/#head-cf004ee9a75592797e076752b2a889c10f445418> - * The only required option is `freq`, one of RRule.YEARLY, RRule.MONTHLY, ... - * @constructor - */ -var RRule = function(options, noCache) { - - // RFC string - this._string = null; - - options = options || {}; - - this._cache = noCache ? null : { - all: false, - before: [], - after: [], - between: [] - }; - - // used by toString() - this.origOptions = {}; - - var invalid = [], - keys = Object.keys(options), - defaultKeys = Object.keys(RRule.DEFAULT_OPTIONS); - - // Shallow copy for origOptions and check for invalid - keys.forEach(function(key) { - this.origOptions[key] = options[key]; - if (!contains(defaultKeys, key)) invalid.push(key); - }, this); - - if (invalid.length) { - throw new Error('Invalid options: ' + invalid.join(', ')) - } - - if (!RRule.FREQUENCIES[options.freq] && options.byeaster === null) { - throw new Error('Invalid frequency: ' + String(options.freq)) - } - - // Merge in default options - defaultKeys.forEach(function(key) { - if (!contains(keys, key)) options[key] = RRule.DEFAULT_OPTIONS[key]; - }); - - var opts = this.options = options; - - if (opts.byeaster !== null) { - opts.freq = RRule.YEARLY; - } - - if (!opts.dtstart) { - opts.dtstart = new Date(); - opts.dtstart.setMilliseconds(0); - } - - if (opts.wkst === null) { - opts.wkst = RRule.MO.weekday; - } else if (typeof opts.wkst == 'number') { - // cool, just keep it like that - } else { - opts.wkst = opts.wkst.weekday; - } - - if (opts.bysetpos !== null) { - if (typeof opts.bysetpos == 'number') { - opts.bysetpos = [opts.bysetpos]; - } - for (var i = 0; i < opts.bysetpos.length; i++) { - var v = opts.bysetpos[i]; - if (v == 0 || !(-366 <= v && v <= 366)) { - throw new Error( - 'bysetpos must be between 1 and 366,' + - ' or between -366 and -1' - ); - } - } - } - - if (!(plb(opts.byweekno) || plb(opts.byyearday) - || plb(opts.bymonthday) || opts.byweekday !== null - || opts.byeaster !== null)) - { - switch (opts.freq) { - case RRule.YEARLY: - if (!opts.bymonth) { - opts.bymonth = opts.dtstart.getMonth() + 1; - } - opts.bymonthday = opts.dtstart.getDate(); - break; - case RRule.MONTHLY: - opts.bymonthday = opts.dtstart.getDate(); - break; - case RRule.WEEKLY: - opts.byweekday = dateutil.getWeekday( - opts.dtstart); - break; - } - } - - // bymonth - if (opts.bymonth !== null - && !(opts.bymonth instanceof Array)) { - opts.bymonth = [opts.bymonth]; - } - - // byyearday - if (opts.byyearday !== null - && !(opts.byyearday instanceof Array)) { - opts.byyearday = [opts.byyearday]; - } - - // bymonthday - if (opts.bymonthday === null) { - opts.bymonthday = []; - opts.bynmonthday = []; - } else if (opts.bymonthday instanceof Array) { - var bymonthday = [], bynmonthday = []; - - for (i = 0; i < opts.bymonthday.length; i++) { - var v = opts.bymonthday[i]; - if (v > 0) { - bymonthday.push(v); - } else if (v < 0) { - bynmonthday.push(v); - } - } - opts.bymonthday = bymonthday; - opts.bynmonthday = bynmonthday; - } else { - if (opts.bymonthday < 0) { - opts.bynmonthday = [opts.bymonthday]; - opts.bymonthday = []; - } else { - opts.bynmonthday = []; - opts.bymonthday = [opts.bymonthday]; - } - } - - // byweekno - if (opts.byweekno !== null - && !(opts.byweekno instanceof Array)) { - opts.byweekno = [opts.byweekno]; - } - - // byweekday / bynweekday - if (opts.byweekday === null) { - opts.bynweekday = null; - } else if (typeof opts.byweekday == 'number') { - opts.byweekday = [opts.byweekday]; - opts.bynweekday = null; - - } else if (opts.byweekday instanceof Weekday) { - - if (!opts.byweekday.n || opts.freq > RRule.MONTHLY) { - opts.byweekday = [opts.byweekday.weekday]; - opts.bynweekday = null; - } else { - opts.bynweekday = [ - [opts.byweekday.weekday, - opts.byweekday.n] - ]; - opts.byweekday = null; - } - - } else { - var byweekday = [], bynweekday = []; - - for (i = 0; i < opts.byweekday.length; i++) { - var wday = opts.byweekday[i]; - - if (typeof wday == 'number') { - byweekday.push(wday); - } else if (!wday.n || opts.freq > RRule.MONTHLY) { - byweekday.push(wday.weekday); - } else { - bynweekday.push([wday.weekday, wday.n]); - } - } - opts.byweekday = plb(byweekday) ? byweekday : null; - opts.bynweekday = plb(bynweekday) ? bynweekday : null; - } - - // byhour - if (opts.byhour === null) { - opts.byhour = (opts.freq < RRule.HOURLY) - ? [opts.dtstart.getHours()] - : null; - } else if (typeof opts.byhour == 'number') { - opts.byhour = [opts.byhour]; - } - - // byminute - if (opts.byminute === null) { - opts.byminute = (opts.freq < RRule.MINUTELY) - ? [opts.dtstart.getMinutes()] - : null; - } else if (typeof opts.byminute == 'number') { - opts.byminute = [opts.byminute]; - } - - // bysecond - if (opts.bysecond === null) { - opts.bysecond = (opts.freq < RRule.SECONDLY) - ? [opts.dtstart.getSeconds()] - : null; - } else if (typeof opts.bysecond == 'number') { - opts.bysecond = [opts.bysecond]; - } - - if (opts.freq >= RRule.HOURLY) { - this.timeset = null; - } else { - this.timeset = []; - for (i = 0; i < opts.byhour.length; i++) { - var hour = opts.byhour[i]; - for (var j = 0; j < opts.byminute.length; j++) { - var minute = opts.byminute[j]; - for (var k = 0; k < opts.bysecond.length; k++) { - var second = opts.bysecond[k]; - // python: - // datetime.time(hour, minute, second, - // tzinfo=self._tzinfo)) - this.timeset.push(new dateutil.Time(hour, minute, second)); - } - } - } - dateutil.sort(this.timeset); - } - -}; -//}}} - -// RRule class 'constants' - -RRule.FREQUENCIES = [ - 'YEARLY', 'MONTHLY', 'WEEKLY', 'DAILY', - 'HOURLY', 'MINUTELY', 'SECONDLY' -]; - -RRule.YEARLY = 0; -RRule.MONTHLY = 1; -RRule.WEEKLY = 2; -RRule.DAILY = 3; -RRule.HOURLY = 4; -RRule.MINUTELY = 5; -RRule.SECONDLY = 6; - -RRule.MO = new Weekday(0); -RRule.TU = new Weekday(1); -RRule.WE = new Weekday(2); -RRule.TH = new Weekday(3); -RRule.FR = new Weekday(4); -RRule.SA = new Weekday(5); -RRule.SU = new Weekday(6); - -RRule.DEFAULT_OPTIONS = { - freq: null, - dtstart: null, - interval: 1, - wkst: RRule.MO, - count: null, - until: null, - bysetpos: null, - bymonth: null, - bymonthday: null, - byyearday: null, - byweekno: null, - byweekday: null, - byhour: null, - byminute: null, - bysecond: null, - byeaster: null -}; - - - -RRule.parseText = function(text, language) { - return getnlp().parseText(text, language) -}; - -RRule.fromText = function(text, language) { - return getnlp().fromText(text, language) -}; - -RRule.optionsToString = function(options) { - var key, keys, defaultKeys, value, strValues, pairs = []; - - keys = Object.keys(options); - defaultKeys = Object.keys(RRule.DEFAULT_OPTIONS); - - for (var i = 0; i < keys.length; i++) { - - if (!contains(defaultKeys, keys[i])) continue; - - key = keys[i].toUpperCase(); - value = options[keys[i]]; - strValues = []; - - if (value === null || value instanceof Array && !value.length) { - continue; - } - - switch (key) { - case 'FREQ': - value = RRule.FREQUENCIES[options.freq]; - break; - case 'WKST': - value = value.toString(); - break; - case 'BYWEEKDAY': - /* - NOTE: BYWEEKDAY is a special case. - RRule() deconstructs the rule.options.byweekday array - into an array of Weekday arguments. - On the other hand, rule.origOptions is an array of Weekdays. - We need to handle both cases here. - It might be worth change RRule to keep the Weekdays. - - Also, BYWEEKDAY (used by RRule) vs. BYDAY (RFC) - - */ - key = 'BYDAY'; - if (!(value instanceof Array)) { - value = [value]; - } - for (var wday, j = 0; j < value.length; j++) { - wday = value[j]; - if (wday instanceof Weekday) { - // good - } else if (wday instanceof Array) { - wday = new Weekday(wday[0], wday[1]); - } else { - wday = new Weekday(wday); - } - strValues[j] = wday.toString(); - } - value = strValues; - break; - case'DTSTART': - case'UNTIL': - value = dateutil.timeToUntilString(value); - break; - default: - if (value instanceof Array) { - for (var j = 0; j < value.length; j++) { - strValues[j] = String(value[j]); - } - value = strValues; - } else { - value = String(value); - } - - } - pairs.push([key, value]); - } - - var strings = []; - for (var i = 0; i < pairs.length; i++) { - var attr = pairs[i]; - strings.push(attr[0] + '=' + attr[1].toString()); - } - return strings.join(';'); - -}; - -RRule.prototype = { - - /** - * @param {Function} iterator - optional function that will be called - * on each date that is added. It can return false - * to stop the iteration. - * @return Array containing all recurrences. - */ - all: function(iterator) { - if (iterator) { - return this._iter(new CallbackIterResult('all', {}, iterator)); - } else { - var result = this._cacheGet('all'); - if (result === false) { - result = this._iter(new IterResult('all', {})); - this._cacheAdd('all', result); - } - return result; - } - }, - - /** - * Returns all the occurrences of the rrule between after and before. - * The inc keyword defines what happens if after and/or before are - * themselves occurrences. With inc == True, they will be included in the - * list, if they are found in the recurrence set. - * @return Array - */ - between: function(after, before, inc, iterator) { - var args = { - before: before, - after: after, - inc: inc - } - - if (iterator) { - return this._iter( - new CallbackIterResult('between', args, iterator)); - } else { - var result = this._cacheGet('between', args); - if (result === false) { - result = this._iter(new IterResult('between', args)); - this._cacheAdd('between', result, args); - } - return result; - } - }, - - /** - * Returns the last recurrence before the given datetime instance. - * The inc keyword defines what happens if dt is an occurrence. - * With inc == True, if dt itself is an occurrence, it will be returned. - * @return Date or null - */ - before: function(dt, inc) { - var args = { - dt: dt, - inc: inc - }, - result = this._cacheGet('before', args); - if (result === false) { - result = this._iter(new IterResult('before', args)); - this._cacheAdd('before', result, args); - } - return result; - }, - - /** - * Returns the first recurrence after the given datetime instance. - * The inc keyword defines what happens if dt is an occurrence. - * With inc == True, if dt itself is an occurrence, it will be returned. - * @return Date or null - */ - after: function(dt, inc) { - var args = { - dt: dt, - inc: inc - }, - result = this._cacheGet('after', args); - if (result === false) { - result = this._iter(new IterResult('after', args)); - this._cacheAdd('after', result, args); - } - return result; - }, - - /** - * Returns the number of recurrences in this set. It will have go trough - * the whole recurrence, if this hasn't been done before. - */ - count: function() { - return this.all().length; - }, - - /** - * Converts the rrule into its string representation - * @see <http://www.ietf.org/rfc/rfc2445.txt> - * @return String - */ - toString: function() { - return RRule.optionsToString(this.origOptions); - }, - - /** - * Will convert all rules described in nlp:ToText - * to text. - */ - toText: function(gettext, language) { - return getnlp().toText(this, gettext, language); - }, - - isFullyConvertibleToText: function() { - return getnlp().isFullyConvertible(this) - }, - - /** - * @param {String} what - all/before/after/between - * @param {Array,Date} value - an array of dates, one date, or null - * @param {Object?} args - _iter arguments - */ - _cacheAdd: function(what, value, args) { - - if (!this._cache) return; - - if (value) { - value = (value instanceof Date) - ? dateutil.clone(value) - : dateutil.cloneDates(value); - } - - if (what == 'all') { - this._cache.all = value; - } else { - args._value = value; - this._cache[what].push(args); - } - - }, - - /** - * @return false - not in the cache - * null - cached, but zero occurrences (before/after) - * Date - cached (before/after) - * [] - cached, but zero occurrences (all/between) - * [Date1, DateN] - cached (all/between) - */ - _cacheGet: function(what, args) { - - if (!this._cache) { - return false; - } - - var cached = false; - - if (what == 'all') { - cached = this._cache.all; - } else { - // Let's see whether we've already called the - // 'what' method with the same 'args' - loopItems: - for (var item, i = 0; i < this._cache[what].length; i++) { - item = this._cache[what][i]; - for (var k in args) { - if (args.hasOwnProperty(k) - && String(args[k]) != String(item[k])) { - continue loopItems; - } - } - cached = item._value; - break; - } - } - - if (!cached && this._cache.all) { - // Not in the cache, but we already know all the occurrences, - // so we can find the correct dates from the cached ones. - var iterResult = new IterResult(what, args); - for (var i = 0; i < this._cache.all.length; i++) { - if (!iterResult.accept(this._cache.all[i])) { - break; - } - } - cached = iterResult.getValue(); - this._cacheAdd(what, cached, args); - } - - return cached instanceof Array - ? dateutil.cloneDates(cached) - : (cached instanceof Date - ? dateutil.clone(cached) - : cached); - }, - - /** - * @return a RRule instance with the same freq and options - * as this one (cache is not cloned) - */ - clone: function() { - return new RRule(this.origOptions); - }, - - _iter: function(iterResult) { - - /* Since JavaScript doesn't have the python's yield operator (<1.7), - we use the IterResult object that tells us when to stop iterating. - - */ - - var dtstart = this.options.dtstart; - - var - year = dtstart.getFullYear(), - month = dtstart.getMonth() + 1, - day = dtstart.getDate(), - hour = dtstart.getHours(), - minute = dtstart.getMinutes(), - second = dtstart.getSeconds(), - weekday = dateutil.getWeekday(dtstart), - yearday = dateutil.getYearDay(dtstart); - - // Some local variables to speed things up a bit - var - freq = this.options.freq, - interval = this.options.interval, - wkst = this.options.wkst, - until = this.options.until, - bymonth = this.options.bymonth, - byweekno = this.options.byweekno, - byyearday = this.options.byyearday, - byweekday = this.options.byweekday, - byeaster = this.options.byeaster, - bymonthday = this.options.bymonthday, - bynmonthday = this.options.bynmonthday, - bysetpos = this.options.bysetpos, - byhour = this.options.byhour, - byminute = this.options.byminute, - bysecond = this.options.bysecond; - - var ii = new Iterinfo(this); - ii.rebuild(year, month); - - var getdayset = {}; - getdayset[RRule.YEARLY] = ii.ydayset; - getdayset[RRule.MONTHLY] = ii.mdayset; - getdayset[RRule.WEEKLY] = ii.wdayset; - getdayset[RRule.DAILY] = ii.ddayset; - getdayset[RRule.HOURLY] = ii.ddayset; - getdayset[RRule.MINUTELY] = ii.ddayset; - getdayset[RRule.SECONDLY] = ii.ddayset; - - getdayset = getdayset[freq]; - - var timeset; - if (freq < RRule.HOURLY) { - timeset = this.timeset; - } else { - var gettimeset = {}; - gettimeset[RRule.HOURLY] = ii.htimeset; - gettimeset[RRule.MINUTELY] = ii.mtimeset; - gettimeset[RRule.SECONDLY] = ii.stimeset; - gettimeset = gettimeset[freq]; - if ((freq >= RRule.HOURLY && plb(byhour) && !contains(byhour, hour)) || - (freq >= RRule.MINUTELY && plb(byminute) && !contains(byminute, minute)) || - (freq >= RRule.SECONDLY && plb(bysecond) && !contains(bysecond, minute))) - { - timeset = []; - } else { - timeset = gettimeset.call(ii, hour, minute, second); - } - } - - var filtered, total = 0, count = this.options.count; - - var iterNo = 0; - - var i, j, k, dm, div, mod, tmp, pos, dayset, start, end, fixday; - - while (true) { - - // Get dayset with the right frequency - tmp = getdayset.call(ii, year, month, day); - dayset = tmp[0]; start = tmp[1]; end = tmp[2]; - - // Do the "hard" work ;-) - filtered = false; - for (j = start; j < end; j++) { - - i = dayset[j]; - - if ((plb(bymonth) && !contains(bymonth, ii.mmask[i])) || - (plb(byweekno) && !ii.wnomask[i]) || - (plb(byweekday) && !contains(byweekday, ii.wdaymask[i])) || - (plb(ii.nwdaymask) && !ii.nwdaymask[i]) || - (byeaster !== null && !contains(ii.eastermask, i)) || - ( - (plb(bymonthday) || plb(bynmonthday)) && - !contains(bymonthday, ii.mdaymask[i]) && - !contains(bynmonthday, ii.nmdaymask[i]) - ) - || - ( - plb(byyearday) - && - ( - ( - i < ii.yearlen && - !contains(byyearday, i + 1) && - !contains(byyearday, -ii.yearlen + i) - ) - || - ( - i >= ii.yearlen && - !contains(byyearday, i + 1 - ii.yearlen) && - !contains(byyearday, -ii.nextyearlen + i - ii.yearlen) - ) - ) - ) - ) - { - dayset[i] = null; - filtered = true; - } - } - - // Output results - if (plb(bysetpos) && plb(timeset)) { - - var daypos, timepos, poslist = []; - - for (i, j = 0; j < bysetpos.length; j++) { - var pos = bysetpos[j]; - if (pos < 0) { - daypos = Math.floor(pos / timeset.length); - timepos = pymod(pos, timeset.length); - } else { - daypos = Math.floor((pos - 1) / timeset.length); - timepos = pymod((pos - 1), timeset.length); - } - - try { - tmp = []; - for (k = start; k < end; k++) { - var val = dayset[k]; - if (val === null) { - continue; - } - tmp.push(val); - } - if (daypos < 0) { - // we're trying to emulate python's aList[-n] - i = tmp.slice(daypos)[0]; - } else { - i = tmp[daypos]; - } - - var time = timeset[timepos]; - - var date = dateutil.fromOrdinal(ii.yearordinal + i); - var res = dateutil.combine(date, time); - // XXX: can this ever be in the array? - // - compare the actual date instead? - if (!contains(poslist, res)) { - poslist.push(res); - } - } catch (e) {} - } - - dateutil.sort(poslist); - - for (j = 0; j < poslist.length; j++) { - var res = poslist[j]; - if (until && res > until) { - this._len = total; - return iterResult.getValue(); - } else if (res >= dtstart) { - ++total; - if (!iterResult.accept(res)) { - return iterResult.getValue(); - } - if (count) { - --count; - if (!count) { - this._len = total; - return iterResult.getValue(); - } - } - } - } - - } else { - for (j = start; j < end; j++) { - i = dayset[j]; - if (i !== null) { - var date = dateutil.fromOrdinal(ii.yearordinal + i); - for (k = 0; k < timeset.length; k++) { - var time = timeset[k]; - var res = dateutil.combine(date, time); - if (until && res > until) { - this._len = total; - return iterResult.getValue(); - } else if (res >= dtstart) { - ++total; - if (!iterResult.accept(res)) { - return iterResult.getValue(); - } - if (count) { - --count; - if (!count) { - this._len = total; - return iterResult.getValue(); - } - } - } - } - } - } - } - - // Handle frequency and interval - fixday = false; - if (freq == RRule.YEARLY) { - year += interval; - if (year > dateutil.MAXYEAR) { - this._len = total; - return iterResult.getValue(); - } - ii.rebuild(year, month); - } else if (freq == RRule.MONTHLY) { - month += interval; - if (month > 12) { - div = Math.floor(month / 12); - mod = pymod(month, 12); - month = mod; - year += div; - if (month == 0) { - month = 12; - --year; - } - if (year > dateutil.MAXYEAR) { - this._len = total; - return iterResult.getValue(); - } - } - ii.rebuild(year, month); - } else if (freq == RRule.WEEKLY) { - if (wkst > weekday) { - day += -(weekday + 1 + (6 - wkst)) + interval * 7; - } else { - day += -(weekday - wkst) + interval * 7; - } - weekday = wkst; - fixday = true; - } else if (freq == RRule.DAILY) { - day += interval; - fixday = true; - } else if (freq == RRule.HOURLY) { - if (filtered) { - // Jump to one iteration before next day - hour += Math.floor((23 - hour) / interval) * interval; - } - while (true) { - hour += interval; - dm = divmod(hour, 24); - div = dm.div; - mod = dm.mod; - if (div) { - hour = mod; - day += div; - fixday = true; - } - if (!plb(byhour) || contains(byhour, hour)) { - break; - } - } - timeset = gettimeset.call(ii, hour, minute, second); - } else if (freq == RRule.MINUTELY) { - if (filtered) { - // Jump to one iteration before next day - minute += Math.floor( - (1439 - (hour * 60 + minute)) / interval) * interval; - } - while(true) { - minute += interval; - dm = divmod(minute, 60); - div = dm.div; - mod = dm.mod; - if (div) { - minute = mod; - hour += div; - dm = divmod(hour, 24); - div = dm.div; - mod = dm.mod; - if (div) { - hour = mod; - day += div; - fixday = true; - filtered = false; - } - } - if ((!plb(byhour) || contains(byhour, hour)) && - (!plb(byminute) || contains(byminute, minute))) { - break; - } - } - timeset = gettimeset.call(ii, hour, minute, second); - } else if (freq == RRule.SECONDLY) { - if (filtered) { - // Jump to one iteration before next day - second += Math.floor( - (86399 - (hour * 3600 + minute * 60 + second)) - / interval) * interval; - } - while (true) { - second += interval; - dm = divmod(second, 60); - div = dm.div; - mod = dm.mod; - if (div) { - second = mod; - minute += div; - dm = divmod(minute, 60); - div = dm.div; - mod = dm.mod; - if (div) { - minute = mod; - hour += div; - dm = divmod(hour, 24); - div = dm.div; - mod = dm.mod; - if (div) { - hour = mod; - day += div; - fixday = true; - } - } - } - if ((!plb(byhour) || contains(byhour, hour)) && - (!plb(byminute) || contains(byminute, minute)) && - (!plb(bysecond) || contains(bysecond, second))) - { - break; - } - } - timeset = gettimeset.call(ii, hour, minute, second); - } - - if (fixday && day > 28) { - var daysinmonth = dateutil.monthRange(year, month - 1)[1]; - if (day > daysinmonth) { - while (day > daysinmonth) { - day -= daysinmonth; - ++month; - if (month == 13) { - month = 1; - ++year; - if (year > dateutil.MAXYEAR) { - this._len = total; - return iterResult.getValue(); - } - } - daysinmonth = dateutil.monthRange(year, month - 1)[1]; - } - ii.rebuild(year, month); - } - } - } - } - -}; - - -RRule.parseString = function(rfcString) { - rfcString = rfcString.replace(/^\s+|\s+$/, ''); - if (!rfcString.length) { - return null; - } - - var i, j, key, value, attr, - attrs = rfcString.split(';'), - options = {}; - - for (i = 0; i < attrs.length; i++) { - attr = attrs[i].split('='); - key = attr[0]; - value = attr[1]; - switch (key) { - case 'FREQ': - options.freq = RRule[value]; - break; - case 'WKST': - options.wkst = RRule[value]; - break; - case 'COUNT': - case 'INTERVAL': - case 'BYSETPOS': - case 'BYMONTH': - case 'BYMONTHDAY': - case 'BYYEARDAY': - case 'BYWEEKNO': - case 'BYHOUR': - case 'BYMINUTE': - case 'BYSECOND': - if (value.indexOf(',') != -1) { - value = value.split(','); - for (j = 0; j < value.length; j++) { - if (/^[+-]?\d+$/.test(value[j])) { - value[j] = Number(value[j]); - } - } - } else if (/^[+-]?\d+$/.test(value)) { - value = Number(value); - } - key = key.toLowerCase(); - options[key] = value; - break; - case 'BYDAY': // => byweekday - var n, wday, day, days = value.split(','); - options.byweekday = []; - for (j = 0; j < days.length; j++) { - day = days[j]; - if (day.length == 2) { // MO, TU, ... - wday = RRule[day]; // wday instanceof Weekday - options.byweekday.push(wday); - } else { // -1MO, +3FR, 1SO, ... - day = day.match(/^([+-]?\d)([A-Z]{2})$/); - n = Number(day[1]); - wday = day[2]; - wday = RRule[wday].weekday; - options.byweekday.push(new Weekday(wday, n)); - } - } - break; - case 'DTSTART': - options.dtstart = dateutil.untilStringToDate(value); - break; - case 'UNTIL': - options.until = dateutil.untilStringToDate(value); - break; - case 'BYEASTER': - options.byeaster = Number(value); - break; - default: - throw new Error("Unknown RRULE property '" + key + "'"); - } - } - return options; -}; - - -RRule.fromString = function(string) { - return new RRule(RRule.parseString(string)); -}; - - -//============================================================================= -// Iterinfo -//============================================================================= - -var Iterinfo = function(rrule) { - this.rrule = rrule; - this.lastyear = null; - this.lastmonth = null; - this.yearlen = null; - this.nextyearlen = null; - this.yearordinal = null; - this.yearweekday = null; - this.mmask = null; - this.mrange = null; - this.mdaymask = null; - this.nmdaymask = null; - this.wdaymask = null; - this.wnomask = null; - this.nwdaymask = null; - this.eastermask = null; -}; - -Iterinfo.prototype.easter = function(y, offset) { - offset = offset || 0; - - var a = y % 19, - b = Math.floor(y / 100), - c = y % 100, - d = Math.floor(b / 4), - e = b % 4, - f = Math.floor((b + 8) / 25), - g = Math.floor((b - f + 1) / 3), - h = Math.floor(19 * a + b - d - g + 15) % 30, - i = Math.floor(c / 4), - k = c % 4, - l = Math.floor(32 + 2 * e + 2 * i - h - k) % 7, - m = Math.floor((a + 11 * h + 22 * l) / 451), - month = Math.floor((h + l - 7 * m + 114) / 31), - day = (h + l - 7 * m + 114) % 31 + 1, - date = Date.UTC(y, month - 1, day + offset), - yearStart = Date.UTC(y, 0, 1); - - return [ Math.ceil((date - yearStart) / (1000 * 60 * 60 * 24)) ]; -} - -Iterinfo.prototype.rebuild = function(year, month) { - - var rr = this.rrule; - - if (year != this.lastyear) { - - this.yearlen = dateutil.isLeapYear(year) ? 366 : 365; - this.nextyearlen = dateutil.isLeapYear(year + 1) ? 366 : 365; - var firstyday = new Date(year, 0, 1); - - this.yearordinal = dateutil.toOrdinal(firstyday); - this.yearweekday = dateutil.getWeekday(firstyday); - - var wday = dateutil.getWeekday(new Date(year, 0, 1)); - - if (this.yearlen == 365) { - this.mmask = [].concat(M365MASK); - this.mdaymask = [].concat(MDAY365MASK); - this.nmdaymask = [].concat(NMDAY365MASK); - this.wdaymask = WDAYMASK.slice(wday); - this.mrange = [].concat(M365RANGE); - } else { - this.mmask = [].concat(M366MASK); - this.mdaymask = [].concat(MDAY366MASK); - this.nmdaymask = [].concat(NMDAY366MASK); - this.wdaymask = WDAYMASK.slice(wday); - this.mrange = [].concat(M366RANGE); - } - - if (!plb(rr.options.byweekno)) { - this.wnomask = null; - } else { - this.wnomask = repeat(0, this.yearlen + 7); - var no1wkst, firstwkst, wyearlen; - no1wkst = firstwkst = pymod( - 7 - this.yearweekday + rr.options.wkst, 7); - if (no1wkst >= 4) { - no1wkst = 0; - // Number of days in the year, plus the days we got - // from last year. - wyearlen = this.yearlen + pymod( - this.yearweekday - rr.options.wkst, 7); - } else { - // Number of days in the year, minus the days we - // left in last year. - wyearlen = this.yearlen - no1wkst; - } - var div = Math.floor(wyearlen / 7); - var mod = pymod(wyearlen, 7); - var numweeks = Math.floor(div + (mod / 4)); - for (var n, i, j = 0; j < rr.options.byweekno.length; j++) { - n = rr.options.byweekno[j]; - if (n < 0) { - n += numweeks + 1; - } if (!(0 < n && n <= numweeks)) { - continue; - } if (n > 1) { - i = no1wkst + (n - 1) * 7; - if (no1wkst != firstwkst) { - i -= 7-firstwkst; - } - } else { - i = no1wkst; - } - for (var k = 0; k < 7; k++) { - this.wnomask[i] = 1; - i++; - if (this.wdaymask[i] == rr.options.wkst) { - break; - } - } - } - - if (contains(rr.options.byweekno, 1)) { - // Check week number 1 of next year as well - // orig-TODO : Check -numweeks for next year. - var i = no1wkst + numweeks * 7; - if (no1wkst != firstwkst) { - i -= 7 - firstwkst; - } - if (i < this.yearlen) { - // If week starts in next year, we - // don't care about it. - for (var j = 0; j < 7; j++) { - this.wnomask[i] = 1; - i += 1; - if (this.wdaymask[i] == rr.options.wkst) { - break; - } - } - } - } - - if (no1wkst) { - // Check last week number of last year as - // well. If no1wkst is 0, either the year - // started on week start, or week number 1 - // got days from last year, so there are no - // days from last year's last week number in - // this year. - var lnumweeks; - if (!contains(rr.options.byweekno, -1)) { - var lyearweekday = dateutil.getWeekday( - new Date(year - 1, 0, 1)); - var lno1wkst = pymod( - 7 - lyearweekday + rr.options.wkst, 7); - var lyearlen = dateutil.isLeapYear(year - 1) ? 366 : 365; - if (lno1wkst >= 4) { - lno1wkst = 0; - lnumweeks = Math.floor( - 52 - + pymod( - lyearlen + pymod( - lyearweekday - rr.options.wkst, 7), 7) - / 4); - } else { - lnumweeks = Math.floor( - 52 + pymod(this.yearlen - no1wkst, 7) / 4); - } - } else { - lnumweeks = -1; - } - if (contains(rr.options.byweekno, lnumweeks)) { - for (var i = 0; i < no1wkst; i++) { - this.wnomask[i] = 1; - } - } - } - } - } - - if (plb(rr.options.bynweekday) - && (month != this.lastmonth || year != this.lastyear)) { - var ranges = []; - if (rr.options.freq == RRule.YEARLY) { - if (plb(rr.options.bymonth)) { - for (j = 0; j < rr.options.bymonth.length; j++) { - month = rr.options.bymonth[j]; - ranges.push(this.mrange.slice(month - 1, month + 1)); - } - } else { - ranges = [[0, this.yearlen]]; - } - } else if (rr.options.freq == RRule.MONTHLY) { - ranges = [this.mrange.slice(month - 1, month + 1)]; - } - if (plb(ranges)) { - // Weekly frequency won't get here, so we may not - // care about cross-year weekly periods. - this.nwdaymask = repeat(0, this.yearlen); - - for (var j = 0; j < ranges.length; j++) { - var rang = ranges[j]; - var first = rang[0], last = rang[1]; - last -= 1; - for (var k = 0; k < rr.options.bynweekday.length; k++) { - var wday = rr.options.bynweekday[k][0], - n = rr.options.bynweekday[k][1]; - if (n < 0) { - i = last + (n + 1) * 7; - i -= pymod(this.wdaymask[i] - wday, 7); - } else { - i = first + (n - 1) * 7; - i += pymod(7 - this.wdaymask[i] + wday, 7); - } - if (first <= i && i <= last) { - this.nwdaymask[i] = 1; - } - } - } - - } - - this.lastyear = year; - this.lastmonth = month; - } - - if (rr.options.byeaster !== null) { - this.eastermask = this.easter(year, rr.options.byeaster); - } -}; - -Iterinfo.prototype.ydayset = function(year, month, day) { - return [range(this.yearlen), 0, this.yearlen]; -}; - -Iterinfo.prototype.mdayset = function(year, month, day) { - var set = repeat(null, this.yearlen); - var start = this.mrange[month-1]; - var end = this.mrange[month]; - for (var i = start; i < end; i++) { - set[i] = i; - } - return [set, start, end]; -}; - -Iterinfo.prototype.wdayset = function(year, month, day) { - - // We need to handle cross-year weeks here. - var set = repeat(null, this.yearlen + 7); - var i = dateutil.toOrdinal( - new Date(year, month - 1, day)) - this.yearordinal; - var start = i; - for (var j = 0; j < 7; j++) { - set[i] = i; - ++i; - if (this.wdaymask[i] == this.rrule.options.wkst) { - break; - } - } - return [set, start, i]; -}; - -Iterinfo.prototype.ddayset = function(year, month, day) { - var set = repeat(null, this.yearlen); - var i = dateutil.toOrdinal( - new Date(year, month - 1, day)) - this.yearordinal; - set[i] = i; - return [set, i, i + 1]; -}; - -Iterinfo.prototype.htimeset = function(hour, minute, second) { - var set = [], rr = this.rrule; - for (var i = 0; i < rr.options.byminute.length; i++) { - minute = rr.options.byminute[i]; - for (var j = 0; j < rr.options.bysecond.length; j++) { - second = rr.options.bysecond[j]; - set.push(new dateutil.Time(hour, minute, second)); - } - } - dateutil.sort(set); - return set; -}; - -Iterinfo.prototype.mtimeset = function(hour, minute, second) { - var set = [], rr = this.rrule; - for (var j = 0; j < rr.options.bysecond.length; j++) { - second = rr.options.bysecond[j]; - set.push(new dateutil.Time(hour, minute, second)); - } - dateutil.sort(set); - return set; -}; - -Iterinfo.prototype.stimeset = function(hour, minute, second) { - return [new dateutil.Time(hour, minute, second)]; -}; - - -//============================================================================= -// Results -//============================================================================= - -/** - * This class helps us to emulate python's generators, sorta. - */ -var IterResult = function(method, args) { - this.init(method, args) -}; - -IterResult.prototype = { - - init: function(method, args) { - this.method = method; - this.args = args; - - this._result = []; - - this.minDate = null; - this.maxDate = null; - - if (method == 'between') { - this.maxDate = args.inc - ? args.before - : new Date(args.before.getTime() - 1); - this.minDate = args.inc - ? args.after - : new Date(args.after.getTime() + 1); - } else if (method == 'before') { - this.maxDate = args.inc ? args.dt : new Date(args.dt.getTime() - 1); - } else if (method == 'after') { - this.minDate = args.inc ? args.dt : new Date(args.dt.getTime() + 1); - } - }, - - /** - * Possibly adds a date into the result. - * - * @param {Date} date - the date isn't necessarly added to the result - * list (if it is too late/too early) - * @return {Boolean} true if it makes sense to continue the iteration; - * false if we're done. - */ - accept: function(date) { - var tooEarly = this.minDate && date < this.minDate, - tooLate = this.maxDate && date > this.maxDate; - - if (this.method == 'between') { - if (tooEarly) - return true; - if (tooLate) - return false; - } else if (this.method == 'before') { - if (tooLate) - return false; - } else if (this.method == 'after') { - if (tooEarly) - return true; - this.add(date); - return false; - } - - return this.add(date); - - }, - - /** - * - * @param {Date} date that is part of the result. - * @return {Boolean} whether we are interested in more values. - */ - add: function(date) { - this._result.push(date); - return true; - }, - - /** - * 'before' and 'after' return only one date, whereas 'all' - * and 'between' an array. - * @return {Date,Array?} - */ - getValue: function() { - switch (this.method) { - case 'all': - case 'between': - return this._result; - case 'before': - case 'after': - return this._result.length - ? this._result[this._result.length - 1] - : null; - } - } - -}; - - -/** - * IterResult subclass that calls a callback function on each add, - * and stops iterating when the callback returns false. - */ -var CallbackIterResult = function(method, args, iterator) { - var allowedMethods = ['all', 'between']; - if (!contains(allowedMethods, method)) { - throw new Error('Invalid method "' + method - + '". Only all and between works with iterator.'); - } - this.add = function(date) { - if (iterator(date, this._result.length)) { - this._result.push(date); - return true; - } - return false; - - }; - - this.init(method, args); - -}; -CallbackIterResult.prototype = IterResult.prototype; - - -//============================================================================= -// Export -//============================================================================= - -if (serverSide) { - module.exports = { - RRule: RRule - // rruleset: rruleset - } -} -if (typeof ender === 'undefined') { - root['RRule'] = RRule; - // root['rruleset'] = rruleset; -} - -if (typeof define === "function" && define.amd) { - /*global define:false */ - define("rrule", [], function () { - return RRule; - }); -} - -}(this)); |