// 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. var isArray = Array.isArray; var domain; exports.usingDomains = false; function EventEmitter() { this.domain = null; if (exports.usingDomains) { // if there is an active domain, then attach to it. domain = domain || require('domain'); if (domain.active && !(this instanceof domain.Domain)) { this.domain = domain.active; } } this._events = this._events || null; this._maxListeners = this._maxListeners || defaultMaxListeners; } exports.EventEmitter = EventEmitter; // 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. // // Obviously not all Emitters should be limited to 10. This function allows // that to be increased. Set to zero for unlimited. var defaultMaxListeners = 10; EventEmitter.prototype.setMaxListeners = function(n) { if (typeof n !== 'number' || n < 0) throw TypeError('n must be a positive number'); this._maxListeners = n; }; // non-global reference, for speed. var PROCESS; EventEmitter.prototype.emit = function(type) { // If there is no 'error' event listener then throw. if (type === 'error') { if (!this._events || !this._events.error || (isArray(this._events.error) && !this._events.error.length)) { if (this.domain) { var er = arguments[1]; er.domainEmitter = this; er.domain = this.domain; er.domainThrown = false; this.domain.emit('error', er); return false; } if (arguments[1] instanceof Error) { throw arguments[1]; // Unhandled 'error' event } else { throw TypeError("Uncaught, unspecified 'error' event."); } return false; } } if (!this._events) return false; var handler = this._events[type]; if (!handler) return false; if (typeof handler == 'function') { if (this.domain) { PROCESS = PROCESS || process; if (this !== PROCESS) { this.domain.enter(); } } 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: var l = arguments.length; var args = new Array(l - 1); for (var i = 1; i < l; i++) args[i - 1] = arguments[i]; handler.apply(this, args); } if (this.domain && this !== PROCESS) { this.domain.exit(); } return true; } else if (isArray(handler)) { if (this.domain) { PROCESS = PROCESS || process; if (this !== PROCESS) { this.domain.enter(); } } var l = arguments.length; var args = new Array(l - 1); for (var i = 1; i < l; i++) args[i - 1] = arguments[i]; var listeners = handler.slice(); for (var i = 0, l = listeners.length; i < l; i++) { listeners[i].apply(this, args); } if (this.domain && this !== PROCESS) { this.domain.exit(); } return true; } else { return false; } }; EventEmitter.prototype.addListener = function(type, listener) { if ('function' !== typeof listener) { throw TypeError('addListener only takes instances of 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, typeof listener.listener === 'function' ? 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 (isArray(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 (isArray(this._events[type]) && !this._events[type].warned) { var m; m = this._maxListeners; 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); console.trace(); } } return this; }; EventEmitter.prototype.on = EventEmitter.prototype.addListener; EventEmitter.prototype.once = function(type, listener) { if ('function' !== typeof listener) { throw TypeError('.once only takes instances of Function'); } var self = this; function g() { self.removeListener(type, g); listener.apply(this, arguments); }; g.listener = listener; self.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 (typeof type !== 'string') throw TypeError('type must be a string'); if (typeof listener !== 'function') 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 || (typeof list.listener === 'function' && list.listener === listener)) { this._events[type] = null; if (this._events.removeListener) this.emit('removeListener', type, listener); } else if (isArray(list)) { for (i = 0; i < length; i++) { 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; this._events[type] = null; } 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 (arguments.length > 0 && typeof type !== 'string') throw TypeError('type must not be set or must be a string'); if (!this._events) return this; // not listening for removeListener, no need to emit if (!this._events.removeListener) { if (arguments.length === 0) this._events = null; else if (this._events[type]) this._events[type] = null; 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 = null; return this; } listeners = this._events[type]; if (typeof listeners === 'function') { this.removeListener(type, listeners); } else { // LIFO order while (listeners.length) this.removeListener(type, listeners[listeners.length - 1]); } this._events[type] = null; return this; }; EventEmitter.prototype.listeners = function(type) { if (typeof type !== 'string') throw TypeError('event type must be a string'); if (!this._events || !this._events[type]) return []; if (typeof this._events[type] === 'function') return [this._events[type]]; return this._events[type].slice(); }; EventEmitter.listenerCount = function(emitter, type) { var ret; if (!emitter._events || !emitter._events[type]) ret = 0; else if (typeof emitter._events[type] === 'function') ret = 1; else ret = emitter._events[type].length; return ret; };