text: /*
   * Copyright 2020 New Relic Corporation. All rights reserved.
   * SPDX-License-Identifier: Apache-2.0
   */
  
  var ctxId = 'nr@context'
  var getOrSet = require('gos')
  var mapOwn = require('map-own')
  
  var eventBuffer = {}
  var emitters = {}
  
  var baseEE = module.exports = ee()
  module.exports.getOrSetContext = getOrSetContext
  
  baseEE.backlog = eventBuffer
  
  function EventContext () {}
  
  function ee (old) {
    var handlers = {}
    var bufferGroupMap = {}
  
    var emitter = {
      on: addEventListener,
      addEventListener: addEventListener,
      removeEventListener: removeEventListener,
      emit: emit,
      get: getOrCreate,
      listeners: listeners,
      context: context,
      buffer: bufferEventsByGroup,
      abort: abortIfNotLoaded,
      aborted: false
    }
  
    return emitter
  
    function context (contextOrStore) {
      if (contextOrStore && contextOrStore instanceof EventContext) {
        return contextOrStore
      } else if (contextOrStore) {
        return getOrSet(contextOrStore, ctxId, getNewContext)
      } else {
        return getNewContext()
      }
    }
  
    function emit (type, args, contextOrStore, force, bubble) {
      if (bubble !== false) bubble = true
      if (baseEE.aborted && !force) { return }
      if (old && bubble) old(type, args, contextOrStore)
  
      var ctx = context(contextOrStore)
      var handlersArray = listeners(type)
      var len = handlersArray.length
  
      // Extremely verbose debug logging
      // if ([/^xhr/].map(function (match) {return type.match(match)}).filter(Boolean).length) {
      //  console.log(type + ' args:')
      //  console.log(args)
      //  console.log(type + ' handlers array:')
      //  console.log(handlersArray)
      //  console.log(type + ' context:')
      //  console.log(ctx)
      //  console.log(type + ' ctxStore:')
      //  console.log(ctxStore)
      // }
  
      // Apply each handler function in the order they were added
      // to the context with the arguments
  
      for (var i = 0; i < len; i++) handlersArray[i].apply(ctx, args)
  
      // Buffer after emitting for consistent ordering
      var bufferGroup = eventBuffer[bufferGroupMap[type]]
      if (bufferGroup) {
        bufferGroup.push([emitter, type, args, ctx])
      }
  
      // Return the context so that the module that emitted can see what was done.
      return ctx
    }
  
    function addEventListener (type, fn) {
      // Retrieve type from handlers, if it doesn't exist assign the default and retrieve it.
      handlers[type] = listeners(type).concat(fn)
    }
  
    function removeEventListener (type, fn) {
      var listeners = handlers[type]
      if (!listeners) return
      for (var i = 0; i < listeners.length; i++) {
        if (listeners[i] === fn) {
          listeners.splice(i, 1)
        }
      }
    }
  
    function listeners (type) {
      return handlers[type] || []
    }
  
    function getOrCreate (name) {
      return (emitters[name] = emitters[name] || ee(emit))
    }
  
    function bufferEventsByGroup (types, group) {
      // do not buffer events if agent has been aborted
      if (baseEE.aborted) return
      mapOwn(types, function (i, type) {
        group = group || 'feature'
        bufferGroupMap[type] = group
        if (!(group in eventBuffer)) {
          eventBuffer[group] = []
        }
      })
    }
  }
  
  // get context object from store object, or create if does not exist
  function getOrSetContext(obj) {
    return getOrSet(obj, ctxId, getNewContext)
  }
  
  function getNewContext () {
    return new EventContext()
  }
  
  // abort should be called 30 seconds after the page has started running
  // We should drop our data and stop collecting if we still have a backlog, which
  // signifies the rest of the agent wasn't loaded
  function abortIfNotLoaded () {
    if (eventBuffer.api || eventBuffer.feature) {
      baseEE.aborted = true
      eventBuffer = baseEE.backlog = {}
    }
  }
  