docs: function sendNotifications(userId, channels, payload, callback) {
      // is channel list restricted?
      if (arguments.length < 4) {
          callback = payload
          payload  = channels
          channels = this._plugins
      }
      else
          channels = only(this._plugins, words(channels))
  
      // helper for decorating error objects with debug info when possible
      // and storing them to pass back to the caller when we're done
      function failed(err, userId, channel, target) {
          if (err && typeof err === 'object') {
              err.userId  = userId
              err.channel = channel
              err.target  = target
          }
  
          errors.push(err)
          done()
      }
  
      // helper for counting finished operations and call back when we're done
      function done() {
          var arg = errors.length ? errors : null
          --pending || process.nextTick(callback, arg)
      }
  
      var self    = this,
          list    = Object.keys(channels),
          pending = list.length,
          errors  = []
  
      if (pending) {
          // iterate over the required channels
          list.forEach(function (name) {
              // apply payload transformation per channel
              self.transform(userId, name, payload, function (err, payload) {
                  if (err)
                      return failed(err, userId, name)
  
                  // get the targets for this channel
                  self.load(userId, name, function (err, targets) {
                      if (err)
                          return failed(err, userId, name)
  
                      if (!Array.isArray(targets))
                          targets = [ targets ]
                      else {
                          // dereference the original array,
                          // because that may not be trustworthy
                          targets = cloneArray(targets)
                      }
  
                      if (targets.length) {
                          // we're initiating operations for each target,
                          // so we need to update the counter
                          pending += targets.length - 1
                          // get the plugin corresponding to channel
                          var channel = channels[ name ]
  
                          targets.forEach(function (target) {
                              channel.send(target, payload, function (err) {
                                  if (err)
                                      failed(err, userId, name, target)
                                  else
                                      done()
                              })
                          })
                      }
                      else
                          done()
                  })
              })
          })
      }
      else {
          // no matching channels found,
          // so there is nothing to do here
          process.nextTick(callback, null)
      }
  
      // make it chainable
      return this
  }