docs: function(config) {
    var excludes = ConfigParser.resolveFilePatterns(config.exclude, true, config.configDir);
    var allSpecs = ConfigParser.resolveFilePatterns(
        ConfigParser.getSpecs(config), false, config.configDir).filter(function(path) {
          return excludes.indexOf(path) < 0;
        });
  
    if (config.capabilities) {
      if (config.multiCapabilities.length) {
        console.log('Running using config.multiCapabilities - ' +
          'config.capabilities will be ignored');
      } else {
        // Use capabilities if multiCapabilities is empty.
        config.multiCapabilities = [config.capabilities];
      }
    } else if (!config.multiCapabilities.length) {
      // Default to chrome if no capability given
      config.multiCapabilities = [{
        browserName: 'chrome'
      }];
    }
  
    var taskQueues = [];
    config.multiCapabilities.forEach(function(capability) {
      var capabilitySpecs = allSpecs;
      if (capability.specs) {
        var capabilitySpecificSpecs = ConfigParser.resolveFilePatterns(
            capability.specs, false, config.configDir);
        capabilitySpecs = capabilitySpecs.concat(capabilitySpecificSpecs);
      }
  
      var specLists = [];
      // If we shard, we return an array of one element arrays, each containing 
      // the spec file. If we don't shard, we return an one element array 
      // containing an array of all the spec files
      if (capability.shardTestFiles) {
        capabilitySpecs.forEach(function(spec) {
          specLists.push([spec]);
        });
      } else {
        specLists.push(capabilitySpecs);
      }
  
      capability.count = capability.count || 1;
  
      for (var i = 0; i < capability.count; ++i) {
        taskQueues.push(new TaskQueue(capability, specLists));
      }
    });
    this.taskQueues = taskQueues;
    this.config = config;
    this.rotationIndex = 0; // Helps suggestions to rotate amongst capabilities
  }