code: function(tabId, pageOptions) {
    /**
     * Target tab ID.
     * @type {number}
     * @private
     */
    this.tabId_ = tabId;
  
    /**
     * Target debugee.
     * @type {!Object}
     * @private
     */
    this.debugee_ = {
      tabId: this.tabId_
    };
  
    /**
     * Page options.
     * @type {!Object}
     * @private
     */
    this.pageOptions_ = pageOptions;
  
    /**
     * A list of timeline records that have been recorded.
     * @type {!Array.<!Array>}
     * @private
     */
    this.records_ = [];
  
    /**
     * Whether this debugger is attached.
     * @type {boolean}
     * @private
     */
    this.attached_ = false;
  
    /**
     * Interval ID used for polling memory statistics.
     * @type {number|null}
     * @private
     */
    this.memoryPollIntervalId_ = null;
  
    /**
     * The time of the first GC event inside of an event tree.
     * Frequently the timeline will send 2-3 GC events with the same time.
     * De-dupe those by tracking the first GC and ignoring the others.
     * @type {number}
     * @private
     */
    this.lastGcStartTime_ = 0;
  
    // Register us for dispatch.
    Debugger.dispatchTable_.register(this.tabId_, this);
  
    // Attach to the target tab.
    try {
      chrome.debugger.attach(this.debugee_, '1.0', (function() {
        this.attached_ = true;
        this.beginListening_();
      }).bind(this));
    } catch (e) {
      // This is likely an exception saying the debugger is already attached,
      // as Chrome has started throwing this in some versions. There's seriously
      // like 10 different ways they report errors like this and it's different
      // in every version. Sigh.
    }
  }
docs: Debugger data proxy.
  This connects to a tab and sets up a debug session that is used for reading
  out events from the page.
  
  @param {number} tabId Tab ID.
  @param {!Object} pageOptions Page options.
  @constructor