static _notifyListenerGroup (lGroup, msg, transform, ws, chanData) {
    const [, eventName, data = []] = msg
    let filterByData

    // Catch-all can't filter/transform
    WSv2._notifyCatchAllListeners(lGroup, msg)

    if (!lGroup[eventName] || lGroup[eventName].length === 0) return

    const listeners = lGroup[eventName].filter((listener) => {
      const { filter } = listener

      if (!filter) return true

      // inspect snapshots for matching packets
      if (Array.isArray(data[0])) {
        const matchingData = data.filter((item) => {
          filterByData = msg.filterOverride ? msg.filterOverride : item

          return WSv2._payloadPassesFilter(filterByData, filter)
        })

        return matchingData.length !== 0
      }

      // inspect single packet
      filterByData = msg.filterOverride ? msg.filterOverride : data

      return WSv2._payloadPassesFilter(filterByData, filter)
    })

    if (listeners.length === 0) return

    listeners.forEach(({ cb, modelClass }) => {
      const ModelClass = modelClass

      if (!ModelClass || !transform || data.length === 0) {
        cb(data, chanData)
      } else if (Array.isArray(data[0])) {
        cb(data.map((entry) => {
          return new ModelClass(entry, ws)
        }), chanData)
      } else {
        cb(new ModelClass(data, ws), chanData)
      }
    })
  }
Applies filtering & transform to a packet before sending it out to matching
listeners in the group.

@param {object} lGroup - listener group to parse & notify
@param {object} msg - passed to each matched listener
@param {boolean} transform - whether or not to instantiate a model
@param {WSv2} ws - instance to pass to models if transforming
@param {object} chanData - channel data
@private