text: var repl = require('repl');
  var debuggerCommons = require('../debuggerCommons');
  var CommandRepl = require('../modes/commandRepl');
  var DebuggerRepl = require('../modes/debuggerRepl');
  
  /**
   * BETA BETA BETA
   * Custom protractor debugger which steps through one control flow task
   * at a time.
   *
   * @constructor
   */
  var WdDebugger = function () {
      this.client;
      this.replServer;
  
      // repl is broken into 'command repl' and 'debugger repl'.
      this.cmdRepl;
      this.dbgRepl;
      // currentRepl is a pointer to one of them.
      this.currentRepl;
  };
  
  /**
   * Eval function for processing a single step in repl.
   * @private
   * @param {string} cmd
   * @param {object} context
   * @param {string} filename
   * @param {function} callback
   */
  WdDebugger.prototype.stepEval_ = function (cmd, context, filename, callback) {
      // The loop won't come back until 'callback' is called.
      // Note - node's debugger gets around this by adding custom objects
      // named 'c', 's', etc to the REPL context. They have getters which
      // perform the desired function, and the callback is stored for later use.
      // Think about whether this is a better pattern.
  
      cmd = debuggerCommons.trimReplCmd(cmd);
  
      if (this.currentRepl === this.dbgRepl && cmd === 'repl' ||
          this.currentRepl === this.cmdRepl && cmd === 'exit') {
          // switch repl mode
          this.currentRepl =
              this.currentRepl === this.dbgRepl ? this.cmdRepl : this.dbgRepl;
          // For node backward compatibility. In older versions of node `setPrompt`
          // does not exist, and we set the prompt by overwriting `replServer.prompt`
          // directly.
          if (this.replServer.setPrompt) {
              this.replServer.setPrompt(this.currentRepl.prompt);
          } else {
              this.replServer.prompt = this.currentRepl.prompt;
          }
          this.replServer.complete = this.currentRepl.complete.bind(this.currentRepl);
          callback();
      } else if (this.currentRepl === this.cmdRepl) {
          // If we are currently in command repl mode. 
          this.cmdRepl.stepEval(cmd, function (err, res) {
              // Result is a string representation of the evaluation, so we console.log
              // the result to print it properly. Then we callback with undefined so 
              // that the result isn't printed twice. 
              if (res !== undefined) {
                  console.log(res);
              }
              callback(err, undefined);
          });
      } else {
          this.dbgRepl.stepEval(cmd, callback);
      }
  };
  
  /**
   * Instantiate all repl objects, and debuggerRepl as current and start repl.
   * @private
   */
  WdDebugger.prototype.initRepl_ = function () {
      var self = this;
      this.cmdRepl = new CommandRepl(this.client);
      this.dbgRepl = new DebuggerRepl(this.client);
      this.currentRepl = this.dbgRepl;
  
      // We want the prompt to show up only after the controlflow text prints.
      this.dbgRepl.printControlFlow_(function () {
          // Backward compatibility: node version 0.8.14 has a number of built in 
          // libraries for repl, and the keyword 'repl' clashes with our usage.
          if (repl._builtinLibs && repl._builtinLibs.indexOf('repl') > -1) {
              repl._builtinLibs.splice(repl._builtinLibs.indexOf('repl'), 1);
          }
          self.replServer = repl.start({
              prompt: self.currentRepl.prompt,
              input: process.stdin,
              output: process.stdout,
              eval: self.stepEval_.bind(self),
              useGlobal: false,
              ignoreUndefined: true
          });
  
          self.replServer.complete = self.currentRepl.complete.bind(self.currentRepl);
  
          self.replServer.on('exit', function () {
              console.log('Resuming code execution');
              self.client.req({command: 'disconnect'}, function () {
                  // Intentionally blank.
              });
          });
      });
  };
  
  /**
   * Initiate the debugger.
   * @public
   */
  WdDebugger.prototype.init = function () {
      var self = this;
      this.client = debuggerCommons.attachDebugger(process.argv[2], process.argv[3]);
      this.client.once('ready', function () {
          self.initRepl_();
      });
  };
  
  var wdDebugger = new WdDebugger();
  wdDebugger.init();
  