UNPKG

dvbcss-clocks

Version:

Javascript library implementing clock objects for modelling timelines. Useful in DVB CSS implementations.

1,476 lines (1,301 loc) 104 kB
(function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(); else if(typeof define === 'function' && define.amd) define([], factory); else if(typeof exports === 'object') exports["dvbcss-clocks"] = factory(); else root["dvbcss-clocks"] = factory(); })(this, function() { return /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) /******/ return installedModules[moduleId].exports; /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ exports: {}, /******/ id: moduleId, /******/ loaded: false /******/ }; /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ // Flag the module as loaded /******/ module.loaded = true; /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ // Load entry module and return exports /******/ return __webpack_require__(0); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ (function(module, exports, __webpack_require__) { module.exports = __webpack_require__(1); /***/ }), /* 1 */ /***/ (function(module, exports, __webpack_require__) { /**************************************************************************** * Copyright 2017 British Broadcasting Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *****************************************************************************/ var ClockBase = __webpack_require__(2); var DateNowClock = __webpack_require__(6); var CorrelatedClock = __webpack_require__(8); var Correlation = __webpack_require__(9); var OffsetClock = __webpack_require__(10); /** * @module dvbcss-clocks * * @description * The dvbcss-clocks library consists of this module containing the clock classes: * * <ul> * <li> dvbcss-clocks.{@link ClockBase} - base class for all clock implementations. * <li> cdvbcss-locks.{@link DateNowClock} - a root clock based on <tt>Date.now()</tt> * <li> dvbcss-clocks.{@link CorrelatedClock} - a clock based on a parent using a correlation. * <li> dvbcss-clocks.{@link Correlation} - a correlation. * <li> dvbcss-clocks.{@link OffsetClock} - a clock that applies a fixed offset to enable compensating for rendering latency. * </ul> * * <p>Clock can be built into hierarchies, where one clock is the root, and other * clocks use it as their parent, and others use those as their parents etc. * * <p>Clocks raise events, and listen to events from their parents: * <ul> * <li> {@link event:change} ... when any change occurs to a clock, or it is affected by a change of its parents. * <li> {@link event:available} ... when aa clock becomes flagged available * <li> {@link event:unavailable} ... when aa clock becomes flagged unavailable * </ul> */ module.exports = { /** * base class for all clock implementations * @see ClockBase */ ClockBase: ClockBase, /** * a root clock based on <tt>Date.now()</tt> * @see DateNowClock */ DateNowClock: DateNowClock, /** * a clock based on a parent using a correlation. * @see CorrelatedClock */ CorrelatedClock: CorrelatedClock, /** * a correlation. * @see Correlation */ Correlation: Correlation, /** * a clock that applies a fixed offset to enable compensating for rendering latency. * @see OffsetClock */ OffsetClock: OffsetClock }; /***/ }), /* 2 */ /***/ (function(module, exports, __webpack_require__) { /**************************************************************************** * Copyright 2017 British Broadcasting Corporation * and contributions Copyright 2017 British Telecommunications (BT) PLC. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * -------------------------------------------------------------------------- * Summary of parts containing contributions * by British Telecommunications (BT) PLC: * CorrelatedClock.prototype.setAtTime * CorrelatedClock.prototype._rescheduleTimers *****************************************************************************/ var EventEmitter = __webpack_require__(3); var inherits = __webpack_require__(4); var WeakMap = __webpack_require__(5); var PRIVATE = new WeakMap(); var nextIdNum = 0; var nextTimeoutHandle = 0; /** * There has been a change in the timing of this clock. * This might be due to a change made directly to this clock, or a change * made to a parent in the hierarchy that affected this clock. * * <p>Causes of changes to clocks include: changes to * [speed]{@link ClockBase#speed}, * [tick rate]{@link ClockBase#tickRate}, * [correlation]{@link CorrelatedClock#correlation}, or * [parentage]{@link ClockBase#parent}. * Changes to availability do not cause this event to fire. * * <p>The following parameters are passed as arguments to the event handler: * @event change * @param {ClockBase} source The clock that fired the event. */ /** * This clock has become available. * * This might be because [availabilityFlag]{@link ClockBase#availabilityFlag} * became true for this clock, or one of its parents in the hierarchy, causing this * clock and all its parents to now be flagged as available. * * <p>The following parameters are passed as arguments to the event handler: * @event available * @param {ClockBase} source The clock that fired the event. */ /** * This clock has become unavailable. * * This might be because [availabilityFlag]{@link ClockBase#availabilityFlag} * became false for this clock, or one of its parents in the hierarchy. * * <p>The following parameters are passed as arguments to the event handler: * @event unavailable * @param {ClockBase} source The clock that fired the event. */ /** * @module clocks * @exports ClockBase * @class ClockBase * * @classdesc * Abstract Base class for clock implementations. * * <p>Implementations that can be used are: * {@link DateNowClock} and * {@link CorrelatedClock}. * * <p>This is the base class on which other clocks are implemented. It provides * the basic framework of properties, getter and setters for common properties * such as availability, speed, tick rate and parents, and provides the basic * events framework, some standard helper methods for time conversion between clocks, comparisons * between clocks and calculating disperison (error/uncertainty). * * <p>Clocks may fire the following events: * <ul> * <li> [change]{@link event:change} * <li> [available]{@link event:available} * <li> [unavailable]{@link event:unavailable} * </ul> * * <p>Clock implementations should inherit from this class and implement some * or all of the following method stubs: * [now()]{@link ClockBase#now} * [calcWhen()]{@link ClockBase#calcWhen} * [getTickRate()]{@link ClockBase#getTickRate} * [setTickRate()]{@link ClockBase#setTickRate} * [getSpeed()]{@link ClockBase#getSpeed} * [setSpeed()]{@link ClockBase#setSpeed} * [getParent()]{@link ClockBase#getParent} * [setParent()]{@link ClockBase#setParent} * [toParentTime()]{@link ClockBase#toParentTime} * [fromParentTime()]{@link ClockBase#fromParentTime} * [_errorAtTime()]{@link ClockBase#_errorAtTime} * * @listens change * @constructor * @abstract */ var ClockBase = function() { EventEmitter.call(this); PRIVATE.set(this, {}); var priv = PRIVATE.get(this); this._availability = true; /** * Every clock instance has a unique ID assigned to it for convenience. This is always of the form "clock_N" where N is a unique number. * @var {String} id * @memberof ClockBase * @instance */ this.id = "clock_"+nextIdNum; nextIdNum = nextIdNum+1; priv.timerHandles = {}; this.on('change', this._rescheduleTimers.bind(this)); priv.availablePrev = this._availability; }; inherits(ClockBase, EventEmitter); /** * @returns the current time value of this clock in units of ticks of the clock, or NaN if it cannot be determined (e.g. if the clock is missinga parent) * @abstract */ ClockBase.prototype.now = function() { throw "Unimplemented"; }; /** * @var {Number} speed The speed at which this clock is running. * 1.0 = normal. 0.0 = pause. negative values mean it ticks in reverse. * * For some implementations this can be changed, as well as read. * * <p>The underlying implementation of this property uses the * [getSpeed]{@link ClockBase#getSpeed} and * [setSpeed]{@link ClockBase#setSpeed} methods. * @default 1.0 * @memberof ClockBase * @instance * @fires change */ Object.defineProperty(ClockBase.prototype, "speed", { get: function() { return this.getSpeed(); }, set: function(v) { return this.setSpeed(v); }, }); /** * @var {Number} tickRate The rate of this clock (in ticks per second). * * For some implementations this can be changed, as well as read. * * <p>The underlying implementation of this property uses the * [getTickRate]{@link ClockBase#getTickRate} and * [setTickRate]{@link ClockBase#setTickRate} methods. * * @memberof ClockBase * @instance * @fires change */ Object.defineProperty(ClockBase.prototype, "tickRate", { get: function() { return this.getTickRate(); }, set: function(v) { return this.setTickRate(v); }, }); /** * @var {ClockBase} parent The parent of this clock, or <tt>null</tt> if it has no parent. * * For some implementations this can be changed, as well as read. * * <p>The underlying implementation of this property uses the * [getParent]{@link ClockBase#getParent} and * [setParent]{@link ClockBase#setParent} methods. * * @memberof ClockBase * @instance * @fires change */ Object.defineProperty(ClockBase.prototype, "parent", { get: function() { return this.getParent(); }, set: function(v) { return this.setParent(v); }, }); /** * @var {Boolean} availabilityFlag The availability flag for this clock. * * For some implementations this can be changed, as well as read. * * <p>This is only the flag for this clock. Its availability may also be affected * by the flags on its parents. To determine true availability, call the * [isAvailable]{@link ClockBase#isAvailable} method. * * <p>The underlying implementation of this property uses the * [getAvailabilityFlag]{@link ClockBase#getAvailabilityFlag} and * [setAvailabilityFlag]{@link ClockBase#setAvailabilityFlag} methods. * * @default true * @memberof ClockBase * @instance * @fires change * @fires available * @fires unavailable */ Object.defineProperty(ClockBase.prototype, "availabilityFlag", { get: function() { return this.getAvailabilityFlag(); }, set: function(v) { return this.setAvailabilityFlag(v); }, }); /** * Returns the current speed of this clock. * @returns {Number} Speed of this clock. * @abstract */ ClockBase.prototype.getSpeed = function() { return 1.0; }; /** * Sets the current speed of this clock, or throws an exception if this is not possible * @param {Number} newSpeed The new speed for this clock. * @abstract * @fires change */ ClockBase.prototype.setSpeed = function(newSpeed) { throw "Unimplemented"; }; /** * Calculates the effective speed of this clock, taking into account the effects * of the speed settings for all of its parents. * @returns {Number} the effective speed. */ ClockBase.prototype.getEffectiveSpeed = function() { var s = 1.0; var clock = this; while (clock !== null) { s = s * clock.getSpeed(); clock = clock.getParent(); } return s; }; /** * Returns the current tick rate of this clock. * @returns {Number} Tick rate in ticks/second. * @abstract */ ClockBase.prototype.getTickRate = function() { throw "Unimplemented"; }; /** * Sets the current tick rate of this clock, or throws an exception if this is not possible. * @param {Number} newRate New tick rate in ticks/second. * @abstract * @fires change */ ClockBase.prototype.setTickRate = function(newRate) { throw "Unimplemented"; }; /** * Return the current time of this clock but converted to units of nanoseconds, instead of the normal units of the tick rate. * @returns {Number} current time of this clock in nanoseconds. */ ClockBase.prototype.getNanos = function() { return this.now() * 1000000000 / this.getTickRate(); }; /** * Convert a timevalue from nanoseconds to the units of this clock, given its current [tickRate]{@link ClockBase#tickRate} * @param {Number} time in nanoseconds. * @returns {Number} the supplied time converted to units of its tick rate. */ ClockBase.prototype.fromNanos = function(nanos) { return nanos * this.getTickRate() / 1000000000; }; /** * Is this clock currently available? Given its availability flag and the availability of its parents. * @returns {Boolean} True if this clock is available, and all its parents are available; otherwise false. */ ClockBase.prototype.isAvailable = function() { var parent = this.getParent(); return this._availability && (!parent || parent.isAvailable()); }; /** * Sets the availability flag for this clock. * * <p>This is only the flag for this clock. Its availability may also be affected * by the flags on its parents. To determine true availability, call the * [isAvailable]{@link ClockBase#isAvailable} method. * * @param {Boolean} availability The availability flag for this clock * @fires unavailable * @fires available */ ClockBase.prototype.setAvailabilityFlag = function(availability) { this._availability = availability; this.notifyAvailabilityChange(); }; /** * Cause the "available" or "unavailable" events to fire if availability has * changed since last time this method was called. Subclasses should call this * to robustly generate "available" or "unavailable" events instead of trying * to figure out if there has been a change for themselves. * @fires unavailable * @fires available */ ClockBase.prototype.notifyAvailabilityChange = function() { var priv = PRIVATE.get(this); var availableNow = this.isAvailable(); if (Boolean(availableNow) != Boolean(priv.availablePrev)) { priv.availablePrev = availableNow; this.emit(availableNow?"available":"unavailable", this); } }; /** * Returns the availability flag for this clock (without taking into account whether its parents are available). * * <p>This is only the flag for this clock. Its availability may also be affected * by the flags on its parents. To determine true availability, call the * [isAvailable]{@link ClockBase#isAvailable} method. * * @returns {Boolean} The availability flag of this clock */ ClockBase.prototype.getAvailabilityFlag = function() { return this._availability; }; /** * Convert a time value for this clock into a time value corresponding to teh underlying system time source being used by the root clock. * * <p>For example: if this clock is part of a hierarchy, where the root clock of the hierarchy is a [DateNowClock]{@link DateNowClock} then * this method converts the supplied time to be in the same units as <tt>Date.now()</tt>. * * @param {Number} ticksWhen Time value of this clock. * @return {Number} The corresponding time value in the units of the underlying system clock that is being used by the root clock, or <tt>NaN</tt> if this conversion is not possible. * @abstract */ ClockBase.prototype.calcWhen = function(ticksWhen) { throw "Unimplemented"; }; /** * Return the root clock for the hierarchy that this clock is part of. * * <p>If this clock is the root clock (it has no parent), then it will return itself. * * @return {ClockBase} The root clock of the hierarchy */ ClockBase.prototype.getRoot = function() { var p = this; var p2 = p.getParent(); while (p2) { p=p2; p2=p.getParent(); } return p; }; /** * Convert a time for the root clock to a time for this clock. * @param {Number} t A time value of the root clock. * @returns {Number} The corresponding time value for this clock. */ ClockBase.prototype.fromRootTime = function(t) { var p = this.getParent(); if (!p) { return t; } else { var x = p.fromRootTime(t); return this.fromParentTime(x); } }; /** * Convert a time for this clock to a time for the root clock. * @param {Number} t A time value for this clock. * @returns {Number} The corresponding time value of the root clock, or <tt>NaN</tt> if this is not possible. */ ClockBase.prototype.toRootTime = function(t) { var p = this.getParent(); if (!p) { return t; } else { var x = this.toParentTime(t); return p.toRootTime(x); } }; /** * Convert a time value for this clock to a time value for any other clock in the same hierarchy as this one. * @param {ClockBase} otherClock The clock to convert the value value to. * @param {Number} t Time value of this clock. * @returns {Number} The corresponding time value for the specified <tt>otherClock</tt>, or <tt>NaN</tt> if this is not possible. * @throws if this clock is not part of the same hierarchy as the other clock. */ ClockBase.prototype.toOtherClockTime = function(otherClock, t) { var selfAncestry = this.getAncestry(); var otherAncestry = otherClock.getAncestry(); var clock; var common = false; while (selfAncestry.length && otherAncestry.length && selfAncestry[selfAncestry.length-1] === otherAncestry[otherAncestry.length-1]) { selfAncestry.pop(); otherAncestry.pop(); common=true; } if (!common) { throw "No common ancestor clock."; } selfAncestry.forEach(function(clock) { t = clock.toParentTime(t); }); otherAncestry.reverse(); otherAncestry.forEach(function(clock) { t = clock.fromParentTime(t); }); return t; }; /** * Get an array of the clocks that are the parents and ancestors of this clock. * @returns {ClockBase[]} an array starting with this clock and ending with the root clock. */ ClockBase.prototype.getAncestry = function() { var ancestry = [this]; var c = this; while (c) { var p = c.getParent(); if (p) { ancestry.push(p); } c=p; } return ancestry; }; /** * Convert time value of this clock to the equivalent time of its parent. * * @param {Number} t Time value of this clock * @returns {Number} corresponding time of the parent clock, or <tt>NaN</tt> if this is not possible. * @abstract */ ClockBase.prototype.toParentTime = function(t) { throw "Unimplemented"; }; /** * Convert time value of this clock's parent to the equivalent time of this clock. * @param {Number} t Time value of this clock's parent * @returns {Number} corresponding time of this clock. * @abstract */ ClockBase.prototype.fromParentTime = function(t) { throw "Unimplemented"; }; /** * Returns the parent of this clock, or <tt>null</tt> if it has no parent. * @returns {ClockBase} parent clock, or <tt>null</tt> * @abstract */ ClockBase.prototype.getParent = function() { throw "Unimplemented"; }; /** * Set/change the parent of this clock. * @param {ClockBase} parent clock, or <tt>null</tt> * @throws if it is not allowed to set this clock's parent. * @abstract * @fires change */ ClockBase.prototype.setParent = function(newParent) { throw "Unimplemented"; }; /** * Calculate the potential for difference between this clock and another clock. * @param {ClockBase} otherClock The clock to compare with. * @returns {Number} The potential difference in units of seconds. If effective speeds or tick rates differ, this will always be <tt>Number.POSITIVE_INFINITY</tt> * * If the clocks differ in effective speed or tick rate, even slightly, then * this means that the clocks will eventually diverge to infinity, and so the * returned difference will equal +infinity. * * If the clocks do not differ in effective speed or tick rate, then there will * be a constant time difference between them. This is what is returned. */ ClockBase.prototype.clockDiff = function(otherClock) { var thisSpeed = this.getEffectiveSpeed(); var otherSpeed = otherClock.getEffectiveSpeed(); if (thisSpeed !== otherSpeed) { return Number.POSITIVE_INFINITY; } else if (this.getTickRate() !== otherClock.getTickRate()) { return Number.POSITIVE_INFINITY; } else { var root = this.getRoot(); var t = root.now(); var t1 = this.fromRootTime(t); var t2 = otherClock.fromRootTime(t); return Math.abs(t1-t2) / this.getTickRate(); } }; /** * Calculates the dispersion (maximum error bounds) at the specified clock time. * This takes into account the contribution to error of this clock and its ancestors. * @param {Number} t The time position of this clock for which the dispersion is to be calculated. * @returns {Number} Dispersion (in seconds) at the specified clock time. */ ClockBase.prototype.dispersionAtTime = function(t) { var disp = this._errorAtTime(t); var p = this.getParent(); if (p) { var pt = this.toParentTime(t); disp += p.dispersionAtTime(pt); } return disp; }; /** * Calculates the error/uncertainty contribution of this clock at a given time position. * * <p>It is not intended that this function is called directly. Instead, call * [dispersionAtTime()]{@link ClockBase.dispersionAtTime} which uses this function * as part of calculating the total dispersion. * * @param {Number} t A time position of this clock * @returns {Number} the potential for error (in seconds) arising from this clock * at a given time of this clock. Does not include the contribution of * any parent clocks. * * @abstract */ ClockBase.prototype._errorAtTime = function(t) { throw "Unimplemented"; }; /** * Retrieve the maximium frequency error (in ppm) of the root clock in the hierarchy. * * <p>This method contains an implementation for non-root clocks only. It must * be overriden for root clock implementations. * * @returns {Number} The maximum frequency error of the root clock (in parts per million) * @abstract */ ClockBase.prototype.getRootMaxFreqError = function() { var root = this.getRoot(); if (root === this) { throw "Unimplemented"; } else { return root.getRootMaxFreqError(); } }; /** * A callback that is called when using [setTimeout]{@link ClockBase#setTimeout} or [setAtTime][@link ClockBase#setAtTime]. * * @callback setTimeoutCallback * @param {...*} args The parameters that were passed when the callback was scheduled. * @this ClockBase */ /** * Request a timeout callback when the time of this clock passes the current time plus * the number of specified ticks. * * <p>If there are changes to timing caused by changes to this clock or its parents, then this timer will be automatically * rescheduled to compensate. * * @param {setTimeoutCallback} func The function to callback * @param {Number} ticks The callback is triggered when the clock passes (reaches or jumps past) this number of ticks beyond the current time. * @param {...*} args Other arguments are passed to the callback * @returns A handle for the timer. Pass this handle to [clearTimeout]{@link ClockBase#clearTimeout} to cancel this timer callback. */ ClockBase.prototype.setTimeout = function(func, ticks) { arguments[1] = arguments[1] + this.now(); return this.setAtTime.apply(this, arguments); }; /** * Request a timeout callback when the time of this clock passes the specified time. * * <p>If there are changes to timing caused by changes to this clock or its parents, then this timer will be automatically * rescheduled to compensate. * * @param {setTimeoutCallBack} func The function to callback * @param {Number} when The callback is triggered when the clock passes (reaches or jumps past) this time. * @param {...*} args Other arguments are passed to the callback * @returns A handle for the timer. Pass this handle to [clearTimeout]{@link ClockBase#clearTimeout} to cancel this timer callback. */ ClockBase.prototype.setAtTime = function(func, when) { var priv = PRIVATE.get(this); var self = this; var handle = self.id + ":timeout-" + nextTimeoutHandle++; var root = self.getRoot(); if (root === null) { root = self; } // remove first two args var args = new Array(arguments.length-2); for(var i=2; i<arguments.length; i++) { args[i-2] = arguments[i]; } var callback = function() { delete priv.timerHandles[handle]; func.apply(self, args); } ; var numRootTicks = self.toRootTime(when) - root.now(); if (numRootTicks !== 0) { numRootTicks = root.getSpeed() !== 0 ? numRootTicks / root.getSpeed() : NaN; } var millis = numRootTicks * (1000 / root.getTickRate()); var realHandle; if (!isNaN(millis)) { realHandle = setTimeout(callback, millis); } priv.timerHandles[handle] = { realHandle:realHandle, when:when, callback:callback }; return handle; }; ClockBase.prototype._rescheduleTimers = function() { // clock timing has changed, we need to re-schedule all timers var priv = PRIVATE.get(this); var root = this.getRoot(); for(var handle in priv.timerHandles) { if (priv.timerHandles.hasOwnProperty(handle)) { var d = priv.timerHandles[handle]; // clear existing timer if (d.realHandle !== null && d.realHandle !== undefined) { clearTimeout(d.realHandle); } // re-calculate when this timer is due and re-schedule var numRootTicks = this.toRootTime(d.when) - root.now(); if (numRootTicks !== 0) { numRootTicks = root.getSpeed() !== 0 ? numRootTicks / root.getSpeed() : NaN; } var millis = numRootTicks * (1000 / root.getTickRate()); if (!isNaN(millis)) { d.realHandle = setTimeout(d.callback, Math.max(0,millis)); } else { delete d.realHandle; } } } }; /** * Clear (cancel) a timer that was scheduled using [setTimeout]{@link ClockBase#setTimeout} or [setAtTime][@link ClockBase#setAtTime]. * * @param handle - The handle for the previously scheduled callback. * * If the handle does not represent a callback that was scheduled against this clock, then this method returns without doing anything. */ ClockBase.prototype.clearTimeout = function(handle) { var priv = PRIVATE.get(this); var d = priv.timerHandles[handle]; if (d !== undefined) { clearTimeout(d.realHandle); delete priv.timerHandles[handle]; } }; module.exports = ClockBase; /***/ }), /* 3 */ /***/ (function(module, exports) { // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to permit // persons to whom the Software is furnished to do so, subject to the // following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. function EventEmitter() { this._events = this._events || {}; this._maxListeners = this._maxListeners || undefined; } module.exports = EventEmitter; // Backwards-compat with node 0.10.x EventEmitter.EventEmitter = EventEmitter; EventEmitter.prototype._events = undefined; EventEmitter.prototype._maxListeners = undefined; // By default EventEmitters will print a warning if more than 10 listeners are // added to it. This is a useful default which helps finding memory leaks. EventEmitter.defaultMaxListeners = 10; // Obviously not all Emitters should be limited to 10. This function allows // that to be increased. Set to zero for unlimited. EventEmitter.prototype.setMaxListeners = function(n) { if (!isNumber(n) || n < 0 || isNaN(n)) throw TypeError('n must be a positive number'); this._maxListeners = n; return this; }; EventEmitter.prototype.emit = function(type) { var er, handler, len, args, i, listeners; if (!this._events) this._events = {}; // If there is no 'error' event listener then throw. if (type === 'error') { if (!this._events.error || (isObject(this._events.error) && !this._events.error.length)) { er = arguments[1]; if (er instanceof Error) { throw er; // Unhandled 'error' event } else { // At least give some kind of context to the user var err = new Error('Uncaught, unspecified "error" event. (' + er + ')'); err.context = er; throw err; } } } handler = this._events[type]; if (isUndefined(handler)) return false; if (isFunction(handler)) { switch (arguments.length) { // fast cases case 1: handler.call(this); break; case 2: handler.call(this, arguments[1]); break; case 3: handler.call(this, arguments[1], arguments[2]); break; // slower default: args = Array.prototype.slice.call(arguments, 1); handler.apply(this, args); } } else if (isObject(handler)) { args = Array.prototype.slice.call(arguments, 1); listeners = handler.slice(); len = listeners.length; for (i = 0; i < len; i++) listeners[i].apply(this, args); } return true; }; EventEmitter.prototype.addListener = function(type, listener) { var m; if (!isFunction(listener)) throw TypeError('listener must be a function'); if (!this._events) this._events = {}; // To avoid recursion in the case that type === "newListener"! Before // adding it to the listeners, first emit "newListener". if (this._events.newListener) this.emit('newListener', type, isFunction(listener.listener) ? listener.listener : listener); if (!this._events[type]) // Optimize the case of one listener. Don't need the extra array object. this._events[type] = listener; else if (isObject(this._events[type])) // If we've already got an array, just append. this._events[type].push(listener); else // Adding the second element, need to change to array. this._events[type] = [this._events[type], listener]; // Check for listener leak if (isObject(this._events[type]) && !this._events[type].warned) { if (!isUndefined(this._maxListeners)) { m = this._maxListeners; } else { m = EventEmitter.defaultMaxListeners; } if (m && m > 0 && this._events[type].length > m) { this._events[type].warned = true; console.error('(node) warning: possible EventEmitter memory ' + 'leak detected. %d listeners added. ' + 'Use emitter.setMaxListeners() to increase limit.', this._events[type].length); if (typeof console.trace === 'function') { // not supported in IE 10 console.trace(); } } } return this; }; EventEmitter.prototype.on = EventEmitter.prototype.addListener; EventEmitter.prototype.once = function(type, listener) { if (!isFunction(listener)) throw TypeError('listener must be a function'); var fired = false; function g() { this.removeListener(type, g); if (!fired) { fired = true; listener.apply(this, arguments); } } g.listener = listener; this.on(type, g); return this; }; // emits a 'removeListener' event iff the listener was removed EventEmitter.prototype.removeListener = function(type, listener) { var list, position, length, i; if (!isFunction(listener)) throw TypeError('listener must be a function'); if (!this._events || !this._events[type]) return this; list = this._events[type]; length = list.length; position = -1; if (list === listener || (isFunction(list.listener) && list.listener === listener)) { delete this._events[type]; if (this._events.removeListener) this.emit('removeListener', type, listener); } else if (isObject(list)) { for (i = length; i-- > 0;) { if (list[i] === listener || (list[i].listener && list[i].listener === listener)) { position = i; break; } } if (position < 0) return this; if (list.length === 1) { list.length = 0; delete this._events[type]; } else { list.splice(position, 1); } if (this._events.removeListener) this.emit('removeListener', type, listener); } return this; }; EventEmitter.prototype.removeAllListeners = function(type) { var key, listeners; if (!this._events) return this; // not listening for removeListener, no need to emit if (!this._events.removeListener) { if (arguments.length === 0) this._events = {}; else if (this._events[type]) delete this._events[type]; return this; } // emit removeListener for all listeners on all events if (arguments.length === 0) { for (key in this._events) { if (key === 'removeListener') continue; this.removeAllListeners(key); } this.removeAllListeners('removeListener'); this._events = {}; return this; } listeners = this._events[type]; if (isFunction(listeners)) { this.removeListener(type, listeners); } else if (listeners) { // LIFO order while (listeners.length) this.removeListener(type, listeners[listeners.length - 1]); } delete this._events[type]; return this; }; EventEmitter.prototype.listeners = function(type) { var ret; if (!this._events || !this._events[type]) ret = []; else if (isFunction(this._events[type])) ret = [this._events[type]]; else ret = this._events[type].slice(); return ret; }; EventEmitter.prototype.listenerCount = function(type) { if (this._events) { var evlistener = this._events[type]; if (isFunction(evlistener)) return 1; else if (evlistener) return evlistener.length; } return 0; }; EventEmitter.listenerCount = function(emitter, type) { return emitter.listenerCount(type); }; function isFunction(arg) { return typeof arg === 'function'; } function isNumber(arg) { return typeof arg === 'number'; } function isObject(arg) { return typeof arg === 'object' && arg !== null; } function isUndefined(arg) { return arg === void 0; } /***/ }), /* 4 */ /***/ (function(module, exports) { if (typeof Object.create === 'function') { // implementation from standard node.js 'util' module module.exports = function inherits(ctor, superCtor) { ctor.super_ = superCtor ctor.prototype = Object.create(superCtor.prototype, { constructor: { value: ctor, enumerable: false, writable: true, configurable: true } }); }; } else { // old school shim for old browsers module.exports = function inherits(ctor, superCtor) { ctor.super_ = superCtor var TempCtor = function () {} TempCtor.prototype = superCtor.prototype ctor.prototype = new TempCtor() ctor.prototype.constructor = ctor } } /***/ }), /* 5 */ /***/ (function(module, exports) { // Copyright (C) 2011 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /** * @fileoverview Install a leaky WeakMap emulation on platforms that * don't provide a built-in one. * * <p>Assumes that an ES5 platform where, if {@code WeakMap} is * already present, then it conforms to the anticipated ES6 * specification. To run this file on an ES5 or almost ES5 * implementation where the {@code WeakMap} specification does not * quite conform, run <code>repairES5.js</code> first. * * <p>Even though WeakMapModule is not global, the linter thinks it * is, which is why it is in the overrides list below. * * <p>NOTE: Before using this WeakMap emulation in a non-SES * environment, see the note below about hiddenRecord. * * @author Mark S. Miller * @requires crypto, ArrayBuffer, Uint8Array, navigator, console * @overrides WeakMap, ses, Proxy * @overrides WeakMapModule */ /** * This {@code WeakMap} emulation is observably equivalent to the * ES-Harmony WeakMap, but with leakier garbage collection properties. * * <p>As with true WeakMaps, in this emulation, a key does not * retain maps indexed by that key and (crucially) a map does not * retain the keys it indexes. A map by itself also does not retain * the values associated with that map. * * <p>However, the values associated with a key in some map are * retained so long as that key is retained and those associations are * not overridden. For example, when used to support membranes, all * values exported from a given membrane will live for the lifetime * they would have had in the absence of an interposed membrane. Even * when the membrane is revoked, all objects that would have been * reachable in the absence of revocation will still be reachable, as * far as the GC can tell, even though they will no longer be relevant * to ongoing computation. * * <p>The API implemented here is approximately the API as implemented * in FF6.0a1 and agreed to by MarkM, Andreas Gal, and Dave Herman, * rather than the offially approved proposal page. TODO(erights): * upgrade the ecmascript WeakMap proposal page to explain this API * change and present to EcmaScript committee for their approval. * * <p>The first difference between the emulation here and that in * FF6.0a1 is the presence of non enumerable {@code get___, has___, * set___, and delete___} methods on WeakMap instances to represent * what would be the hidden internal properties of a primitive * implementation. Whereas the FF6.0a1 WeakMap.prototype methods * require their {@code this} to be a genuine WeakMap instance (i.e., * an object of {@code [[Class]]} "WeakMap}), since there is nothing * unforgeable about the pseudo-internal method names used here, * nothing prevents these emulated prototype methods from being * applied to non-WeakMaps with pseudo-internal methods of the same * names. * * <p>Another difference is that our emulated {@code * WeakMap.prototype} is not itself a WeakMap. A problem with the * current FF6.0a1 API is that WeakMap.prototype is itself a WeakMap * providing ambient mutability and an ambient communications * channel. Thus, if a WeakMap is already present and has this * problem, repairES5.js wraps it in a safe wrappper in order to * prevent access to this channel. (See * PATCH_MUTABLE_FROZEN_WEAKMAP_PROTO in repairES5.js). */ /** * If this is a full <a href= * "http://code.google.com/p/es-lab/wiki/SecureableES5" * >secureable ES5</a> platform and the ES-Harmony {@code WeakMap} is * absent, install an approximate emulation. * * <p>If WeakMap is present but cannot store some objects, use our approximate * emulation as a wrapper. * * <p>If this is almost a secureable ES5 platform, then WeakMap.js * should be run after repairES5.js. * * <p>See {@code WeakMap} for documentation of the garbage collection * properties of this WeakMap emulation. */ (function WeakMapModule() { "use strict"; if (typeof ses !== 'undefined' && ses.ok && !ses.ok()) { // already too broken, so give up return; } /** * In some cases (current Firefox), we must make a choice betweeen a * WeakMap which is capable of using all varieties of host objects as * keys and one which is capable of safely using proxies as keys. See * comments below about HostWeakMap and DoubleWeakMap for details. * * This function (which is a global, not exposed to guests) marks a * WeakMap as permitted to do what is necessary to index all host * objects, at the cost of making it unsafe for proxies. * * Do not apply this function to anything which is not a genuine * fresh WeakMap. */ function weakMapPermitHostObjects(map) { // identity of function used as a secret -- good enough and cheap if (map.permitHostObjects___) { map.permitHostObjects___(weakMapPermitHostObjects); } } if (typeof ses !== 'undefined') { ses.weakMapPermitHostObjects = weakMapPermitHostObjects; } // IE 11 has no Proxy but has a broken WeakMap such that we need to patch // it using DoubleWeakMap; this flag tells DoubleWeakMap so. var doubleWeakMapCheckSilentFailure = false; // Check if there is already a good-enough WeakMap implementation, and if so // exit without replacing it. if (typeof WeakMap === 'function') { var HostWeakMap = WeakMap; // There is a WeakMap -- is it good enough? if (typeof navigator !== 'undefined' && /Firefox/.test(navigator.userAgent)) { // We're now *assuming not*, because as of this writing (2013-05-06) // Firefox's WeakMaps have a miscellany of objects they won't accept, and // we don't want to make an exhaustive list, and testing for just one // will be a problem if that one is fixed alone (as they did for Event). // If there is a platform that we *can* reliably test on, here's how to // do it: // var problematic = ... ; // var testHostMap = new HostWeakMap(); // try { // testHostMap.set(problematic, 1); // Firefox 20 will throw here // if (testHostMap.get(problematic) === 1) { // return; // } // } catch (e) {} } else { // IE 11 bug: WeakMaps silently fail to store frozen objects. var testMap = new HostWeakMap(); var testObject = Object.freeze({}); testMap.set(testObject, 1); if (testMap.get(testObject) !== 1) { doubleWeakMapCheckSilentFailure = true; // Fall through to installing our WeakMap. } else { module.exports = WeakMap; return; } } } var hop = Object.prototype.hasOwnProperty; var gopn = Object.getOwnPropertyNames; var defProp = Object.defineProperty; var isExtensible = Object.isExtensible; /** * Security depends on HIDDEN_NAME being both <i>unguessable</i> and * <i>undiscoverable</i> by untrusted code. * * <p>Given the known weaknesses of Math.random() on existing * browsers, it does not generate unguessability we can be confident * of. * * <p>It is the monkey patching logic in this file that is intended * to ensure undiscoverability. The basic idea is that there are * three fundamental means of discovering properties of an object: * The for/in loop, Object.keys(), and Object.getOwnPropertyNames(), * as well as some proposed ES6 extensions that appear on our * whitelist. The first two only discover enumerable properties, and * we only use HIDDEN_NAME to name a non-enumerable property, so the * only remaining threat should be getOwnPropertyNames and some * proposed ES6 extensions that appear on our whitelist. We monkey * patch them to remove HIDDEN_NAME from the list of properties they * returns. * * <p>TODO(erights): On a platform with built-in Proxies, proxies * could be used to trap and thereby discover the HIDDEN_NAME, so we * need to monkey patch Proxy.create, Proxy.createFunction, etc, in * order to wrap the provided handler with the real handler which * filters out all traps using HIDDEN_NAME. * * <p>TODO(erights): Revisit Mike Stay's suggestion that we use an * encapsulated function at a not-necessarily-secret name, which * uses the Stiegler shared-state rights amplification pattern to * reveal the associated value only to the WeakMap in which this key * is associated with that value. Since only the key retains the * function, the function can also remember the key without causing * leakage of the key, so this doesn't violate our general gc * goals. In addition, because the name need not be a guarded * secret, we could efficiently handle cross-frame frozen keys. */ var HIDDEN_NAME_PREFIX = 'weakmap:'; var HIDDEN_NAME = HIDDEN_NAME_PREFIX + 'ident:' + Math.random() + '___'; if (typeof crypto !== 'undefined' && typeof crypto.getRandomValues === 'function' && typeof ArrayBuffer === 'function' && typeof Uint8Array === 'function') { var ab = new ArrayBuffer(25); var u8s = new Uint8Array(ab); crypto.getRandomValues(u8s); HIDDEN_NAME = HIDDEN_NAME_PREFIX + 'rand:' + Array.prototype.map.call(u8s, function(u8) { return (u8 % 36).toString(36); }).join('') + '___'; } function isNotHiddenName(name) { return !( name.substr(0, HIDDEN_NAME_PREFIX.length) == HIDDEN_NAME_PREFIX && name.substr(name.length - 3) === '___'); } /** * Monkey patch getOwnPropertyNames to avoid revealing the * HIDDEN_NAME. * * <p>The ES5.1 spec requires each name to appear only once, but as * of this writing, this requirement is controversial for ES6, so we * made this code robust against this case. If the resulting extra * search turns out to be expensive, we can probably relax this once * ES6 is adequately supported on all major browsers, iff no browser * versions we support at that time have relaxed this constraint * without providing built-in ES6 WeakMaps. */ defProp(Object, 'getOwnPropertyNames', { value: function fakeGetOwnPropertyNames(obj) { return gopn(obj).filter(isNotHiddenName); } }); /** * getPropertyNames is not in ES5 but it is proposed for ES6 and * does appear in our whitelist, so we need to clean it too. */ if ('getPropertyNames' in Object) { var originalGetPropertyNames = Object.getPropertyNames; defProp(Object, 'getPropertyNames', { value: function fakeGetPropertyNames(obj) { return originalGetPropertyNames(obj).filter(isNotHiddenName); } }); } /** * <p>To treat objects as identity-keys with reasonable efficiency * on ES5 by itself (i.e., without any object-keyed collections), we * need to add a hidden property to such key objects when we * c