text: "use strict";
  module.exports = EventEmitter;
  
  /**
   * Constructs a new event emitter instance.
   * @classdesc A minimal event emitter.
   * @memberof util
   * @constructor
   */
  function EventEmitter() {
  
      /**
       * Registered listeners.
       * @type {Object.<string,*>}
       * @private
       */
      this._listeners = {};
  }
  
  /**
   * Event listener as used by {@link util.EventEmitter}.
   * @typedef EventEmitterListener
   * @type {function}
   * @param {...*} args Arguments
   * @returns {undefined}
   */
  
  /**
   * Registers an event listener.
   * @param {string} evt Event name
   * @param {EventEmitterListener} fn Listener
   * @param {*} [ctx] Listener context
   * @returns {this} `this`
   */
  EventEmitter.prototype.on = function on(evt, fn, ctx) {
      (this._listeners[evt] || (this._listeners[evt] = [])).push({
          fn  : fn,
          ctx : ctx || this
      });
      return this;
  };
  
  /**
   * Removes an event listener or any matching listeners if arguments are omitted.
   * @param {string} [evt] Event name. Removes all listeners if omitted.
   * @param {EventEmitterListener} [fn] Listener to remove. Removes all listeners of `evt` if omitted.
   * @returns {this} `this`
   */
  EventEmitter.prototype.off = function off(evt, fn) {
      if (evt === undefined)
          this._listeners = {};
      else {
          if (fn === undefined)
              this._listeners[evt] = [];
          else {
              var listeners = this._listeners[evt];
              for (var i = 0; i < listeners.length;)
                  if (listeners[i].fn === fn)
                      listeners.splice(i, 1);
                  else
                      ++i;
          }
      }
      return this;
  };
  
  /**
   * Emits an event by calling its listeners with the specified arguments.
   * @param {string} evt Event name
   * @param {...*} args Arguments
   * @returns {this} `this`
   */
  EventEmitter.prototype.emit = function emit(evt) {
      var listeners = this._listeners[evt];
      if (listeners) {
          var args = [],
              i = 1;
          for (; i < arguments.length;)
              args.push(arguments[i++]);
          for (i = 0; i < listeners.length;)
              listeners[i].fn.apply(listeners[i++].ctx, args);
      }
      return this;
  };
  