text: var q = require('q');
  var webdriver = require('selenium-webdriver');
  
  var RunnerReporter = function(emitter) {
    this.emitter = emitter;
    this.testResult = [],
    this.failedCount = 0;
  };
  
  RunnerReporter.prototype.jasmineStarted = function() {
    // Need to initiate startTime here, in case reportSpecStarting is not
    // called (e.g. when fit is used)
    this.startTime = new Date();
  };
  
  RunnerReporter.prototype.specStarted = function() {
    this.startTime = new Date();
  };
  
  RunnerReporter.prototype.specDone = function(result) {
    var specInfo = {
      name: result.description,
      category: result.fullName.slice(0, -result.description.length).trim()
    };
    if (result.status == 'passed') {
      this.emitter.emit('testPass', specInfo);
    } else if (result.status == 'failed') {
      this.emitter.emit('testFail', specInfo);
      this.failedCount++;
    }
  
    var entry = {
      description: result.fullName,
      assertions: [],
      duration: new Date().getTime() - this.startTime.getTime()
    };
  
    if (result.failedExpectations.length === 0) {
      entry.assertions.push({
        passed: true
      });
    }
  
    result.failedExpectations.forEach(function(item) {
      entry.assertions.push({
        passed: item.passed,
        errorMsg: item.passed ? undefined : item.message,
        stackTrace: item.passed ? undefined : item.stack
      });
    });
    this.testResult.push(entry);
  };
  
  /**
   * Execute the Runner's test cases through Jasmine.
   *
   * @param {Runner} runner The current Protractor Runner.
   * @param {Array} specs Array of Directory Path Strings.
   * @return {q.Promise} Promise resolved with the test results
   */
  exports.run = function(runner, specs) {
    var JasmineRunner = require('jasmine');
    var jrunner = new JasmineRunner();
    /* global jasmine */
  
    require('jasminewd2').init(webdriver.promise.controlFlow(), webdriver);
  
    var jasmineNodeOpts = runner.getConfig().jasmineNodeOpts;
  
    // On timeout, the flow should be reset. This will prevent webdriver tasks
    // from overflowing into the next test and causing it to fail or timeout
    // as well. This is done in the reporter instead of an afterEach block
    // to ensure that it runs after any afterEach() blocks with webdriver tasks
    // get to complete first.
    var reporter = new RunnerReporter(runner);
    jasmine.getEnv().addReporter(reporter);
  
    // Add hooks for afterEach
    require('./setupAfterEach').setup(runner, specs);
  
    // Filter specs to run based on jasmineNodeOpts.grep and jasmineNodeOpts.invert.
    jasmine.getEnv().specFilter = function(spec) {
      var grepMatch = !jasmineNodeOpts ||
          !jasmineNodeOpts.grep ||
          spec.getFullName().match(new RegExp(jasmineNodeOpts.grep)) != null;
      var invertGrep = !!(jasmineNodeOpts && jasmineNodeOpts.invertGrep);
      if (grepMatch == invertGrep) {
        spec.disable();
      }
      return true;
    };
  
    // Run specs in semi-random order
    if (jasmineNodeOpts.random) {
      jasmine.getEnv().randomizeTests(true);
  
      // Sets the randomization seed if randomization is turned on
      if (jasmineNodeOpts.seed) {
        jasmine.getEnv().seed(jasmineNodeOpts.seed);
      }
    }
  
    return runner.runTestPreparer().then(function() {
      return q.promise(function(resolve, reject) {
        if (jasmineNodeOpts && jasmineNodeOpts.defaultTimeoutInterval) {
          jasmine.DEFAULT_TIMEOUT_INTERVAL = jasmineNodeOpts.defaultTimeoutInterval;
        }
  
        var originalOnComplete = runner.getConfig().onComplete;
  
        jrunner.onComplete(function(passed) {
          try {
            var completed = q();
            if (originalOnComplete) {
              completed = q(originalOnComplete(passed));
            }
            completed.then(function() {
              resolve({
                failedCount: reporter.failedCount,
                specResults: reporter.testResult
              });
            });
          } catch (err) {
            reject(err);
          }
        });
  
        jrunner.configureDefaultReporter(jasmineNodeOpts);
        jrunner.projectBaseDir = '';
        jrunner.specDir = '';
        jrunner.addSpecFiles(specs);
        jrunner.execute();
      });
    });
  };
  