--------------------------------------------------------------------------- Class constructor. --------------------------------------------------------------------------- 
@class An object stream to list S3 objects via multiple concurrent requests.

This is considerably faster than S3ListObjectStream, but the level of
concurrency is limited by practical concerns. Aside from API throttling,
most ordinary machines start to exhibit failures with AWS SDKs at around 20
parallel requests.

It works by descending through 'directories' defined by splitting keys with
the delimiter. For each new 'subdirectory', a new task is spawned to list
it and its 'subdirectories'. Those tasks run in parallel up to the maximum
concurrency.

Pipe in objects of the following form:

{
s3Client: new AWS.S3(),
bucket: 'exampleBucket',
// Optional. Maximum degree of concurrency if there are many common
// prefixes. Defaults to 10.
maxConcurrency: 10,
// Optional. Used to find common prefixes that can be listed concurrently.
// Defaults to '/'.
delimiter: '/',
// Optional, defaults to 1000. How many objects to return in one API
// request under the hood.
maxKeys: 1000,
// Optional. If present, only list objects with keys matching the prefix.
prefix: 'examplePrefix'
}

Pipe out standard response objects from the S3 listObjects API, with the
addition of the bucket name as well.

{
Bucket: 'exampleBucket',
Key: ...
LastModified: ...
ETag: ...
Size: ...
StorageClass: ...
Owner: {
DisplayName: ...
ID: ...
}
}

@param {Object} options Standard stream options, plus the following.
@param {Number} [options.maxConcurrency] Defaults to 15. Number of
concurrent API requests to make.
function S3ConcurrentListObjectStream (options) {
  options = options || {};
  // Important; make this an object stream.
  options.objectMode = true;
  options.maxConcurrency = options.maxConcurrency || 15;

  // A queue for managing concurrency of API requests.
  this.queue = async.queue(
    this.listDirectoryAndRecuse.bind(this),
    options.maxConcurrency
  );

  S3ConcurrentListObjectStream.super_.call(this, options);
}