You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1346 lines
43 KiB
1346 lines
43 KiB
// Copyright (c) Microsoft, All rights reserved. See License.txt in the project root for license information. |
|
|
|
;(function (undefined) { |
|
|
|
var objectTypes = { |
|
'function': true, |
|
'object': true |
|
}; |
|
|
|
function checkGlobal(value) { |
|
return (value && value.Object === Object) ? value : null; |
|
} |
|
|
|
var freeExports = (objectTypes[typeof exports] && exports && !exports.nodeType) ? exports : null; |
|
var freeModule = (objectTypes[typeof module] && module && !module.nodeType) ? module : null; |
|
var freeGlobal = checkGlobal(freeExports && freeModule && typeof global === 'object' && global); |
|
var freeSelf = checkGlobal(objectTypes[typeof self] && self); |
|
var freeWindow = checkGlobal(objectTypes[typeof window] && window); |
|
var moduleExports = (freeModule && freeModule.exports === freeExports) ? freeExports : null; |
|
var thisGlobal = checkGlobal(objectTypes[typeof this] && this); |
|
var root = freeGlobal || ((freeWindow !== (thisGlobal && thisGlobal.window)) && freeWindow) || freeSelf || thisGlobal || Function('return this')(); |
|
|
|
var Rx = { |
|
internals: {}, |
|
config: { |
|
Promise: root.Promise |
|
}, |
|
helpers: { } |
|
}; |
|
|
|
// Defaults |
|
var |
|
noop = Rx.helpers.noop = function () { }, |
|
defaultNow = Rx.helpers.defaultNow = (function () { return !!Date.now ? Date.now : function () { return +new Date; }; }()), |
|
defaultError = Rx.helpers.defaultError = function (err) { throw err; }, |
|
isPromise = Rx.helpers.isPromise = function (p) { return !!p && !isFunction(p.subscribe) && isFunction(p.then); }, |
|
defaultSubComparer = Rx.helpers.defaultSubComparer = function (x, y) { return x > y ? 1 : (x < y ? -1 : 0); } |
|
isFunction = Rx.helpers.isFunction = (function () { |
|
var isFn = function (value) { |
|
return typeof value == 'function' || false; |
|
}; |
|
|
|
// fallback for older versions of Chrome and Safari |
|
if (isFn(/x/)) { |
|
isFn = function(value) { |
|
return typeof value == 'function' && toString.call(value) == '[object Function]'; |
|
}; |
|
} |
|
return isFn; |
|
}()); |
|
|
|
var NotImplementedError = Rx.NotImplementedError = function (message) { |
|
this.message = message || 'This operation is not implemented'; |
|
Error.call(this); |
|
}; |
|
NotImplementedError.prototype = Error.prototype; |
|
|
|
var NotSupportedError = Rx.NotSupportedError = function (message) { |
|
this.message = message || 'This operation is not supported'; |
|
Error.call(this); |
|
}; |
|
NotSupportedError.prototype = Error.prototype; |
|
|
|
var notImplemented = Rx.helpers.notImplemented = function () { |
|
throw new NotImplementedError(); |
|
}; |
|
|
|
var notSupported = Rx.helpers.notSupported = function () { |
|
throw new NotSupportedError(); |
|
}; |
|
|
|
var errorObj = {e: {}}; |
|
|
|
function tryCatcherGen(tryCatchTarget) { |
|
return function tryCatcher() { |
|
try { |
|
return tryCatchTarget.apply(this, arguments); |
|
} catch (e) { |
|
errorObj.e = e; |
|
return errorObj; |
|
} |
|
}; |
|
} |
|
|
|
var tryCatch = Rx.internals.tryCatch = function tryCatch(fn) { |
|
if (!isFunction(fn)) { throw new TypeError('fn must be a function'); } |
|
return tryCatcherGen(fn); |
|
}; |
|
|
|
function thrower(e) { |
|
throw e; |
|
} |
|
|
|
Rx.config.longStackSupport = false; |
|
var hasStacks = false, stacks = tryCatch(function () { throw new Error(); })(); |
|
hasStacks = !!stacks.e && !!stacks.e.stack; |
|
|
|
// All code after this point will be filtered from stack traces reported by RxJS |
|
var rStartingLine = captureLine(), rFileName; |
|
|
|
var STACK_JUMP_SEPARATOR = 'From previous event:'; |
|
|
|
function makeStackTraceLong(error, observable) { |
|
// If possible, transform the error stack trace by removing Node and RxJS |
|
// cruft, then concatenating with the stack trace of `observable`. |
|
if (hasStacks && |
|
observable.stack && |
|
typeof error === 'object' && |
|
error !== null && |
|
error.stack && |
|
error.stack.indexOf(STACK_JUMP_SEPARATOR) === -1 |
|
) { |
|
var stacks = []; |
|
for (var o = observable; !!o; o = o.source) { |
|
if (o.stack) { |
|
stacks.unshift(o.stack); |
|
} |
|
} |
|
stacks.unshift(error.stack); |
|
|
|
var concatedStacks = stacks.join('\n' + STACK_JUMP_SEPARATOR + '\n'); |
|
error.stack = filterStackString(concatedStacks); |
|
} |
|
} |
|
|
|
function filterStackString(stackString) { |
|
var lines = stackString.split('\n'), desiredLines = []; |
|
for (var i = 0, len = lines.length; i < len; i++) { |
|
var line = lines[i]; |
|
|
|
if (!isInternalFrame(line) && !isNodeFrame(line) && line) { |
|
desiredLines.push(line); |
|
} |
|
} |
|
return desiredLines.join('\n'); |
|
} |
|
|
|
function isInternalFrame(stackLine) { |
|
var fileNameAndLineNumber = getFileNameAndLineNumber(stackLine); |
|
if (!fileNameAndLineNumber) { |
|
return false; |
|
} |
|
var fileName = fileNameAndLineNumber[0], lineNumber = fileNameAndLineNumber[1]; |
|
|
|
return fileName === rFileName && |
|
lineNumber >= rStartingLine && |
|
lineNumber <= rEndingLine; |
|
} |
|
|
|
function isNodeFrame(stackLine) { |
|
return stackLine.indexOf('(module.js:') !== -1 || |
|
stackLine.indexOf('(node.js:') !== -1; |
|
} |
|
|
|
function captureLine() { |
|
if (!hasStacks) { return; } |
|
|
|
try { |
|
throw new Error(); |
|
} catch (e) { |
|
var lines = e.stack.split('\n'); |
|
var firstLine = lines[0].indexOf('@') > 0 ? lines[1] : lines[2]; |
|
var fileNameAndLineNumber = getFileNameAndLineNumber(firstLine); |
|
if (!fileNameAndLineNumber) { return; } |
|
|
|
rFileName = fileNameAndLineNumber[0]; |
|
return fileNameAndLineNumber[1]; |
|
} |
|
} |
|
|
|
function getFileNameAndLineNumber(stackLine) { |
|
// Named functions: 'at functionName (filename:lineNumber:columnNumber)' |
|
var attempt1 = /at .+ \((.+):(\d+):(?:\d+)\)$/.exec(stackLine); |
|
if (attempt1) { return [attempt1[1], Number(attempt1[2])]; } |
|
|
|
// Anonymous functions: 'at filename:lineNumber:columnNumber' |
|
var attempt2 = /at ([^ ]+):(\d+):(?:\d+)$/.exec(stackLine); |
|
if (attempt2) { return [attempt2[1], Number(attempt2[2])]; } |
|
|
|
// Firefox style: 'function@filename:lineNumber or @filename:lineNumber' |
|
var attempt3 = /.*@(.+):(\d+)$/.exec(stackLine); |
|
if (attempt3) { return [attempt3[1], Number(attempt3[2])]; } |
|
} |
|
|
|
var hasProp = {}.hasOwnProperty, |
|
slice = Array.prototype.slice; |
|
|
|
var inherits = Rx.internals.inherits = function (child, parent) { |
|
function __() { this.constructor = child; } |
|
__.prototype = parent.prototype; |
|
child.prototype = new __(); |
|
}; |
|
|
|
var addProperties = Rx.internals.addProperties = function (obj) { |
|
for(var sources = [], i = 1, len = arguments.length; i < len; i++) { sources.push(arguments[i]); } |
|
for (var idx = 0, ln = sources.length; idx < ln; idx++) { |
|
var source = sources[idx]; |
|
for (var prop in source) { |
|
obj[prop] = source[prop]; |
|
} |
|
} |
|
}; |
|
|
|
// Rx Utils |
|
var addRef = Rx.internals.addRef = function (xs, r) { |
|
return new AnonymousObservable(function (observer) { |
|
return new BinaryDisposable(r.getDisposable(), xs.subscribe(observer)); |
|
}); |
|
}; |
|
|
|
function arrayInitialize(count, factory) { |
|
var a = new Array(count); |
|
for (var i = 0; i < count; i++) { |
|
a[i] = factory(); |
|
} |
|
return a; |
|
} |
|
|
|
/** |
|
* Represents a group of disposable resources that are disposed together. |
|
* @constructor |
|
*/ |
|
var CompositeDisposable = Rx.CompositeDisposable = function () { |
|
var args = [], i, len; |
|
if (Array.isArray(arguments[0])) { |
|
args = arguments[0]; |
|
} else { |
|
len = arguments.length; |
|
args = new Array(len); |
|
for(i = 0; i < len; i++) { args[i] = arguments[i]; } |
|
} |
|
this.disposables = args; |
|
this.isDisposed = false; |
|
this.length = args.length; |
|
}; |
|
|
|
var CompositeDisposablePrototype = CompositeDisposable.prototype; |
|
|
|
/** |
|
* Adds a disposable to the CompositeDisposable or disposes the disposable if the CompositeDisposable is disposed. |
|
* @param {Mixed} item Disposable to add. |
|
*/ |
|
CompositeDisposablePrototype.add = function (item) { |
|
if (this.isDisposed) { |
|
item.dispose(); |
|
} else { |
|
this.disposables.push(item); |
|
this.length++; |
|
} |
|
}; |
|
|
|
/** |
|
* Removes and disposes the first occurrence of a disposable from the CompositeDisposable. |
|
* @param {Mixed} item Disposable to remove. |
|
* @returns {Boolean} true if found; false otherwise. |
|
*/ |
|
CompositeDisposablePrototype.remove = function (item) { |
|
var shouldDispose = false; |
|
if (!this.isDisposed) { |
|
var idx = this.disposables.indexOf(item); |
|
if (idx !== -1) { |
|
shouldDispose = true; |
|
this.disposables.splice(idx, 1); |
|
this.length--; |
|
item.dispose(); |
|
} |
|
} |
|
return shouldDispose; |
|
}; |
|
|
|
/** |
|
* Disposes all disposables in the group and removes them from the group. |
|
*/ |
|
CompositeDisposablePrototype.dispose = function () { |
|
if (!this.isDisposed) { |
|
this.isDisposed = true; |
|
var len = this.disposables.length, currentDisposables = new Array(len); |
|
for(var i = 0; i < len; i++) { currentDisposables[i] = this.disposables[i]; } |
|
this.disposables = []; |
|
this.length = 0; |
|
|
|
for (i = 0; i < len; i++) { |
|
currentDisposables[i].dispose(); |
|
} |
|
} |
|
}; |
|
|
|
/** |
|
* Provides a set of static methods for creating Disposables. |
|
* @param {Function} dispose Action to run during the first call to dispose. The action is guaranteed to be run at most once. |
|
*/ |
|
var Disposable = Rx.Disposable = function (action) { |
|
this.isDisposed = false; |
|
this.action = action || noop; |
|
}; |
|
|
|
/** Performs the task of cleaning up resources. */ |
|
Disposable.prototype.dispose = function () { |
|
if (!this.isDisposed) { |
|
this.action(); |
|
this.isDisposed = true; |
|
} |
|
}; |
|
|
|
/** |
|
* Creates a disposable object that invokes the specified action when disposed. |
|
* @param {Function} dispose Action to run during the first call to dispose. The action is guaranteed to be run at most once. |
|
* @return {Disposable} The disposable object that runs the given action upon disposal. |
|
*/ |
|
var disposableCreate = Disposable.create = function (action) { return new Disposable(action); }; |
|
|
|
/** |
|
* Gets the disposable that does nothing when disposed. |
|
*/ |
|
var disposableEmpty = Disposable.empty = { dispose: noop }; |
|
|
|
/** |
|
* Validates whether the given object is a disposable |
|
* @param {Object} Object to test whether it has a dispose method |
|
* @returns {Boolean} true if a disposable object, else false. |
|
*/ |
|
var isDisposable = Disposable.isDisposable = function (d) { |
|
return d && isFunction(d.dispose); |
|
}; |
|
|
|
var checkDisposed = Disposable.checkDisposed = function (disposable) { |
|
if (disposable.isDisposed) { throw new ObjectDisposedError(); } |
|
}; |
|
|
|
var disposableFixup = Disposable._fixup = function (result) { |
|
return isDisposable(result) ? result : disposableEmpty; |
|
}; |
|
|
|
// Single assignment |
|
var SingleAssignmentDisposable = Rx.SingleAssignmentDisposable = function () { |
|
this.isDisposed = false; |
|
this.current = null; |
|
}; |
|
SingleAssignmentDisposable.prototype.getDisposable = function () { |
|
return this.current; |
|
}; |
|
SingleAssignmentDisposable.prototype.setDisposable = function (value) { |
|
if (this.current) { throw new Error('Disposable has already been assigned'); } |
|
var shouldDispose = this.isDisposed; |
|
!shouldDispose && (this.current = value); |
|
shouldDispose && value && value.dispose(); |
|
}; |
|
SingleAssignmentDisposable.prototype.dispose = function () { |
|
if (!this.isDisposed) { |
|
this.isDisposed = true; |
|
var old = this.current; |
|
this.current = null; |
|
old && old.dispose(); |
|
} |
|
}; |
|
|
|
// Multiple assignment disposable |
|
var SerialDisposable = Rx.SerialDisposable = function () { |
|
this.isDisposed = false; |
|
this.current = null; |
|
}; |
|
SerialDisposable.prototype.getDisposable = function () { |
|
return this.current; |
|
}; |
|
SerialDisposable.prototype.setDisposable = function (value) { |
|
var shouldDispose = this.isDisposed; |
|
if (!shouldDispose) { |
|
var old = this.current; |
|
this.current = value; |
|
} |
|
old && old.dispose(); |
|
shouldDispose && value && value.dispose(); |
|
}; |
|
SerialDisposable.prototype.dispose = function () { |
|
if (!this.isDisposed) { |
|
this.isDisposed = true; |
|
var old = this.current; |
|
this.current = null; |
|
} |
|
old && old.dispose(); |
|
}; |
|
|
|
var BinaryDisposable = Rx.BinaryDisposable = function (first, second) { |
|
this._first = first; |
|
this._second = second; |
|
this.isDisposed = false; |
|
}; |
|
|
|
BinaryDisposable.prototype.dispose = function () { |
|
if (!this.isDisposed) { |
|
this.isDisposed = true; |
|
var old1 = this._first; |
|
this._first = null; |
|
old1 && old1.dispose(); |
|
var old2 = this._second; |
|
this._second = null; |
|
old2 && old2.dispose(); |
|
} |
|
}; |
|
|
|
var NAryDisposable = Rx.NAryDisposable = function (disposables) { |
|
this._disposables = disposables; |
|
this.isDisposed = false; |
|
}; |
|
|
|
NAryDisposable.prototype.dispose = function () { |
|
if (!this.isDisposed) { |
|
this.isDisposed = true; |
|
for (var i = 0, len = this._disposables.length; i < len; i++) { |
|
this._disposables[i].dispose(); |
|
} |
|
this._disposables.length = 0; |
|
} |
|
}; |
|
|
|
var ScheduledItem = Rx.internals.ScheduledItem = function (scheduler, state, action, dueTime, comparer) { |
|
this.scheduler = scheduler; |
|
this.state = state; |
|
this.action = action; |
|
this.dueTime = dueTime; |
|
this.comparer = comparer || defaultSubComparer; |
|
this.disposable = new SingleAssignmentDisposable(); |
|
}; |
|
|
|
ScheduledItem.prototype.invoke = function () { |
|
this.disposable.setDisposable(this.invokeCore()); |
|
}; |
|
|
|
ScheduledItem.prototype.compareTo = function (other) { |
|
return this.comparer(this.dueTime, other.dueTime); |
|
}; |
|
|
|
ScheduledItem.prototype.isCancelled = function () { |
|
return this.disposable.isDisposed; |
|
}; |
|
|
|
ScheduledItem.prototype.invokeCore = function () { |
|
return disposableFixup(this.action(this.scheduler, this.state)); |
|
}; |
|
|
|
/** Provides a set of static properties to access commonly used schedulers. */ |
|
var Scheduler = Rx.Scheduler = (function () { |
|
|
|
function Scheduler() { } |
|
|
|
/** Determines whether the given object is a scheduler */ |
|
Scheduler.isScheduler = function (s) { |
|
return s instanceof Scheduler; |
|
}; |
|
|
|
var schedulerProto = Scheduler.prototype; |
|
|
|
/** |
|
* Schedules an action to be executed. |
|
* @param state State passed to the action to be executed. |
|
* @param {Function} action Action to be executed. |
|
* @returns {Disposable} The disposable object used to cancel the scheduled action (best effort). |
|
*/ |
|
schedulerProto.schedule = function (state, action) { |
|
throw new NotImplementedError(); |
|
}; |
|
|
|
/** |
|
* Schedules an action to be executed after dueTime. |
|
* @param state State passed to the action to be executed. |
|
* @param {Function} action Action to be executed. |
|
* @param {Number} dueTime Relative time after which to execute the action. |
|
* @returns {Disposable} The disposable object used to cancel the scheduled action (best effort). |
|
*/ |
|
schedulerProto.scheduleFuture = function (state, dueTime, action) { |
|
var dt = dueTime; |
|
dt instanceof Date && (dt = dt - this.now()); |
|
dt = Scheduler.normalize(dt); |
|
|
|
if (dt === 0) { return this.schedule(state, action); } |
|
|
|
return this._scheduleFuture(state, dt, action); |
|
}; |
|
|
|
schedulerProto._scheduleFuture = function (state, dueTime, action) { |
|
throw new NotImplementedError(); |
|
}; |
|
|
|
/** Gets the current time according to the local machine's system clock. */ |
|
Scheduler.now = defaultNow; |
|
|
|
/** Gets the current time according to the local machine's system clock. */ |
|
Scheduler.prototype.now = defaultNow; |
|
|
|
/** |
|
* Normalizes the specified TimeSpan value to a positive value. |
|
* @param {Number} timeSpan The time span value to normalize. |
|
* @returns {Number} The specified TimeSpan value if it is zero or positive; otherwise, 0 |
|
*/ |
|
Scheduler.normalize = function (timeSpan) { |
|
timeSpan < 0 && (timeSpan = 0); |
|
return timeSpan; |
|
}; |
|
|
|
return Scheduler; |
|
}()); |
|
|
|
var normalizeTime = Scheduler.normalize, isScheduler = Scheduler.isScheduler; |
|
|
|
(function (schedulerProto) { |
|
|
|
function invokeRecImmediate(scheduler, pair) { |
|
var state = pair[0], action = pair[1], group = new CompositeDisposable(); |
|
action(state, innerAction); |
|
return group; |
|
|
|
function innerAction(state2) { |
|
var isAdded = false, isDone = false; |
|
|
|
var d = scheduler.schedule(state2, scheduleWork); |
|
if (!isDone) { |
|
group.add(d); |
|
isAdded = true; |
|
} |
|
|
|
function scheduleWork(_, state3) { |
|
if (isAdded) { |
|
group.remove(d); |
|
} else { |
|
isDone = true; |
|
} |
|
action(state3, innerAction); |
|
return disposableEmpty; |
|
} |
|
} |
|
} |
|
|
|
function invokeRecDate(scheduler, pair) { |
|
var state = pair[0], action = pair[1], group = new CompositeDisposable(); |
|
action(state, innerAction); |
|
return group; |
|
|
|
function innerAction(state2, dueTime1) { |
|
var isAdded = false, isDone = false; |
|
|
|
var d = scheduler.scheduleFuture(state2, dueTime1, scheduleWork); |
|
if (!isDone) { |
|
group.add(d); |
|
isAdded = true; |
|
} |
|
|
|
function scheduleWork(_, state3) { |
|
if (isAdded) { |
|
group.remove(d); |
|
} else { |
|
isDone = true; |
|
} |
|
action(state3, innerAction); |
|
return disposableEmpty; |
|
} |
|
} |
|
} |
|
|
|
/** |
|
* Schedules an action to be executed recursively. |
|
* @param {Mixed} state State passed to the action to be executed. |
|
* @param {Function} action Action to execute recursively. The last parameter passed to the action is used to trigger recursive scheduling of the action, passing in recursive invocation state. |
|
* @returns {Disposable} The disposable object used to cancel the scheduled action (best effort). |
|
*/ |
|
schedulerProto.scheduleRecursive = function (state, action) { |
|
return this.schedule([state, action], invokeRecImmediate); |
|
}; |
|
|
|
/** |
|
* Schedules an action to be executed recursively after a specified relative or absolute due time. |
|
* @param {Mixed} state State passed to the action to be executed. |
|
* @param {Function} action Action to execute recursively. The last parameter passed to the action is used to trigger recursive scheduling of the action, passing in the recursive due time and invocation state. |
|
* @param {Number | Date} dueTime Relative or absolute time after which to execute the action for the first time. |
|
* @returns {Disposable} The disposable object used to cancel the scheduled action (best effort). |
|
*/ |
|
schedulerProto.scheduleRecursiveFuture = function (state, dueTime, action) { |
|
return this.scheduleFuture([state, action], dueTime, invokeRecDate); |
|
}; |
|
|
|
}(Scheduler.prototype)); |
|
|
|
(function (schedulerProto) { |
|
|
|
/** |
|
* Schedules a periodic piece of work by dynamically discovering the scheduler's capabilities. The periodic task will be scheduled using window.setInterval for the base implementation. |
|
* @param {Mixed} state Initial state passed to the action upon the first iteration. |
|
* @param {Number} period Period for running the work periodically. |
|
* @param {Function} action Action to be executed, potentially updating the state. |
|
* @returns {Disposable} The disposable object used to cancel the scheduled recurring action (best effort). |
|
*/ |
|
schedulerProto.schedulePeriodic = function(state, period, action) { |
|
if (typeof root.setInterval === 'undefined') { throw new NotSupportedError(); } |
|
period = normalizeTime(period); |
|
var s = state, id = root.setInterval(function () { s = action(s); }, period); |
|
return disposableCreate(function () { root.clearInterval(id); }); |
|
}; |
|
|
|
}(Scheduler.prototype)); |
|
|
|
var SchedulePeriodicRecursive = Rx.internals.SchedulePeriodicRecursive = (function () { |
|
function createTick(self) { |
|
return function tick(command, recurse) { |
|
recurse(0, self._period); |
|
var state = tryCatch(self._action)(self._state); |
|
if (state === errorObj) { |
|
self._cancel.dispose(); |
|
thrower(state.e); |
|
} |
|
self._state = state; |
|
}; |
|
} |
|
|
|
function SchedulePeriodicRecursive(scheduler, state, period, action) { |
|
this._scheduler = scheduler; |
|
this._state = state; |
|
this._period = period; |
|
this._action = action; |
|
} |
|
|
|
SchedulePeriodicRecursive.prototype.start = function () { |
|
var d = new SingleAssignmentDisposable(); |
|
this._cancel = d; |
|
d.setDisposable(this._scheduler.scheduleRecursiveFuture(0, this._period, createTick(this))); |
|
|
|
return d; |
|
}; |
|
|
|
return SchedulePeriodicRecursive; |
|
}()); |
|
|
|
/** Gets a scheduler that schedules work immediately on the current thread. */ |
|
var ImmediateScheduler = (function (__super__) { |
|
inherits(ImmediateScheduler, __super__); |
|
function ImmediateScheduler() { |
|
__super__.call(this); |
|
} |
|
|
|
ImmediateScheduler.prototype.schedule = function (state, action) { |
|
return disposableFixup(action(this, state)); |
|
}; |
|
|
|
return ImmediateScheduler; |
|
}(Scheduler)); |
|
|
|
var immediateScheduler = Scheduler.immediate = new ImmediateScheduler(); |
|
|
|
/** |
|
* Gets a scheduler that schedules work as soon as possible on the current thread. |
|
*/ |
|
var CurrentThreadScheduler = (function (__super__) { |
|
var queue; |
|
|
|
function runTrampoline () { |
|
while (queue.length > 0) { |
|
var item = queue.dequeue(); |
|
!item.isCancelled() && item.invoke(); |
|
} |
|
} |
|
|
|
inherits(CurrentThreadScheduler, __super__); |
|
function CurrentThreadScheduler() { |
|
__super__.call(this); |
|
} |
|
|
|
CurrentThreadScheduler.prototype.schedule = function (state, action) { |
|
var si = new ScheduledItem(this, state, action, this.now()); |
|
|
|
if (!queue) { |
|
queue = new PriorityQueue(4); |
|
queue.enqueue(si); |
|
|
|
var result = tryCatch(runTrampoline)(); |
|
queue = null; |
|
if (result === errorObj) { thrower(result.e); } |
|
} else { |
|
queue.enqueue(si); |
|
} |
|
return si.disposable; |
|
}; |
|
|
|
CurrentThreadScheduler.prototype.scheduleRequired = function () { return !queue; }; |
|
|
|
return CurrentThreadScheduler; |
|
}(Scheduler)); |
|
|
|
var currentThreadScheduler = Scheduler.currentThread = new CurrentThreadScheduler(); |
|
|
|
var scheduleMethod, clearMethod; |
|
|
|
var localTimer = (function () { |
|
var localSetTimeout, localClearTimeout = noop; |
|
if (!!root.setTimeout) { |
|
localSetTimeout = root.setTimeout; |
|
localClearTimeout = root.clearTimeout; |
|
} else if (!!root.WScript) { |
|
localSetTimeout = function (fn, time) { |
|
root.WScript.Sleep(time); |
|
fn(); |
|
}; |
|
} else { |
|
throw new NotSupportedError(); |
|
} |
|
|
|
return { |
|
setTimeout: localSetTimeout, |
|
clearTimeout: localClearTimeout |
|
}; |
|
}()); |
|
var localSetTimeout = localTimer.setTimeout, |
|
localClearTimeout = localTimer.clearTimeout; |
|
|
|
(function () { |
|
|
|
var nextHandle = 1, tasksByHandle = {}, currentlyRunning = false; |
|
|
|
clearMethod = function (handle) { |
|
delete tasksByHandle[handle]; |
|
}; |
|
|
|
function runTask(handle) { |
|
if (currentlyRunning) { |
|
localSetTimeout(function () { runTask(handle); }, 0); |
|
} else { |
|
var task = tasksByHandle[handle]; |
|
if (task) { |
|
currentlyRunning = true; |
|
var result = tryCatch(task)(); |
|
clearMethod(handle); |
|
currentlyRunning = false; |
|
if (result === errorObj) { thrower(result.e); } |
|
} |
|
} |
|
} |
|
|
|
var reNative = new RegExp('^' + |
|
String(toString) |
|
.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') |
|
.replace(/toString| for [^\]]+/g, '.*?') + '$' |
|
); |
|
|
|
var setImmediate = typeof (setImmediate = freeGlobal && moduleExports && freeGlobal.setImmediate) == 'function' && |
|
!reNative.test(setImmediate) && setImmediate; |
|
|
|
function postMessageSupported () { |
|
// Ensure not in a worker |
|
if (!root.postMessage || root.importScripts) { return false; } |
|
var isAsync = false, oldHandler = root.onmessage; |
|
// Test for async |
|
root.onmessage = function () { isAsync = true; }; |
|
root.postMessage('', '*'); |
|
root.onmessage = oldHandler; |
|
|
|
return isAsync; |
|
} |
|
|
|
// Use in order, setImmediate, nextTick, postMessage, MessageChannel, script readystatechanged, setTimeout |
|
if (isFunction(setImmediate)) { |
|
scheduleMethod = function (action) { |
|
var id = nextHandle++; |
|
tasksByHandle[id] = action; |
|
setImmediate(function () { runTask(id); }); |
|
|
|
return id; |
|
}; |
|
} else if (typeof process !== 'undefined' && {}.toString.call(process) === '[object process]') { |
|
scheduleMethod = function (action) { |
|
var id = nextHandle++; |
|
tasksByHandle[id] = action; |
|
process.nextTick(function () { runTask(id); }); |
|
|
|
return id; |
|
}; |
|
} else if (postMessageSupported()) { |
|
var MSG_PREFIX = 'ms.rx.schedule' + Math.random(); |
|
|
|
var onGlobalPostMessage = function (event) { |
|
// Only if we're a match to avoid any other global events |
|
if (typeof event.data === 'string' && event.data.substring(0, MSG_PREFIX.length) === MSG_PREFIX) { |
|
runTask(event.data.substring(MSG_PREFIX.length)); |
|
} |
|
}; |
|
|
|
root.addEventListener('message', onGlobalPostMessage, false); |
|
|
|
scheduleMethod = function (action) { |
|
var id = nextHandle++; |
|
tasksByHandle[id] = action; |
|
root.postMessage(MSG_PREFIX + id, '*'); |
|
return id; |
|
}; |
|
} else if (!!root.MessageChannel) { |
|
var channel = new root.MessageChannel(); |
|
|
|
channel.port1.onmessage = function (e) { runTask(e.data); }; |
|
|
|
scheduleMethod = function (action) { |
|
var id = nextHandle++; |
|
tasksByHandle[id] = action; |
|
channel.port2.postMessage(id); |
|
return id; |
|
}; |
|
} else if ('document' in root && 'onreadystatechange' in root.document.createElement('script')) { |
|
|
|
scheduleMethod = function (action) { |
|
var scriptElement = root.document.createElement('script'); |
|
var id = nextHandle++; |
|
tasksByHandle[id] = action; |
|
|
|
scriptElement.onreadystatechange = function () { |
|
runTask(id); |
|
scriptElement.onreadystatechange = null; |
|
scriptElement.parentNode.removeChild(scriptElement); |
|
scriptElement = null; |
|
}; |
|
root.document.documentElement.appendChild(scriptElement); |
|
return id; |
|
}; |
|
|
|
} else { |
|
scheduleMethod = function (action) { |
|
var id = nextHandle++; |
|
tasksByHandle[id] = action; |
|
localSetTimeout(function () { |
|
runTask(id); |
|
}, 0); |
|
|
|
return id; |
|
}; |
|
} |
|
}()); |
|
|
|
/** |
|
* Gets a scheduler that schedules work via a timed callback based upon platform. |
|
*/ |
|
var DefaultScheduler = (function (__super__) { |
|
inherits(DefaultScheduler, __super__); |
|
function DefaultScheduler() { |
|
__super__.call(this); |
|
} |
|
|
|
function scheduleAction(disposable, action, scheduler, state) { |
|
return function schedule() { |
|
disposable.setDisposable(Disposable._fixup(action(scheduler, state))); |
|
}; |
|
} |
|
|
|
function ClearDisposable(id) { |
|
this._id = id; |
|
this.isDisposed = false; |
|
} |
|
|
|
ClearDisposable.prototype.dispose = function () { |
|
if (!this.isDisposed) { |
|
this.isDisposed = true; |
|
clearMethod(this._id); |
|
} |
|
}; |
|
|
|
function LocalClearDisposable(id) { |
|
this._id = id; |
|
this.isDisposed = false; |
|
} |
|
|
|
LocalClearDisposable.prototype.dispose = function () { |
|
if (!this.isDisposed) { |
|
this.isDisposed = true; |
|
localClearTimeout(this._id); |
|
} |
|
}; |
|
|
|
DefaultScheduler.prototype.schedule = function (state, action) { |
|
var disposable = new SingleAssignmentDisposable(), |
|
id = scheduleMethod(scheduleAction(disposable, action, this, state)); |
|
return new BinaryDisposable(disposable, new ClearDisposable(id)); |
|
}; |
|
|
|
DefaultScheduler.prototype._scheduleFuture = function (state, dueTime, action) { |
|
if (dueTime === 0) { return this.schedule(state, action); } |
|
var disposable = new SingleAssignmentDisposable(), |
|
id = localSetTimeout(scheduleAction(disposable, action, this, state), dueTime); |
|
return new BinaryDisposable(disposable, new LocalClearDisposable(id)); |
|
}; |
|
|
|
function scheduleLongRunning(state, action, disposable) { |
|
return function () { action(state, disposable); }; |
|
} |
|
|
|
DefaultScheduler.prototype.scheduleLongRunning = function (state, action) { |
|
var disposable = disposableCreate(noop); |
|
scheduleMethod(scheduleLongRunning(state, action, disposable)); |
|
return disposable; |
|
}; |
|
|
|
return DefaultScheduler; |
|
}(Scheduler)); |
|
|
|
var defaultScheduler = Scheduler['default'] = Scheduler.async = new DefaultScheduler(); |
|
|
|
function IndexedItem(id, value) { |
|
this.id = id; |
|
this.value = value; |
|
} |
|
|
|
IndexedItem.prototype.compareTo = function (other) { |
|
var c = this.value.compareTo(other.value); |
|
c === 0 && (c = this.id - other.id); |
|
return c; |
|
}; |
|
|
|
var PriorityQueue = Rx.internals.PriorityQueue = function (capacity) { |
|
this.items = new Array(capacity); |
|
this.length = 0; |
|
}; |
|
|
|
var priorityProto = PriorityQueue.prototype; |
|
priorityProto.isHigherPriority = function (left, right) { |
|
return this.items[left].compareTo(this.items[right]) < 0; |
|
}; |
|
|
|
priorityProto.percolate = function (index) { |
|
if (index >= this.length || index < 0) { return; } |
|
var parent = index - 1 >> 1; |
|
if (parent < 0 || parent === index) { return; } |
|
if (this.isHigherPriority(index, parent)) { |
|
var temp = this.items[index]; |
|
this.items[index] = this.items[parent]; |
|
this.items[parent] = temp; |
|
this.percolate(parent); |
|
} |
|
}; |
|
|
|
priorityProto.heapify = function (index) { |
|
+index || (index = 0); |
|
if (index >= this.length || index < 0) { return; } |
|
var left = 2 * index + 1, |
|
right = 2 * index + 2, |
|
first = index; |
|
if (left < this.length && this.isHigherPriority(left, first)) { |
|
first = left; |
|
} |
|
if (right < this.length && this.isHigherPriority(right, first)) { |
|
first = right; |
|
} |
|
if (first !== index) { |
|
var temp = this.items[index]; |
|
this.items[index] = this.items[first]; |
|
this.items[first] = temp; |
|
this.heapify(first); |
|
} |
|
}; |
|
|
|
priorityProto.peek = function () { return this.items[0].value; }; |
|
|
|
priorityProto.removeAt = function (index) { |
|
this.items[index] = this.items[--this.length]; |
|
this.items[this.length] = undefined; |
|
this.heapify(); |
|
}; |
|
|
|
priorityProto.dequeue = function () { |
|
var result = this.peek(); |
|
this.removeAt(0); |
|
return result; |
|
}; |
|
|
|
priorityProto.enqueue = function (item) { |
|
var index = this.length++; |
|
this.items[index] = new IndexedItem(PriorityQueue.count++, item); |
|
this.percolate(index); |
|
}; |
|
|
|
priorityProto.remove = function (item) { |
|
for (var i = 0; i < this.length; i++) { |
|
if (this.items[i].value === item) { |
|
this.removeAt(i); |
|
return true; |
|
} |
|
} |
|
return false; |
|
}; |
|
PriorityQueue.count = 0; |
|
|
|
/** |
|
* Supports push-style iteration over an observable sequence. |
|
*/ |
|
var Observer = Rx.Observer = function () { }; |
|
|
|
/** |
|
* Creates an observer from the specified OnNext, along with optional OnError, and OnCompleted actions. |
|
* @param {Function} [onNext] Observer's OnNext action implementation. |
|
* @param {Function} [onError] Observer's OnError action implementation. |
|
* @param {Function} [onCompleted] Observer's OnCompleted action implementation. |
|
* @returns {Observer} The observer object implemented using the given actions. |
|
*/ |
|
var observerCreate = Observer.create = function (onNext, onError, onCompleted) { |
|
onNext || (onNext = noop); |
|
onError || (onError = defaultError); |
|
onCompleted || (onCompleted = noop); |
|
return new AnonymousObserver(onNext, onError, onCompleted); |
|
}; |
|
|
|
/** |
|
* Abstract base class for implementations of the Observer class. |
|
* This base class enforces the grammar of observers where OnError and OnCompleted are terminal messages. |
|
*/ |
|
var AbstractObserver = Rx.internals.AbstractObserver = (function (__super__) { |
|
inherits(AbstractObserver, __super__); |
|
|
|
/** |
|
* Creates a new observer in a non-stopped state. |
|
*/ |
|
function AbstractObserver() { |
|
this.isStopped = false; |
|
} |
|
|
|
// Must be implemented by other observers |
|
AbstractObserver.prototype.next = notImplemented; |
|
AbstractObserver.prototype.error = notImplemented; |
|
AbstractObserver.prototype.completed = notImplemented; |
|
|
|
/** |
|
* Notifies the observer of a new element in the sequence. |
|
* @param {Any} value Next element in the sequence. |
|
*/ |
|
AbstractObserver.prototype.onNext = function (value) { |
|
!this.isStopped && this.next(value); |
|
}; |
|
|
|
/** |
|
* Notifies the observer that an exception has occurred. |
|
* @param {Any} error The error that has occurred. |
|
*/ |
|
AbstractObserver.prototype.onError = function (error) { |
|
if (!this.isStopped) { |
|
this.isStopped = true; |
|
this.error(error); |
|
} |
|
}; |
|
|
|
/** |
|
* Notifies the observer of the end of the sequence. |
|
*/ |
|
AbstractObserver.prototype.onCompleted = function () { |
|
if (!this.isStopped) { |
|
this.isStopped = true; |
|
this.completed(); |
|
} |
|
}; |
|
|
|
/** |
|
* Disposes the observer, causing it to transition to the stopped state. |
|
*/ |
|
AbstractObserver.prototype.dispose = function () { this.isStopped = true; }; |
|
|
|
AbstractObserver.prototype.fail = function (e) { |
|
if (!this.isStopped) { |
|
this.isStopped = true; |
|
this.error(e); |
|
return true; |
|
} |
|
|
|
return false; |
|
}; |
|
|
|
return AbstractObserver; |
|
}(Observer)); |
|
|
|
/** |
|
* Class to create an Observer instance from delegate-based implementations of the on* methods. |
|
*/ |
|
var AnonymousObserver = Rx.AnonymousObserver = (function (__super__) { |
|
inherits(AnonymousObserver, __super__); |
|
|
|
/** |
|
* Creates an observer from the specified OnNext, OnError, and OnCompleted actions. |
|
* @param {Any} onNext Observer's OnNext action implementation. |
|
* @param {Any} onError Observer's OnError action implementation. |
|
* @param {Any} onCompleted Observer's OnCompleted action implementation. |
|
*/ |
|
function AnonymousObserver(onNext, onError, onCompleted) { |
|
__super__.call(this); |
|
this._onNext = onNext; |
|
this._onError = onError; |
|
this._onCompleted = onCompleted; |
|
} |
|
|
|
/** |
|
* Calls the onNext action. |
|
* @param {Any} value Next element in the sequence. |
|
*/ |
|
AnonymousObserver.prototype.next = function (value) { |
|
this._onNext(value); |
|
}; |
|
|
|
/** |
|
* Calls the onError action. |
|
* @param {Any} error The error that has occurred. |
|
*/ |
|
AnonymousObserver.prototype.error = function (error) { |
|
this._onError(error); |
|
}; |
|
|
|
/** |
|
* Calls the onCompleted action. |
|
*/ |
|
AnonymousObserver.prototype.completed = function () { |
|
this._onCompleted(); |
|
}; |
|
|
|
return AnonymousObserver; |
|
}(AbstractObserver)); |
|
|
|
var observableProto; |
|
|
|
/** |
|
* Represents a push-style collection. |
|
*/ |
|
var Observable = Rx.Observable = (function () { |
|
|
|
function makeSubscribe(self, subscribe) { |
|
return function (o) { |
|
var oldOnError = o.onError; |
|
o.onError = function (e) { |
|
makeStackTraceLong(e, self); |
|
oldOnError.call(o, e); |
|
}; |
|
|
|
return subscribe.call(self, o); |
|
}; |
|
} |
|
|
|
function Observable() { |
|
if (Rx.config.longStackSupport && hasStacks) { |
|
var oldSubscribe = this._subscribe; |
|
var e = tryCatch(thrower)(new Error()).e; |
|
this.stack = e.stack.substring(e.stack.indexOf('\n') + 1); |
|
this._subscribe = makeSubscribe(this, oldSubscribe); |
|
} |
|
} |
|
|
|
observableProto = Observable.prototype; |
|
|
|
/** |
|
* Determines whether the given object is an Observable |
|
* @param {Any} An object to determine whether it is an Observable |
|
* @returns {Boolean} true if an Observable, else false. |
|
*/ |
|
Observable.isObservable = function (o) { |
|
return o && isFunction(o.subscribe); |
|
}; |
|
|
|
/** |
|
* Subscribes an o to the observable sequence. |
|
* @param {Mixed} [oOrOnNext] The object that is to receive notifications or an action to invoke for each element in the observable sequence. |
|
* @param {Function} [onError] Action to invoke upon exceptional termination of the observable sequence. |
|
* @param {Function} [onCompleted] Action to invoke upon graceful termination of the observable sequence. |
|
* @returns {Diposable} A disposable handling the subscriptions and unsubscriptions. |
|
*/ |
|
observableProto.subscribe = observableProto.forEach = function (oOrOnNext, onError, onCompleted) { |
|
return this._subscribe(typeof oOrOnNext === 'object' ? |
|
oOrOnNext : |
|
observerCreate(oOrOnNext, onError, onCompleted)); |
|
}; |
|
|
|
/** |
|
* Subscribes to the next value in the sequence with an optional "this" argument. |
|
* @param {Function} onNext The function to invoke on each element in the observable sequence. |
|
* @param {Any} [thisArg] Object to use as this when executing callback. |
|
* @returns {Disposable} A disposable handling the subscriptions and unsubscriptions. |
|
*/ |
|
observableProto.subscribeOnNext = function (onNext, thisArg) { |
|
return this._subscribe(observerCreate(typeof thisArg !== 'undefined' ? function(x) { onNext.call(thisArg, x); } : onNext)); |
|
}; |
|
|
|
/** |
|
* Subscribes to an exceptional condition in the sequence with an optional "this" argument. |
|
* @param {Function} onError The function to invoke upon exceptional termination of the observable sequence. |
|
* @param {Any} [thisArg] Object to use as this when executing callback. |
|
* @returns {Disposable} A disposable handling the subscriptions and unsubscriptions. |
|
*/ |
|
observableProto.subscribeOnError = function (onError, thisArg) { |
|
return this._subscribe(observerCreate(null, typeof thisArg !== 'undefined' ? function(e) { onError.call(thisArg, e); } : onError)); |
|
}; |
|
|
|
/** |
|
* Subscribes to the next value in the sequence with an optional "this" argument. |
|
* @param {Function} onCompleted The function to invoke upon graceful termination of the observable sequence. |
|
* @param {Any} [thisArg] Object to use as this when executing callback. |
|
* @returns {Disposable} A disposable handling the subscriptions and unsubscriptions. |
|
*/ |
|
observableProto.subscribeOnCompleted = function (onCompleted, thisArg) { |
|
return this._subscribe(observerCreate(null, null, typeof thisArg !== 'undefined' ? function() { onCompleted.call(thisArg); } : onCompleted)); |
|
}; |
|
|
|
return Observable; |
|
})(); |
|
|
|
var AnonymousObservable = Rx.AnonymousObservable = (function (__super__) { |
|
inherits(AnonymousObservable, __super__); |
|
|
|
// Fix subscriber to check for undefined or function returned to decorate as Disposable |
|
function fixSubscriber(subscriber) { |
|
return subscriber && isFunction(subscriber.dispose) ? subscriber : |
|
isFunction(subscriber) ? disposableCreate(subscriber) : disposableEmpty; |
|
} |
|
|
|
function setDisposable(s, state) { |
|
var ado = state[0], self = state[1]; |
|
var sub = tryCatch(self.__subscribe).call(self, ado); |
|
if (sub === errorObj && !ado.fail(errorObj.e)) { thrower(errorObj.e); } |
|
ado.setDisposable(fixSubscriber(sub)); |
|
} |
|
|
|
function AnonymousObservable(subscribe, parent) { |
|
this.source = parent; |
|
this.__subscribe = subscribe; |
|
__super__.call(this); |
|
} |
|
|
|
AnonymousObservable.prototype._subscribe = function (o) { |
|
var ado = new AutoDetachObserver(o), state = [ado, this]; |
|
|
|
if (currentThreadScheduler.scheduleRequired()) { |
|
currentThreadScheduler.schedule(state, setDisposable); |
|
} else { |
|
setDisposable(null, state); |
|
} |
|
return ado; |
|
}; |
|
|
|
return AnonymousObservable; |
|
|
|
}(Observable)); |
|
|
|
var ObservableBase = Rx.ObservableBase = (function (__super__) { |
|
inherits(ObservableBase, __super__); |
|
|
|
function fixSubscriber(subscriber) { |
|
return subscriber && isFunction(subscriber.dispose) ? subscriber : |
|
isFunction(subscriber) ? disposableCreate(subscriber) : disposableEmpty; |
|
} |
|
|
|
function setDisposable(s, state) { |
|
var ado = state[0], self = state[1]; |
|
var sub = tryCatch(self.subscribeCore).call(self, ado); |
|
if (sub === errorObj && !ado.fail(errorObj.e)) { thrower(errorObj.e); } |
|
ado.setDisposable(fixSubscriber(sub)); |
|
} |
|
|
|
function ObservableBase() { |
|
__super__.call(this); |
|
} |
|
|
|
ObservableBase.prototype._subscribe = function (o) { |
|
var ado = new AutoDetachObserver(o), state = [ado, this]; |
|
|
|
if (currentThreadScheduler.scheduleRequired()) { |
|
currentThreadScheduler.schedule(state, setDisposable); |
|
} else { |
|
setDisposable(null, state); |
|
} |
|
return ado; |
|
}; |
|
|
|
ObservableBase.prototype.subscribeCore = notImplemented; |
|
|
|
return ObservableBase; |
|
}(Observable)); |
|
|
|
var AutoDetachObserver = (function (__super__) { |
|
inherits(AutoDetachObserver, __super__); |
|
|
|
function AutoDetachObserver(observer) { |
|
__super__.call(this); |
|
this.observer = observer; |
|
this.m = new SingleAssignmentDisposable(); |
|
} |
|
|
|
var AutoDetachObserverPrototype = AutoDetachObserver.prototype; |
|
|
|
AutoDetachObserverPrototype.next = function (value) { |
|
var result = tryCatch(this.observer.onNext).call(this.observer, value); |
|
if (result === errorObj) { |
|
this.dispose(); |
|
thrower(result.e); |
|
} |
|
}; |
|
|
|
AutoDetachObserverPrototype.error = function (err) { |
|
var result = tryCatch(this.observer.onError).call(this.observer, err); |
|
this.dispose(); |
|
result === errorObj && thrower(result.e); |
|
}; |
|
|
|
AutoDetachObserverPrototype.completed = function () { |
|
var result = tryCatch(this.observer.onCompleted).call(this.observer); |
|
this.dispose(); |
|
result === errorObj && thrower(result.e); |
|
}; |
|
|
|
AutoDetachObserverPrototype.setDisposable = function (value) { this.m.setDisposable(value); }; |
|
AutoDetachObserverPrototype.getDisposable = function () { return this.m.getDisposable(); }; |
|
|
|
AutoDetachObserverPrototype.dispose = function () { |
|
__super__.prototype.dispose.call(this); |
|
this.m.dispose(); |
|
}; |
|
|
|
return AutoDetachObserver; |
|
}(AbstractObserver)); |
|
|
|
/** |
|
* Creates an observable sequence from a specified subscribe method implementation. |
|
* @example |
|
* var res = Rx.Observable.create(function (observer) { return function () { } ); |
|
* var res = Rx.Observable.create(function (observer) { return Rx.Disposable.empty; } ); |
|
* var res = Rx.Observable.create(function (observer) { } ); |
|
* @param {Function} subscribe Implementation of the resulting observable sequence's subscribe method, returning a function that will be wrapped in a Disposable. |
|
* @returns {Observable} The observable sequence with the specified implementation for the Subscribe method. |
|
*/ |
|
Observable.create = function (subscribe, parent) { |
|
return new AnonymousObservable(subscribe, parent); |
|
}; |
|
|
|
if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) { |
|
root.Rx = Rx; |
|
|
|
define(function() { |
|
return Rx; |
|
}); |
|
} else if (freeExports && freeModule) { |
|
// in Node.js or RingoJS |
|
if (moduleExports) { |
|
(freeModule.exports = Rx).Rx = Rx; |
|
} else { |
|
freeExports.Rx = Rx; |
|
} |
|
} else { |
|
// in a browser or Rhino |
|
root.Rx = Rx; |
|
} |
|
|
|
// All code before this point will be filtered from stack traces. |
|
var rEndingLine = captureLine(); |
|
|
|
}.call(this));
|
|
|