text: /*!
   * EventEmitter2
   * https://github.com/hij1nx/EventEmitter2
   *
   * Copyright (c) 2013 hij1nx
   * Licensed under the MIT license.
   */
  ;!function(undefined) {
    var hasOwnProperty= Object.hasOwnProperty;
    var isArray = Array.isArray ? Array.isArray : function _isArray(obj) {
      return Object.prototype.toString.call(obj) === "[object Array]";
    };
    var defaultMaxListeners = 10;
    var nextTickSupported= typeof process=='object' && typeof process.nextTick=='function';
    var symbolsSupported= typeof Symbol==='function';
    var reflectSupported= typeof Reflect === 'object';
    var setImmediateSupported= typeof setImmediate === 'function';
    var _setImmediate= setImmediateSupported ? setImmediate : setTimeout;
    var ownKeys= symbolsSupported? (reflectSupported && typeof Reflect.ownKeys==='function'? Reflect.ownKeys : function(obj){
      var arr= Object.getOwnPropertyNames(obj);
      arr.push.apply(arr, Object.getOwnPropertySymbols(obj));
      return arr;
    }) : Object.keys;
  
    function init() {
      this._events = {};
      if (this._conf) {
        configure.call(this, this._conf);
      }
    }
  
    function configure(conf) {
      if (conf) {
        this._conf = conf;
  
        conf.delimiter && (this.delimiter = conf.delimiter);
  
        if(conf.maxListeners!==undefined){
            this._maxListeners= conf.maxListeners;
        }
  
        conf.wildcard && (this.wildcard = conf.wildcard);
        conf.newListener && (this._newListener = conf.newListener);
        conf.removeListener && (this._removeListener = conf.removeListener);
        conf.verboseMemoryLeak && (this.verboseMemoryLeak = conf.verboseMemoryLeak);
        conf.ignoreErrors && (this.ignoreErrors = conf.ignoreErrors);
  
        if (this.wildcard) {
          this.listenerTree = {};
        }
      }
    }
  
    function logPossibleMemoryLeak(count, eventName) {
      var errorMsg = '(node) warning: possible EventEmitter memory ' +
          'leak detected. ' + count + ' listeners added. ' +
          'Use emitter.setMaxListeners() to increase limit.';
  
      if(this.verboseMemoryLeak){
        errorMsg += ' Event name: ' + eventName + '.';
      }
  
      if(typeof process !== 'undefined' && process.emitWarning){
        var e = new Error(errorMsg);
        e.name = 'MaxListenersExceededWarning';
        e.emitter = this;
        e.count = count;
        process.emitWarning(e);
      } else {
        console.error(errorMsg);
  
        if (console.trace){
          console.trace();
        }
      }
    }
  
    var toArray = function (a, b, c) {
      var n = arguments.length;
      switch (n) {
        case 0:
          return [];
        case 1:
          return [a];
        case 2:
          return [a, b];
        case 3:
          return [a, b, c];
        default:
          var arr = new Array(n);
          while (n--) {
            arr[n] = arguments[n];
          }
          return arr;
      }
    };
  
    function toObject(keys, values) {
      var obj = {};
      var key;
      var len = keys.length;
      var valuesCount = values ? value.length : 0;
      for (var i = 0; i < len; i++) {
        key = keys[i];
        obj[key] = i < valuesCount ? values[i] : undefined;
      }
      return obj;
    }
  
    function TargetObserver(emitter, target, options) {
      this._emitter = emitter;
      this._target = target;
      this._listeners = {};
      this._listenersCount = 0;
  
      var on, off;
  
      if (options.on || options.off) {
        on = options.on;
        off = options.off;
      }
  
      if (target.addEventListener) {
        on = target.addEventListener;
        off = target.removeEventListener;
      } else if (target.addListener) {
        on = target.addListener;
        off = target.removeListener;
      } else if (target.on) {
        on = target.on;
        off = target.off;
      }
  
      if (!on && !off) {
        throw Error('target does not implement any known event API');
      }
  
      if (typeof on !== 'function') {
        throw TypeError('on method must be a function');
      }
  
      if (typeof off !== 'function') {
        throw TypeError('off method must be a function');
      }
  
      this._on = on;
      this._off = off;
  
      var _observers= emitter._observers;
      if(_observers){
        _observers.push(this);
      }else{
        emitter._observers= [this];
      }
    }
  
    Object.assign(TargetObserver.prototype, {
      subscribe: function(event, localEvent, reducer){
        var observer= this;
        var target= this._target;
        var emitter= this._emitter;
        var listeners= this._listeners;
        var handler= function(){
          var args= toArray.apply(null, arguments);
          var eventObj= {
            data: args,
            name: localEvent,
            original: event
          };
          if(reducer){
            var result= reducer.call(target, eventObj);
            if(result!==false){
              emitter.emit.apply(emitter, [eventObj.name].concat(args))
            }
            return;
          }
          emitter.emit.apply(emitter, [localEvent].concat(args));
        };
  
  
        if(listeners[event]){
          throw Error('Event \'' + event + '\' is already listening');
        }
  
        this._listenersCount++;
  
        if(emitter._newListener && emitter._removeListener && !observer._onNewListener){
  
          this._onNewListener = function (_event) {
            if (_event === localEvent && listeners[event] === null) {
              listeners[event] = handler;
              observer._on.call(target, event, handler);
            }
          };
  
          emitter.on('newListener', this._onNewListener);
  
          this._onRemoveListener= function(_event){
            if(_event === localEvent && !emitter.hasListeners(_event) && listeners[event]){
              listeners[event]= null;
              observer._off.call(target, event, handler);
            }
          };
  
          listeners[event]= null;
  
          emitter.on('removeListener', this._onRemoveListener);
        }else{
          listeners[event]= handler;
          observer._on.call(target, event, handler);
        }
      },
  
      unsubscribe: function(event){
        var observer= this;
        var listeners= this._listeners;
        var emitter= this._emitter;
        var handler;
        var events;
        var off= this._off;
        var target= this._target;
        var i;
  
        if(event && typeof event!=='string'){
          throw TypeError('event must be a string');
        }
  
        function clearRefs(){
          if(observer._onNewListener){
            emitter.off('newListener', observer._onNewListener);
            emitter.off('removeListener', observer._onRemoveListener);
            observer._onNewListener= null;
            observer._onRemoveListener= null;
          }
          var index= findTargetIndex.call(emitter, observer);
          emitter._observers.splice(index, 1);
        }
  
        if(event){
          handler= listeners[event];
          if(!handler) return;
          off.call(target, event, handler);
          delete listeners[event];
          if(!--this._listenersCount){
            clearRefs();
          }
        }else{
          events= ownKeys(listeners);
          i= events.length;
          while(i-->0){
            event= events[i];
            off.call(target, event, listeners[event]);
          }
          this._listeners= {};
          this._listenersCount= 0;
          clearRefs();
        }
      }
    });
  
    function resolveOptions(options, schema, reducers, allowUnknown) {
      var computedOptions = Object.assign({}, schema);
  
      if (!options) return computedOptions;
  
      if (typeof options !== 'object') {
        throw TypeError('options must be an object')
      }
  
      var keys = Object.keys(options);
      var length = keys.length;
      var option, value;
      var reducer;
  
      function reject(reason) {
        throw Error('Invalid "' + option + '" option value' + (reason ? '. Reason: ' + reason : ''))
      }
  
      for (var i = 0; i < length; i++) {
        option = keys[i];
        if (!allowUnknown && !hasOwnProperty.call(schema, option)) {
          throw Error('Unknown "' + option + '" option');
        }
        value = options[option];
        if (value !== undefined) {
          reducer = reducers[option];
          computedOptions[option] = reducer ? reducer(value, reject) : value;
        }
      }
      return computedOptions;
    }
  
    function constructorReducer(value, reject) {
      if (typeof value !== 'function' || !value.hasOwnProperty('prototype')) {
        reject('value must be a constructor');
      }
      return value;
    }
  
    function makeTypeReducer(types) {
      var message= 'value must be type of ' + types.join('|');
      var conditions= types.map(function(type){
        return 'a==="'+ type.toLowerCase()+'"';
      }).join('||');
  
      return new Function(
          'm',
          'return function(v, reject){var a= typeof v;if(!('+ conditions + '))reject(m);return v;}'
      )(message);
    }
  
    var functionReducer= makeTypeReducer(['function']);
    var objectFunctionReducer= makeTypeReducer(['object', 'function']);
  
    function makeCancelablePromise(Promise, executor, options) {
      var isCancelable;
      var callbacks;
      var timer= 0;
      var subscribeClosed;
  
      var promise = new Promise(function (resolve, reject, onCancel) {
        options= resolveOptions(options, {
          timeout: 0,
          overload: false
        }, {
          timeout: function(value, reject){
            value*= 1;
            if (typeof value !== 'number' || value < 0 || !Number.isFinite(value)) {
              reject('timeout must be a positive number');
            }
            return value;
          }
        });
  
        isCancelable = !options.overload && typeof Promise.prototype.cancel === 'function' && typeof onCancel === 'function';
  
        function cleanup() {
          if (callbacks) {
            callbacks = null;
          }
          if (timer) {
            clearTimeout(timer);
            timer = 0;
          }
        }
  
        var _resolve= function(value){
          cleanup();
          resolve(value);
        };
  
        var _reject= function(err){
          cleanup();
          reject(err);
        };
  
        if (isCancelable) {
          executor(_resolve, _reject, onCancel);
        } else {
          callbacks = [function(reason){
            _reject(reason || Error('canceled'));
          }];
          executor(_resolve, _reject, function (cb) {
            if (subscribeClosed) {
              throw Error('Unable to subscribe on cancel event asynchronously')
            }
            if (typeof cb !== 'function') {
              throw TypeError('onCancel callback must be a function');
            }
            callbacks.push(cb);
          });
          subscribeClosed= true;
        }
  
        if (options.timeout > 0) {
          timer= setTimeout(function(){
            var reason= Error('timeout');
            timer= 0;
            promise.cancel(reason);
            reject(reason);
          }, options.timeout);
        }
      });
  
      if (!isCancelable) {
        promise.cancel = function (reason) {
          if (!callbacks) {
            return;
          }
          var length = callbacks.length;
          for (var i = 1; i < length; i++) {
            callbacks[i](reason);
          }
          // internal callback to reject the promise
          callbacks[0](reason);
          callbacks = null;
        };
      }
  
      return promise;
    }
  
    function findTargetIndex(observer) {
      var observers = this._observers;
      if(!observers){
        return -1;
      }
      var len = observers.length;
      for (var i = 0; i < len; i++) {
        if (observers[i]._target === observer) return i;
      }
      return -1;
    }
  
    // Attention, function return type now is array, always !
    // It has zero elements if no any matches found and one or more
    // elements (leafs) if there are matches
    //
    function searchListenerTree(handlers, type, tree, i) {
      if (!tree) {
        return [];
      }
      var listeners=[], leaf, len, branch, xTree, xxTree, isolatedBranch, endReached,
          typeLength = type.length, currentType = type[i], nextType = type[i+1];
      if (i === typeLength && tree._listeners) {
        //
        // If at the end of the event(s) list and the tree has listeners
        // invoke those listeners.
        //
        if (typeof tree._listeners === 'function') {
          handlers && handlers.push(tree._listeners);
          return [tree];
        } else {
          for (leaf = 0, len = tree._listeners.length; leaf < len; leaf++) {
            handlers && handlers.push(tree._listeners[leaf]);
          }
          return [tree];
        }
      }
  
      if ((currentType === '*' || currentType === '**') || tree[currentType]) {
        //
        // If the event emitted is '*' at this part
        // or there is a concrete match at this patch
        //
        if (currentType === '*') {
          for (branch in tree) {
            if (branch !== '_listeners' && tree.hasOwnProperty(branch)) {
              listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i+1));
            }
          }
          return listeners;
        } else if(currentType === '**') {
          endReached = (i+1 === typeLength || (i+2 === typeLength && nextType === '*'));
          if(endReached && tree._listeners) {
            // The next element has a _listeners, add it to the handlers.
            listeners = listeners.concat(searchListenerTree(handlers, type, tree, typeLength));
          }
  
          for (branch in tree) {
            if (branch !== '_listeners' && tree.hasOwnProperty(branch)) {
              if(branch === '*' || branch === '**') {
                if(tree[branch]._listeners && !endReached) {
                  listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], typeLength));
                }
                listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i));
              } else if(branch === nextType) {
                listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i+2));
              } else {
                // No match on this one, shift into the tree but not in the type array.
                listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i));
              }
            }
          }
          return listeners;
        }
  
        listeners = listeners.concat(searchListenerTree(handlers, type, tree[currentType], i+1));
      }
  
      xTree = tree['*'];
      if (xTree) {
        //
        // If the listener tree will allow any match for this part,
        // then recursively explore all branches of the tree
        //
        searchListenerTree(handlers, type, xTree, i+1);
      }
  
      xxTree = tree['**'];
      if(xxTree) {
        if(i < typeLength) {
          if(xxTree._listeners) {
            // If we have a listener on a '**', it will catch all, so add its handler.
            searchListenerTree(handlers, type, xxTree, typeLength);
          }
  
          // Build arrays of matching next branches and others.
          for(branch in xxTree) {
            if(branch !== '_listeners' && xxTree.hasOwnProperty(branch)) {
              if(branch === nextType) {
                // We know the next element will match, so jump twice.
                searchListenerTree(handlers, type, xxTree[branch], i+2);
              } else if(branch === currentType) {
                // Current node matches, move into the tree.
                searchListenerTree(handlers, type, xxTree[branch], i+1);
              } else {
                isolatedBranch = {};
                isolatedBranch[branch] = xxTree[branch];
                searchListenerTree(handlers, type, { '**': isolatedBranch }, i+1);
              }
            }
          }
        } else if(xxTree._listeners) {
          // We have reached the end and still on a '**'
          searchListenerTree(handlers, type, xxTree, typeLength);
        } else if(xxTree['*'] && xxTree['*']._listeners) {
          searchListenerTree(handlers, type, xxTree['*'], typeLength);
        }
      }
  
      return listeners;
    }
  
    function growListenerTree(type, listener) {
  
      type = typeof type === 'string' ? type.split(this.delimiter) : type.slice();
  
      //
      // Looks for two consecutive '**', if so, don't add the event at all.
      //
      for (var i = 0, len = type.length; i + 1 < len; i++) {
        if (type[i] === '**' && type[i + 1] === '**') {
          return;
        }
      }
  
      var tree = this.listenerTree;
      var name = type.shift();
  
      while (name !== undefined) {
  
        if (!tree[name]) {
          tree[name] = {};
        }
  
        tree = tree[name];
  
        if (type.length === 0) {
  
          if (!tree._listeners) {
            tree._listeners = listener;
          } else {
            if (typeof tree._listeners === 'function') {
              tree._listeners = [tree._listeners];
            }
  
            tree._listeners.push(listener);
  
            if (
                !tree._listeners.warned &&
                this._maxListeners > 0 &&
                tree._listeners.length > this._maxListeners
            ) {
              tree._listeners.warned = true;
              logPossibleMemoryLeak.call(this, tree._listeners.length, name);
            }
          }
          return true;
        }
        name = type.shift();
      }
      return true;
    }
  
    function collectTreeEvents(tree, events, root, asArray){
       var branches= ownKeys(tree);
       var i= branches.length;
       var branch, branchName, path;
       var hasListeners= tree['_listeners'];
       var isArrayPath;
  
       while(i-->0){
           branchName= branches[i];
  
           branch= tree[branchName];
  
           if(branchName==='_listeners'){
               path= root;
           }else {
               path = root ? root.concat(branchName) : [branchName];
           }
  
           isArrayPath= asArray || typeof branchName==='symbol';
  
           hasListeners && events.push(isArrayPath? path : path.join(this.delimiter));
  
           if(typeof branch==='object'){
               collectTreeEvents.call(this, branch, events, path, isArrayPath);
           }
       }
  
       return events;
    }
  
    function recursivelyGarbageCollect(root) {
      var keys = ownKeys(root);
      var i= keys.length;
      var obj, key, flag;
      while(i-->0){
        key = keys[i];
        obj = root[key];
  
        if(obj){
            flag= true;
            if(key !== '_listeners' && !recursivelyGarbageCollect(obj)){
               delete root[key];
            }
        }
      }
  
      return flag;
    }
  
    function Listener(emitter, event, listener){
      this.emitter= emitter;
      this.event= event;
      this.listener= listener;
    }
  
    Listener.prototype.off= function(){
      this.emitter.off(this.event, this.listener);
      return this;
    };
  
    function setupListener(event, listener, options){
        if (options === true) {
          promisify = true;
        } else if (options === false) {
          async = true;
        } else {
          if (!options || typeof options !== 'object') {
            throw TypeError('options should be an object or true');
          }
          var async = options.async;
          var promisify = options.promisify;
          var nextTick = options.nextTick;
          var objectify = options.objectify;
        }
  
        if (async || nextTick || promisify) {
          var _listener = listener;
          var _origin = listener._origin || listener;
  
          if (nextTick && !nextTickSupported) {
            throw Error('process.nextTick is not supported');
          }
  
          if (promisify === undefined) {
            promisify = listener.constructor.name === 'AsyncFunction';
          }
  
          listener = function () {
            var args = arguments;
            var context = this;
            var event = this.event;
  
            return promisify ? (nextTick ? Promise.resolve() : new Promise(function (resolve) {
              _setImmediate(resolve);
            }).then(function () {
              context.event = event;
              return _listener.apply(context, args)
            })) : (nextTick ? process.nextTick : _setImmediate)(function () {
              context.event = event;
              _listener.apply(context, args)
            });
          };
  
          listener._async = true;
          listener._origin = _origin;
        }
  
      return [listener, objectify? new Listener(this, event, listener): this];
    }
  
    function EventEmitter(conf) {
      this._events = {};
      this._newListener = false;
      this._removeListener = false;
      this.verboseMemoryLeak = false;
      configure.call(this, conf);
    }
  
    EventEmitter.EventEmitter2 = EventEmitter; // backwards compatibility for exporting EventEmitter property
  
    EventEmitter.prototype.listenTo= function(target, events, options){
      if(typeof target!=='object'){
        throw TypeError('target musts be an object');
      }
  
      var emitter= this;
  
      options = resolveOptions(options, {
        on: undefined,
        off: undefined,
        reducers: undefined
      }, {
        on: functionReducer,
        off: functionReducer,
        reducers: objectFunctionReducer
      });
  
      function listen(events){
        if(typeof events!=='object'){
          throw TypeError('events must be an object');
        }
  
        var reducers= options.reducers;
        var index= findTargetIndex.call(emitter, target);
        var observer;
  
        if(index===-1){
          observer= new TargetObserver(emitter, target, options);
        }else{
          observer= emitter._observers[index];
        }
  
        var keys= ownKeys(events);
        var len= keys.length;
        var event;
        var isSingleReducer= typeof reducers==='function';
  
        for(var i=0; i<len; i++){
          event= keys[i];
          observer.subscribe(
              event,
              events[event] || event,
              isSingleReducer ? reducers : reducers && reducers[event]
          );
        }
      }
  
      isArray(events)?
          listen(toObject(events)) :
          (typeof events==='string'? listen(toObject(events.split(/\s+/))): listen(events));
  
      return this;
    };
  
    EventEmitter.prototype.stopListeningTo = function (target, event) {
      var observers = this._observers;
  
      if(!observers){
        return false;
      }
  
      var i = observers.length;
      var observer;
      var matched= false;
  
      if(target && typeof target!=='object'){
        throw TypeError('target should be an object');
      }
  
      while (i-- > 0) {
        observer = observers[i];
        if (!target || observer._target === target) {
          observer.unsubscribe(event);
          matched= true;
        }
      }
  
      return matched;
    };
  
    // 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.
  
    EventEmitter.prototype.delimiter = '.';
  
    EventEmitter.prototype.setMaxListeners = function(n) {
      if (n !== undefined) {
        this._maxListeners = n;
        if (!this._conf) this._conf = {};
        this._conf.maxListeners = n;
      }
    };
  
    EventEmitter.prototype.getMaxListeners = function() {
      return this._maxListeners;
    };
  
    EventEmitter.prototype.event = '';
  
    EventEmitter.prototype.once = function(event, fn, options) {
      return this._once(event, fn, false, options);
    };
  
    EventEmitter.prototype.prependOnceListener = function(event, fn, options) {
      return this._once(event, fn, true, options);
    };
  
    EventEmitter.prototype._once = function(event, fn, prepend, options) {
      return this._many(event, 1, fn, prepend, options);
    };
  
    EventEmitter.prototype.many = function(event, ttl, fn, options) {
      return this._many(event, ttl, fn, false, options);
    };
  
    EventEmitter.prototype.prependMany = function(event, ttl, fn, options) {
      return this._many(event, ttl, fn, true, options);
    };
  
    EventEmitter.prototype._many = function(event, ttl, fn, prepend, options) {
      var self = this;
  
      if (typeof fn !== 'function') {
        throw new Error('many only accepts instances of Function');
      }
  
      function listener() {
        if (--ttl === 0) {
          self.off(event, listener);
        }
        return fn.apply(this, arguments);
      }
  
      listener._origin = fn;
  
      return this._on(event, listener, prepend, options);
    };
  
    EventEmitter.prototype.emit = function() {
      if (!this._events && !this._all) {
        return false;
      }
  
      this._events || init.call(this);
  
      var type = arguments[0], ns, wildcard= this.wildcard, kind;
      var args,l,i,j, containsSymbol;
  
      if (type === 'newListener' && !this._newListener) {
        if (!this._events.newListener) {
          return false;
        }
      }
  
      if (wildcard) {
        kind = typeof type;
        if (kind === 'string') {
          ns = type.split(this.delimiter);
        } else {
          if(kind==='symbol'){
            ns= [type];
          }else{
            ns = type.slice();
            l= type.length;
            if(symbolsSupported) {
              for (i = 0; i < l; i++) {
                if (typeof type[i] === 'symbol') {
                  containsSymbol = true;
                  break;
                }
              }
            }
            if(!containsSymbol){
              type = type.join(this.delimiter);
            }
          }
        }
      }
  
      var al = arguments.length;
      var handler;
  
      if (this._all && this._all.length) {
        handler = this._all.slice();
  
        for (i = 0, l = handler.length; i < l; i++) {
          this.event = type;
          switch (al) {
          case 1:
            handler[i].call(this, type);
            break;
          case 2:
            handler[i].call(this, type, arguments[1]);
            break;
          case 3:
            handler[i].call(this, type, arguments[1], arguments[2]);
            break;
          default:
            handler[i].apply(this, arguments);
          }
        }
      }
  
      if (wildcard) {
        handler = [];
        searchListenerTree.call(this, handler, ns, this.listenerTree, 0);
      } else {
        handler = this._events[type];
        if (typeof handler === 'function') {
          this.event = type;
          switch (al) {
          case 1:
            handler.call(this);
            break;
          case 2:
            handler.call(this, arguments[1]);
            break;
          case 3:
            handler.call(this, arguments[1], arguments[2]);
            break;
          default:
            args = new Array(al - 1);
            for (j = 1; j < al; j++) args[j - 1] = arguments[j];
            handler.apply(this, args);
          }
          return true;
        } else if (handler) {
          // need to make copy of handlers because list can change in the middle
          // of emit call
          handler = handler.slice();
        }
      }
  
      if (handler && handler.length) {
        if (al > 3) {
          args = new Array(al - 1);
          for (j = 1; j < al; j++) args[j - 1] = arguments[j];
        }
        for (i = 0, l = handler.length; i < l; i++) {
          this.event = type;
          switch (al) {
          case 1:
            handler[i].call(this);
            break;
          case 2:
            handler[i].call(this, arguments[1]);
            break;
          case 3:
            handler[i].call(this, arguments[1], arguments[2]);
            break;
          default:
            handler[i].apply(this, args);
          }
        }
        return true;
      } else if (!this.ignoreErrors && !this._all && type === 'error') {
        if (arguments[1] instanceof Error) {
          throw arguments[1]; // Unhandled 'error' event
        } else {
          throw new Error("Uncaught, unspecified 'error' event.");
        }
      }
  
      return !!this._all;
    };
  
    EventEmitter.prototype.emitAsync = function() {
      if (!this._events && !this._all) {
        return false;
      }
  
      this._events || init.call(this);
  
      var type = arguments[0], wildcard= this.wildcard, ns, kind, containsSymbol;
      var args,l,i,j;
  
      if (type === 'newListener' && !this._newListener) {
          if (!this._events.newListener) { return Promise.resolve([false]); }
      }
  
      if (wildcard) {
        kind = typeof type;
        if (kind === 'string') {
          ns = type.split(this.delimiter);
        } else {
          if(kind==='symbol'){
            ns= [type];
          }else{
            ns = type.slice();
            l= type.length;
            if(symbolsSupported) {
              for (i = 0; i < l; i++) {
                if (typeof type[i] === 'symbol') {
                  containsSymbol = true;
                  break;
                }
              }
            }
            if(!containsSymbol){
              type = type.join(this.delimiter);
            }
          }
        }
      }
  
      var promises= [];
  
      var al = arguments.length;
      var handler;
  
      if (this._all) {
        for (i = 0, l = this._all.length; i < l; i++) {
          this.event = type;
          switch (al) {
          case 1:
            promises.push(this._all[i].call(this, type));
            break;
          case 2:
            promises.push(this._all[i].call(this, type, arguments[1]));
            break;
          case 3:
            promises.push(this._all[i].call(this, type, arguments[1], arguments[2]));
            break;
          default:
            promises.push(this._all[i].apply(this, arguments));
          }
        }
      }
  
      if (wildcard) {
        handler = [];
        searchListenerTree.call(this, handler, ns, this.listenerTree, 0);
      } else {
        handler = this._events[type];
      }
  
      if (typeof handler === 'function') {
        this.event = type;
        switch (al) {
        case 1:
          promises.push(handler.call(this));
          break;
        case 2:
          promises.push(handler.call(this, arguments[1]));
          break;
        case 3:
          promises.push(handler.call(this, arguments[1], arguments[2]));
          break;
        default:
          args = new Array(al - 1);
          for (j = 1; j < al; j++) args[j - 1] = arguments[j];
          promises.push(handler.apply(this, args));
        }
      } else if (handler && handler.length) {
        handler = handler.slice();
        if (al > 3) {
          args = new Array(al - 1);
          for (j = 1; j < al; j++) args[j - 1] = arguments[j];
        }
        for (i = 0, l = handler.length; i < l; i++) {
          this.event = type;
          switch (al) {
          case 1:
            promises.push(handler[i].call(this));
            break;
          case 2:
            promises.push(handler[i].call(this, arguments[1]));
            break;
          case 3:
            promises.push(handler[i].call(this, arguments[1], arguments[2]));
            break;
          default:
            promises.push(handler[i].apply(this, args));
          }
        }
      } else if (!this.ignoreErrors && !this._all && type === 'error') {
        if (arguments[1] instanceof Error) {
          return Promise.reject(arguments[1]); // Unhandled 'error' event
        } else {
          return Promise.reject("Uncaught, unspecified 'error' event.");
        }
      }
  
      return Promise.all(promises);
    };
  
    EventEmitter.prototype.on = function(type, listener, options) {
      return this._on(type, listener, false, options);
    };
  
    EventEmitter.prototype.prependListener = function(type, listener, options) {
      return this._on(type, listener, true, options);
    };
  
    EventEmitter.prototype.onAny = function(fn) {
      return this._onAny(fn, false);
    };
  
    EventEmitter.prototype.prependAny = function(fn) {
      return this._onAny(fn, true);
    };
  
    EventEmitter.prototype.addListener = EventEmitter.prototype.on;
  
    EventEmitter.prototype._onAny = function(fn, prepend){
      if (typeof fn !== 'function') {
        throw new Error('onAny only accepts instances of Function');
      }
  
      if (!this._all) {
        this._all = [];
      }
  
      // Add the function to the event listener collection.
      if(prepend){
        this._all.unshift(fn);
      }else{
        this._all.push(fn);
      }
  
      return this;
    };
  
    EventEmitter.prototype._on = function(type, listener, prepend, options) {
      if (typeof type === 'function') {
        this._onAny(type, listener);
        return this;
      }
  
      if (typeof listener !== 'function') {
        throw new Error('on only accepts instances of Function');
      }
      this._events || init.call(this);
  
      var returnValue= this, temp;
  
      if (options !== undefined) {
        temp = setupListener.call(this, type, listener, options);
        listener = temp[0];
        returnValue = temp[1];
      }
  
      // To avoid recursion in the case that type == "newListeners"! Before
      // adding it to the listeners, first emit "newListeners".
      if (this._newListener) {
        this.emit('newListener', type, listener);
      }
  
      if (this.wildcard) {
        growListenerTree.call(this, type, listener);
        return this;
      }
  
      if (!this._events[type]) {
        // Optimize the case of one listener. Don't need the extra array object.
        this._events[type] = listener;
      } else {
        if (typeof this._events[type] === 'function') {
          // Change to array.
          this._events[type] = [this._events[type]];
        }
  
        // If we've already got an array, just add
        if(prepend){
          this._events[type].unshift(listener);
        }else{
          this._events[type].push(listener);
        }
  
        // Check for listener leak
        if (
          !this._events[type].warned &&
          this._maxListeners > 0 &&
          this._events[type].length > this._maxListeners
        ) {
          this._events[type].warned = true;
          logPossibleMemoryLeak.call(this, this._events[type].length, type);
        }
      }
  
      return returnValue;
    };
  
    EventEmitter.prototype.off = function(type, listener) {
      if (typeof listener !== 'function') {
        throw new Error('removeListener only takes instances of Function');
      }
  
      var handlers,leafs=[];
  
      if(this.wildcard) {
        var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice();
        leafs = searchListenerTree.call(this, null, ns, this.listenerTree, 0);
      }
      else {
        // does not use listeners(), so no side effect of creating _events[type]
        if (!this._events[type]) return this;
        handlers = this._events[type];
        leafs.push({_listeners:handlers});
      }
  
      for (var iLeaf=0; iLeaf<leafs.length; iLeaf++) {
        var leaf = leafs[iLeaf];
        handlers = leaf._listeners;
        if (isArray(handlers)) {
  
          var position = -1;
  
          for (var i = 0, length = handlers.length; i < length; i++) {
            if (handlers[i] === listener ||
              (handlers[i].listener && handlers[i].listener === listener) ||
              (handlers[i]._origin && handlers[i]._origin === listener)) {
              position = i;
              break;
            }
          }
  
          if (position < 0) {
            continue;
          }
  
          if(this.wildcard) {
            leaf._listeners.splice(position, 1);
          }
          else {
            this._events[type].splice(position, 1);
          }
  
          if (handlers.length === 0) {
            if(this.wildcard) {
              delete leaf._listeners;
            }
            else {
              delete this._events[type];
            }
          }
          if (this._removeListener)
            this.emit("removeListener", type, listener);
  
          return this;
        }
        else if (handlers === listener ||
          (handlers.listener && handlers.listener === listener) ||
          (handlers._origin && handlers._origin === listener)) {
          if(this.wildcard) {
            delete leaf._listeners;
          }
          else {
            delete this._events[type];
          }
          if (this._removeListener)
            this.emit("removeListener", type, listener);
        }
      }
  
      this.listenerTree && recursivelyGarbageCollect(this.listenerTree);
  
      return this;
    };
  
    EventEmitter.prototype.offAny = function(fn) {
      var i = 0, l = 0, fns;
      if (fn && this._all && this._all.length > 0) {
        fns = this._all;
        for(i = 0, l = fns.length; i < l; i++) {
          if(fn === fns[i]) {
            fns.splice(i, 1);
            if (this._removeListener)
              this.emit("removeListenerAny", fn);
            return this;
          }
        }
      } else {
        fns = this._all;
        if (this._removeListener) {
          for(i = 0, l = fns.length; i < l; i++)
            this.emit("removeListenerAny", fns[i]);
        }
        this._all = [];
      }
      return this;
    };
  
    EventEmitter.prototype.removeListener = EventEmitter.prototype.off;
  
    EventEmitter.prototype.removeAllListeners = function (type) {
      if (type === undefined) {
        !this._events || init.call(this);
        return this;
      }
  
      if (this.wildcard) {
        var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice();
        var leafs = searchListenerTree.call(this, null, ns, this.listenerTree, 0);
  
        for (var iLeaf = 0; iLeaf < leafs.length; iLeaf++) {
          var leaf = leafs[iLeaf];
          leaf._listeners = null;
        }
        this.listenerTree && recursivelyGarbageCollect(this.listenerTree);
      } else if (this._events) {
        this._events[type] = null;
      }
      return this;
    };
  
    EventEmitter.prototype.listeners = function (type) {
      var _events = this._events;
      var keys, listeners, allListeners;
      var i;
      var listenerTree;
  
      if (type === undefined) {
        if (this.wildcard) {
          throw Error('event name required for wildcard emitter');
        }
  
        if (!_events) {
          return [];
        }
  
        keys = ownKeys(_events);
        i = keys.length;
        allListeners = [];
        while (i-- > 0) {
          listeners = _events[keys[i]];
          if (typeof listeners === 'function') {
            allListeners.push(listeners);
          } else {
            allListeners.push.apply(allListeners, listeners);
          }
        }
        return allListeners;
      } else {
        if (this.wildcard) {
          listenerTree= this.listenerTree;
          if(!listenerTree) return [];
          var handlers = [];
          var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice();
          searchListenerTree.call(this, handlers, ns, listenerTree, 0);
          return handlers;
        }
  
        if (!_events) {
          return [];
        }
  
        listeners = _events[type];
  
        if (!listeners) {
          return [];
        }
        return typeof listeners === 'function' ? [listeners] : listeners;
      }
    };
  
    EventEmitter.prototype.eventNames = function(nsAsArray){
      var _events= this._events;
      return this.wildcard? collectTreeEvents.call(this, this.listenerTree, [], null, nsAsArray) : (_events? ownKeys(_events) : []);
    };
  
    EventEmitter.prototype.listenerCount = function(type) {
      return this.listeners(type).length;
    };
  
    EventEmitter.prototype.hasListeners = function (type) {
      if (this.wildcard) {
        var handlers = [];
        var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice();
        searchListenerTree.call(this, handlers, ns, this.listenerTree, 0);
        return handlers.length > 0;
      }
  
      var _events = this._events;
      var _all = this._all;
  
      return !!(_all && _all.length || _events && (type === undefined ? ownKeys(_events).length : _events[type]));
    };
  
    EventEmitter.prototype.listenersAny = function() {
  
      if(this._all) {
        return this._all;
      }
      else {
        return [];
      }
  
    };
  
    EventEmitter.prototype.waitFor = function (event, options) {
      var self = this;
      var type = typeof options;
      if (type === 'number') {
        options = {timeout: options};
      } else if (type === 'function') {
        options = {filter: options};
      }
  
      options= resolveOptions(options, {
        timeout: 0,
        filter: undefined,
        handleError: false,
        Promise: Promise,
        overload: false
      }, {
        filter: functionReducer,
        Promise: constructorReducer
      });
  
      return makeCancelablePromise(options.Promise, function (resolve, reject, onCancel) {
        function listener() {
          var filter= options.filter;
          if (filter && !filter.apply(self, arguments)) {
            return;
          }
          if (options.handleError) {
            var err = arguments[0];
            err ? reject(err) : resolve(toArray.apply(null, arguments).slice(1));
          } else {
            resolve(toArray.apply(null, arguments));
          }
        }
  
        onCancel(function(){
          self.off(event, listener);
        });
  
        self._on(event, listener, false);
      }, {
        timeout: options.timeout,
        overload: options.overload
      })
    };
  
    function once(emitter, name, options) {
      options= resolveOptions(options, {
        Promise: Promise,
        timeout: 0,
        overload: false
      }, {
        Promise: constructorReducer
      });
  
      var _Promise= options.Promise;
  
      return makeCancelablePromise(_Promise, function(resolve, reject, onCancel){
        var handler;
        if (typeof emitter.addEventListener === 'function') {
          handler=  function () {
            resolve(toArray.apply(null, arguments));
          };
  
          onCancel(function(){
            emitter.removeEventListener(name, handler);
          });
  
          emitter.addEventListener(
              name,
              handler,
              {once: true}
          );
          return;
        }
  
        var eventListener = function(){
          errorListener && emitter.removeListener('error', errorListener);
          resolve(toArray.apply(null, arguments));
        };
  
        var errorListener;
  
        if (name !== 'error') {
          errorListener = function (err){
            emitter.removeListener(name, eventListener);
            reject(err);
          };
  
          emitter.once('error', errorListener);
        }
  
        onCancel(function(){
          errorListener && emitter.removeListener('error', errorListener);
          emitter.removeListener(name, eventListener);
        });
  
        emitter.once(name, eventListener);
      }, {
        timeout: options.timeout,
        overload: options.overload
      });
    }
  
    var prototype= EventEmitter.prototype;
  
    Object.defineProperties(EventEmitter, {
      defaultMaxListeners: {
        get: function () {
          return prototype._maxListeners;
        },
        set: function (n) {
          if (typeof n !== 'number' || n < 0 || Number.isNaN(n)) {
            throw TypeError('n must be a non-negative number')
          }
          prototype._maxListeners = n;
        },
        enumerable: true
      },
      once: {
        value: once,
        writable: true,
        configurable: true
      }
    });
  
    Object.defineProperties(prototype, {
        _maxListeners: {
            value: defaultMaxListeners,
            writable: true,
            configurable: true
        },
        _observers: {value: null, writable: true, configurable: true}
    });
  
    if (typeof define === 'function' && define.amd) {
       // AMD. Register as an anonymous module.
      define(function() {
        return EventEmitter;
      });
    } else if (typeof exports === 'object') {
      // CommonJS
      module.exports = EventEmitter;
    }
    else {
      // global for any kind of environment.
      var _global= new Function('','return this')();
      _global.EventEmitter2 = EventEmitter;
    }
  }();
  