12da489cd246702bee5938545b18a6f710ed214bcJamie Gennis// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22da489cd246702bee5938545b18a6f710ed214bcJamie Gennis// Use of this source code is governed by a BSD-style license that can be
32da489cd246702bee5938545b18a6f710ed214bcJamie Gennis// found in the LICENSE file.
42da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
52da489cd246702bee5938545b18a6f710ed214bcJamie Gennis'use strict';
62da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
72da489cd246702bee5938545b18a6f710ed214bcJamie Gennis/**
82da489cd246702bee5938545b18a6f710ed214bcJamie Gennis * @fileoverview Implements a WebSocket client that receives
92da489cd246702bee5938545b18a6f710ed214bcJamie Gennis * a stream of slices from a server.
102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis *
112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis */
122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennisbase.require('base.events');
1466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennisbase.require('tracing.trace_model');
1566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennisbase.require('tracing.trace_model.slice');
162da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1788448d9ae4dfff1805045790ef5f32495d62abccJeff Brownbase.exportTo('tracing.importer', function() {
182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  var STATE_PAUSED = 0x1;
202da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  var STATE_CAPTURING = 0x2;
212da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
222da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  /**
2388448d9ae4dfff1805045790ef5f32495d62abccJeff Brown   * Converts a stream of trace data from a websocket into a model.
242da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   *
252da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   * Events consumed by this importer have the following JSON structure:
262da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   *
272da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   * {
282da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   *   'cmd': 'commandName',
292da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   *   ... command specific data
302da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   * }
312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   *
322da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   * The importer understands 2 commands:
332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   *      'ptd' (Process Thread Data)
342da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   *      'pcd' (Process Counter Data)
352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   *
362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   * The command specific data is as follows:
372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   *
382da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   * {
392da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   *   'pid': 'Remote Process Id',
402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   *   'td': {
412da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   *                  'n': 'Thread Name Here',
422da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   *                  's: [ {
432da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   *                              'l': 'Slice Label',
442da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   *                              's': startTime,
452da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   *                              'e': endTime
462da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   *                              }, ... ]
472da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   *         }
482da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   * }
492da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   *
502da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   * {
512da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   *  'pid' 'Remote Process Id',
522da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   *  'cd': {
532da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   *      'n': 'Counter Name',
542da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   *      'sn': ['Series Name',...]
552da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   *      'sc': [seriesColor, ...]
562da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   *      'c': [
572da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   *            {
582da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   *              't': timestamp,
592da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   *              'v': [value0, value1, ...]
602da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   *            },
612da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   *            ....
622da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   *           ]
632da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   *       }
642da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   * }
6588448d9ae4dfff1805045790ef5f32495d62abccJeff Brown   * @param {Model} model that will be updated
662da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   * when events are received.
672da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   * @constructor
682da489cd246702bee5938545b18a6f710ed214bcJamie Gennis   */
692da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  function TimelineStreamImporter(model) {
702da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    var self = this;
712da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    this.model_ = model;
722da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    this.connection_ = undefined;
732da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    this.state_ = STATE_CAPTURING;
742da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    this.connectionOpenHandler_ =
7566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        this.connectionOpenHandler_.bind(this);
762da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    this.connectionCloseHandler_ =
7766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        this.connectionCloseHandler_.bind(this);
782da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    this.connectionErrorHandler_ =
7966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        this.connectionErrorHandler_.bind(this);
802da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    this.connectionMessageHandler_ =
8166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        this.connectionMessageHandler_.bind(this);
822da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  }
832da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
842da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  TimelineStreamImporter.prototype = {
852da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    __proto__: base.EventTarget.prototype,
862da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
872da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    cleanup_: function() {
882da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      if (!this.connection_)
892da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        return;
902da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      this.connection_.removeEventListener('open',
9166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis          this.connectionOpenHandler_);
922da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      this.connection_.removeEventListener('close',
9366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis          this.connectionCloseHandler_);
942da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      this.connection_.removeEventListener('error',
9566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis          this.connectionErrorHandler_);
962da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      this.connection_.removeEventListener('message',
9766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis          this.connectionMessageHandler_);
982da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    },
992da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1002da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    connectionOpenHandler_: function() {
1012da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      this.dispatchEvent({'type': 'connect'});
1022da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    },
1032da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1042da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    connectionCloseHandler_: function() {
1052da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      this.dispatchEvent({'type': 'disconnect'});
1062da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      this.cleanup_();
1072da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    },
1082da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1092da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    connectionErrorHandler_: function() {
1102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      this.dispatchEvent({'type': 'connectionerror'});
1112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      this.cleanup_();
1122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    },
1132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    connectionMessageHandler_: function(event) {
1152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      var packet = JSON.parse(event.data);
1162da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      var command = packet['cmd'];
1172da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      var pid = packet['pid'];
1182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      var modelDirty = false;
1192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      if (command == 'ptd') {
1202da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        var process = this.model_.getOrCreateProcess(pid);
1212da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        var threadData = packet['td'];
1222da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        var threadName = threadData['n'];
1232da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        var threadSlices = threadData['s'];
1242da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        var thread = process.getOrCreateThread(threadName);
1252da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        for (var s = 0; s < threadSlices.length; s++) {
1262da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          var slice = threadSlices[s];
12766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis          thread.sliceGroup.pushSlice(new tracing.trace_model.ThreadSlice(
12866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis              'streamed',
12966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis              slice['l'],
13066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis              0,
13166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis              slice['s'],
13266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis              {},
13366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis              slice['e'] - slice['s']));
1342da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        }
1352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        modelDirty = true;
1362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      } else if (command == 'pcd') {
1372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        var process = this.model_.getOrCreateProcess(pid);
1382da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        var counterData = packet['cd'];
1392da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        var counterName = counterData['n'];
1402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        var counterSeriesNames = counterData['sn'];
1412da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        var counterSeriesColors = counterData['sc'];
1422da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        var counterValues = counterData['c'];
1432da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        var counter = process.getOrCreateCounter('streamed', counterName);
1442da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        if (counterSeriesNames.length != counterSeriesColors.length) {
1452da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          var importError = 'Streamed counter name length does not match' +
1462da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                            'counter color length' + counterSeriesNames.length +
1472da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                            ' vs ' + counterSeriesColors.length;
1482da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          this.model_.importErrors.push(importError);
1492da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          return;
1502da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        }
1516833e18b1d4077bf3a727b4422cc2acdbeee35a7Jamie Gennis        if (counter.series.length === 0) {
1526833e18b1d4077bf3a727b4422cc2acdbeee35a7Jamie Gennis          for (var i = 0; i < counterSeriesNames.length; ++i) {
1536833e18b1d4077bf3a727b4422cc2acdbeee35a7Jamie Gennis            counter.addSeries(new tracing.trace_model.CounterSeries(
1546833e18b1d4077bf3a727b4422cc2acdbeee35a7Jamie Gennis                counterSeriesNames[i], counterSeriesColors[i]));
1556833e18b1d4077bf3a727b4422cc2acdbeee35a7Jamie Gennis          }
1562da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        } else {
1576833e18b1d4077bf3a727b4422cc2acdbeee35a7Jamie Gennis          if (counter.series.length != counterSeriesNames.length) {
1582da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            var importError = 'Streamed counter ' + counterName +
15966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis                'changed number of seriesNames';
1602da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            this.model_.importErrors.push(importError);
1612da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            return;
1622da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          } else {
1636833e18b1d4077bf3a727b4422cc2acdbeee35a7Jamie Gennis            for (var i = 0; i < counter.series.length; i++) {
1646833e18b1d4077bf3a727b4422cc2acdbeee35a7Jamie Gennis              var oldSeriesName = counter.series[i].name;
1652da489cd246702bee5938545b18a6f710ed214bcJamie Gennis              var newSeriesName = counterSeriesNames[i];
1666833e18b1d4077bf3a727b4422cc2acdbeee35a7Jamie Gennis
1672da489cd246702bee5938545b18a6f710ed214bcJamie Gennis              if (oldSeriesName != newSeriesName) {
1682da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                var importError = 'Streamed counter ' + counterName +
16966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis                    'series name changed from ' +
17066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis                    oldSeriesName + ' to ' +
17166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis                    newSeriesName;
1722da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                this.model_.importErrors.push(importError);
1732da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                return;
1742da489cd246702bee5938545b18a6f710ed214bcJamie Gennis              }
1752da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            }
1762da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          }
1772da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        }
1782da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        for (var c = 0; c < counterValues.length; c++) {
1792da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          var count = counterValues[c];
1806833e18b1d4077bf3a727b4422cc2acdbeee35a7Jamie Gennis          var ts = count['t'];
1816833e18b1d4077bf3a727b4422cc2acdbeee35a7Jamie Gennis          var values = count['v'];
1826833e18b1d4077bf3a727b4422cc2acdbeee35a7Jamie Gennis          for (var i = 0; i < values.length; ++i) {
1836833e18b1d4077bf3a727b4422cc2acdbeee35a7Jamie Gennis            counter.series[i].addSample(ts, values[i]);
1846833e18b1d4077bf3a727b4422cc2acdbeee35a7Jamie Gennis          }
1852da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        }
1862da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        modelDirty = true;
1872da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      }
1882da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      if (modelDirty == true) {
1892da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        this.model_.updateBounds();
1902da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        this.dispatchEvent({'type': 'modelchange',
1912da489cd246702bee5938545b18a6f710ed214bcJamie Gennis          'model': this.model_});
1922da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      }
1932da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    },
1942da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1952da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    get connected() {
1962da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      if (this.connection_ !== undefined &&
19766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis          this.connection_.readyState == WebSocket.OPEN) {
1982da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        return true;
1992da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      }
2002da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      return false;
2012da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    },
2022da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2032da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    get paused() {
2042da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      return this.state_ == STATE_PAUSED;
2052da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    },
2062da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2072da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    /**
2082da489cd246702bee5938545b18a6f710ed214bcJamie Gennis     * Connects the stream to a websocket.
20966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis     * @param {WebSocket} wsConnection The websocket to use for the stream.
2102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis     */
2112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    connect: function(wsConnection) {
2122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      this.connection_ = wsConnection;
2132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      this.connection_.addEventListener('open',
21466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis          this.connectionOpenHandler_);
2152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      this.connection_.addEventListener('close',
21666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis          this.connectionCloseHandler_);
2172da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      this.connection_.addEventListener('error',
21866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis          this.connectionErrorHandler_);
2192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      this.connection_.addEventListener('message',
22066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis          this.connectionMessageHandler_);
2212da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    },
2222da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2232da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    pause: function() {
2242da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      if (this.state_ == STATE_PAUSED)
2252da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        throw new Error('Already paused.');
2262da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      if (!this.connection_)
2272da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        throw new Error('Not connected.');
2282da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      this.connection_.send(JSON.stringify({'cmd': 'pause'}));
2292da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      this.state_ = STATE_PAUSED;
2302da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    },
2312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2322da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    resume: function() {
2332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      if (this.state_ == STATE_CAPTURING)
2342da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        throw new Error('Already capturing.');
2352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      if (!this.connection_)
2362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        throw new Error('Not connected.');
2372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      this.connection_.send(JSON.stringify({'cmd': 'resume'}));
2382da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      this.state_ = STATE_CAPTURING;
2392da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    }
2402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  };
2412da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2422da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  return {
2432da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    TimelineStreamImporter: TimelineStreamImporter
2442da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  };
2452da489cd246702bee5938545b18a6f710ed214bcJamie Gennis});
246