text: /*
   * Copyright (C) 2007, 2008 Apple Inc.  All rights reserved.
   * Copyright (C) 2008, 2009 Anthony Ricaud <rik@webkit.org>
   * Copyright (C) 2011 Google Inc. All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1.  Redistributions of source code must retain the above copyright
   *     notice, this list of conditions and the following disclaimer.
   * 2.  Redistributions in binary form must reproduce the above copyright
   *     notice, this list of conditions and the following disclaimer in the
   *     documentation and/or other materials provided with the distribution.
   * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
   *     its contributors may be used to endorse or promote products derived
   *     from this software without specific prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
   * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
   * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   */
  
  /**
   * @constructor
   * @extends {WebInspector.VBox}
   * @implements {WebInspector.Searchable}
   * @implements {WebInspector.TargetManager.Observer}
   * @param {!WebInspector.FilterBar} filterBar
   * @param {!Element} progressBarContainer
   * @param {!WebInspector.Setting} networkLogLargeRowsSetting
   */
  WebInspector.NetworkLogView = function(filterBar, progressBarContainer, networkLogLargeRowsSetting)
  {
      WebInspector.VBox.call(this);
      this.setMinimumSize(50, 64);
      this.registerRequiredCSS("network/networkLogView.css");
  
      this._networkHideDataURLSetting = WebInspector.settings.createSetting("networkHideDataURL", false);
      this._networkResourceTypeFiltersSetting = WebInspector.settings.createSetting("networkResourceTypeFilters", {});
      this._networkShowPrimaryLoadWaterfallSetting = WebInspector.settings.createSetting("networkShowPrimaryLoadWaterfall", false);
  
      this._filterBar = filterBar;
      this._progressBarContainer = progressBarContainer;
      this._networkLogLargeRowsSetting = networkLogLargeRowsSetting;
  
      var defaultColumnsVisibility = WebInspector.NetworkLogView._defaultColumnsVisibility;
      this._columnsVisibilitySetting = WebInspector.settings.createSetting("networkLogColumnsVisibility", defaultColumnsVisibility);
      var savedColumnsVisibility = this._columnsVisibilitySetting.get();
      var columnsVisibility = {};
      for (var columnId in defaultColumnsVisibility)
          columnsVisibility[columnId] = savedColumnsVisibility.hasOwnProperty(columnId) ? savedColumnsVisibility[columnId] : defaultColumnsVisibility[columnId];
      this._columnsVisibilitySetting.set(columnsVisibility);
  
      /** @type {!Map.<string, !WebInspector.NetworkDataGridNode>} */
      this._nodesByRequestId = new Map();
      /** @type {!Object.<string, boolean>} */
      this._staleRequestIds = {};
      /** @type {number} */
      this._mainRequestLoadTime = -1;
      /** @type {number} */
      this._mainRequestDOMContentLoadedTime = -1;
      this._matchedRequestCount = 0;
      /** @type {!Array<{time: number, element: !Element}>} */
      this._eventDividers = [];
      this._highlightedSubstringChanges = [];
  
      /** @type {!Array.<!WebInspector.NetworkLogView.Filter>} */
      this._filters = [];
      /** @type {?WebInspector.NetworkLogView.Filter} */
      this._timeFilter = null;
  
      this._currentMatchedRequestNode = null;
      this._currentMatchedRequestIndex = -1;
  
      /** @type {!WebInspector.Linkifier} */
      this._popupLinkifier = new WebInspector.Linkifier();
      /** @type {!WebInspector.Linkifier} */
      this.linkifier = new WebInspector.Linkifier();
  
      this._gridMode = true;
      this._recording = false;
      this._preserveLog = false;
  
      /** @type {number} */
      this._rowHeight = 0;
  
      this._addFilters();
      this._resetSuggestionBuilder();
      this._initializeView();
  
      WebInspector.moduleSetting("networkColorCodeResourceTypes").addChangeListener(this._invalidateAllItems, this);
      this._networkLogLargeRowsSetting.addChangeListener(this._updateRowsSize, this);
  
      WebInspector.targetManager.observeTargets(this);
      WebInspector.targetManager.addModelListener(WebInspector.NetworkManager, WebInspector.NetworkManager.EventTypes.RequestStarted, this._onRequestStarted, this);
      WebInspector.targetManager.addModelListener(WebInspector.NetworkManager, WebInspector.NetworkManager.EventTypes.RequestUpdated, this._onRequestUpdated, this);
      WebInspector.targetManager.addModelListener(WebInspector.NetworkManager, WebInspector.NetworkManager.EventTypes.RequestFinished, this._onRequestUpdated, this);
  }
  
  WebInspector.NetworkLogView._isFilteredOutSymbol = Symbol("isFilteredOut");
  WebInspector.NetworkLogView._isMatchingSearchQuerySymbol = Symbol("isMatchingSearchQuery");
  
  WebInspector.NetworkLogView.HTTPSchemas = {"http": true, "https": true, "ws": true, "wss": true};
  WebInspector.NetworkLogView._responseHeaderColumns = ["Cache-Control", "Connection", "Content-Encoding", "Content-Length", "ETag", "Keep-Alive", "Last-Modified", "Server", "Vary"];
  WebInspector.NetworkLogView._defaultColumnsVisibility = {
      method: false, status: true, protocol: false, scheme: false, domain: false, remoteAddress: false, type: true, initiator: true, cookies: false, setCookies: false, size: true, time: true, priority: false, connectionId: false,
      "Cache-Control": false, "Connection": false, "Content-Encoding": false, "Content-Length": false, "ETag": false, "Keep-Alive": false, "Last-Modified": false, "Server": false, "Vary": false
  };
  WebInspector.NetworkLogView._defaultRefreshDelay = 200;
  
  WebInspector.NetworkLogView._waterfallMinOvertime = 1;
  WebInspector.NetworkLogView._waterfallMaxOvertime = 3;
  
  /** @enum {string} */
  WebInspector.NetworkLogView.FilterType = {
      Domain: "domain",
      HasResponseHeader: "has-response-header",
      Is: "is",
      LargerThan: "larger-than",
      Method: "method",
      MimeType: "mime-type",
      MixedContent: "mixed-content",
      Scheme: "scheme",
      SetCookieDomain: "set-cookie-domain",
      SetCookieName: "set-cookie-name",
      SetCookieValue: "set-cookie-value",
      StatusCode: "status-code"
  };
  
  /** @enum {string} */
  WebInspector.NetworkLogView.MixedContentFilterValues = {
      All: "all",
      Displayed: "displayed",
      Blocked: "blocked",
      BlockOverridden: "block-overridden"
  }
  
  /** @enum {string} */
  WebInspector.NetworkLogView.IsFilterType = {
      Running: "running"
  };
  
  /** @type {!Array.<string>} */
  WebInspector.NetworkLogView._searchKeys = Object.values(WebInspector.NetworkLogView.FilterType);
  
  /** @type {!Object.<string, string>} */
  WebInspector.NetworkLogView._columnTitles = {
      "name": WebInspector.UIString("Name"),
      "method": WebInspector.UIString("Method"),
      "status": WebInspector.UIString("Status"),
      "protocol": WebInspector.UIString("Protocol"),
      "scheme": WebInspector.UIString("Scheme"),
      "domain": WebInspector.UIString("Domain"),
      "remoteAddress": WebInspector.UIString("Remote Address"),
      "type": WebInspector.UIString("Type"),
      "initiator": WebInspector.UIString("Initiator"),
      "cookies": WebInspector.UIString("Cookies"),
      "setCookies": WebInspector.UIString("Set-Cookies"),
      "size": WebInspector.UIString("Size"),
      "time": WebInspector.UIString("Time"),
      "connectionId": WebInspector.UIString("Connection Id"),
      "priority": WebInspector.UIString("Priority"),
      "timeline": WebInspector.UIString("Timeline"),
  
      // Response header columns
      "Cache-Control": WebInspector.UIString("Cache-Control"),
      "Connection": WebInspector.UIString("Connection"),
      "Content-Encoding": WebInspector.UIString("Content-Encoding"),
      "Content-Length": WebInspector.UIString("Content-Length"),
      "ETag": WebInspector.UIString("ETag"),
      "Keep-Alive": WebInspector.UIString("Keep-Alive"),
      "Last-Modified": WebInspector.UIString("Last-Modified"),
      "Server": WebInspector.UIString("Server"),
      "Vary": WebInspector.UIString("Vary")
  };
  
  WebInspector.NetworkLogView.prototype = {
      /**
       * @param {boolean} recording
       */
      setRecording: function(recording)
      {
          this._recording = recording;
          this._updateSummaryBar();
      },
  
      /**
       * @param {boolean} preserveLog
       */
      setPreserveLog: function(preserveLog)
      {
          this._preserveLog = preserveLog;
      },
  
      /**
       * @override
       * @param {!WebInspector.Target} target
       */
      targetAdded: function(target)
      {
          if (!target.parentTarget()) {
              target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, this._mainFrameNavigated, this);
              target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.Load, this._loadEventFired, this);
              target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.DOMContentLoaded, this._domContentLoadedEventFired, this);
          }
          target.networkLog.requests().forEach(this._appendRequest.bind(this));
      },
  
      /**
       * @override
       * @param {!WebInspector.Target} target
       */
      targetRemoved: function(target)
      {
          if (!target.parentTarget()) {
              target.resourceTreeModel.removeEventListener(WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, this._mainFrameNavigated, this);
              target.resourceTreeModel.removeEventListener(WebInspector.ResourceTreeModel.EventTypes.Load, this._loadEventFired, this);
              target.resourceTreeModel.removeEventListener(WebInspector.ResourceTreeModel.EventTypes.DOMContentLoaded, this._domContentLoadedEventFired, this);
          }
      },
  
      /**
       * @param {number} start
       * @param {number} end
       */
      setWindow: function(start, end)
      {
          if (!start && !end) {
              this._timeFilter = null;
              this._timeCalculator.setWindow(null);
          } else {
              this._timeFilter = WebInspector.NetworkLogView._requestTimeFilter.bind(null, start, end);
              this._timeCalculator.setWindow(new WebInspector.NetworkTimeBoundary(start, end));
          }
          this._updateDividersIfNeeded();
          this._filterRequests();
      },
  
      clearSelection: function()
      {
          if (this._dataGrid.selectedNode)
              this._dataGrid.selectedNode.deselect();
      },
  
      _addFilters: function()
      {
          this._textFilterUI = new WebInspector.TextFilterUI(true);
          this._textFilterUI.addEventListener(WebInspector.FilterUI.Events.FilterChanged, this._filterChanged, this);
          this._filterBar.addFilter(this._textFilterUI);
  
          var dataURLSetting = this._networkHideDataURLSetting;
          this._dataURLFilterUI = new WebInspector.CheckboxFilterUI("hide-data-url", WebInspector.UIString("Hide data URLs"), true, dataURLSetting);
          this._dataURLFilterUI.addEventListener(WebInspector.FilterUI.Events.FilterChanged, this._filterChanged.bind(this), this);
          this._filterBar.addFilter(this._dataURLFilterUI);
  
          var filterItems = [];
          for (var categoryId in WebInspector.resourceCategories) {
              var category = WebInspector.resourceCategories[categoryId];
              filterItems.push({name: category.title, label: category.shortTitle, title: category.title});
          }
          this._resourceCategoryFilterUI = new WebInspector.NamedBitSetFilterUI(filterItems, this._networkResourceTypeFiltersSetting);
          this._resourceCategoryFilterUI.addEventListener(WebInspector.FilterUI.Events.FilterChanged, this._filterChanged.bind(this), this);
          this._filterBar.addFilter(this._resourceCategoryFilterUI);
      },
  
      _resetSuggestionBuilder: function()
      {
          this._suggestionBuilder = new WebInspector.FilterSuggestionBuilder(WebInspector.NetworkLogView._searchKeys);
          this._suggestionBuilder.addItem(WebInspector.NetworkLogView.FilterType.Is, WebInspector.NetworkLogView.IsFilterType.Running);
          this._suggestionBuilder.addItem(WebInspector.NetworkLogView.FilterType.LargerThan, "100");
          this._suggestionBuilder.addItem(WebInspector.NetworkLogView.FilterType.LargerThan, "10k");
          this._suggestionBuilder.addItem(WebInspector.NetworkLogView.FilterType.LargerThan, "1M");
          this._textFilterUI.setSuggestionBuilder(this._suggestionBuilder);
      },
  
      /**
       * @param {!WebInspector.Event} event
       */
      _filterChanged: function(event)
      {
          this._removeAllNodeHighlights();
          this._parseFilterQuery(this._textFilterUI.value());
          this._filterRequests();
      },
  
      _initializeView: function()
      {
          this.element.id = "network-container";
  
          this._createSortingFunctions();
          this._createCalculators();
          this._createTable();
          this._createTimelineGrid();
          this._summaryBarElement = this.element.createChild("div", "network-summary-bar");
  
          this._updateRowsSize();
  
          this._popoverHelper = new WebInspector.PopoverHelper(this.element, this._getPopoverAnchor.bind(this), this._showPopover.bind(this), this._onHidePopover.bind(this));
          this.switchViewMode(true);
      },
  
      _showRecordingHint: function()
      {
          this._hideRecordingHint();
          this._recordingHint = this.element.createChild("div", "network-status-pane fill");
          var hintText = this._recordingHint.createChild("div", "recording-hint");
          var reloadShortcutNode = this._recordingHint.createChild("b");
          reloadShortcutNode.textContent = WebInspector.shortcutRegistry.shortcutDescriptorsForAction("main.reload")[0].name;
  
          if (this._recording) {
              var recordingText = hintText.createChild("span");
              recordingText.textContent = WebInspector.UIString("Recording network activity\u2026");
              hintText.createChild("br");
              hintText.appendChild(WebInspector.formatLocalized("Perform a request or hit %s to record the reload.", [reloadShortcutNode]));
          } else {
              var recordNode = hintText.createChild("b");
              recordNode.textContent = WebInspector.shortcutRegistry.shortcutTitleForAction("network.toggle-recording");
              hintText.appendChild(WebInspector.formatLocalized("Record (%s) or reload (%s) to display network activity.", [recordNode, reloadShortcutNode]));
          }
      },
  
      _hideRecordingHint: function()
      {
          if (this._recordingHint)
              this._recordingHint.remove();
          delete this._recordingHint;
      },
  
      /**
       * @override
       * @return {!Array.<!Element>}
       */
      elementsToRestoreScrollPositionsFor: function()
      {
          if (!this._dataGrid) // Not initialized yet.
              return [];
          return [this._dataGrid.scrollContainer];
      },
  
      _createTimelineGrid: function()
      {
          this._timelineGrid = new WebInspector.TimelineGrid();
          this._timelineGrid.element.classList.add("network-timeline-grid");
          this._dataGrid.element.appendChild(this._timelineGrid.element);
      },
  
      _createTable: function()
      {
          var columns = [];
          columns.push({
              id: "name",
              titleDOMFragment: this._makeHeaderFragment(WebInspector.UIString("Name"), WebInspector.UIString("Path")),
              title: WebInspector.NetworkLogView._columnTitles["name"],
              weight: 20
          });
  
          columns.push({
              id: "method",
              title: WebInspector.NetworkLogView._columnTitles["method"],
              weight: 6
          });
  
          columns.push({
              id: "status",
              titleDOMFragment: this._makeHeaderFragment(WebInspector.UIString("Status"), WebInspector.UIString("Text")),
              title: WebInspector.NetworkLogView._columnTitles["status"],
              weight: 6
          });
  
          columns.push({
              id: "protocol",
              title: WebInspector.NetworkLogView._columnTitles["protocol"],
              weight: 6
          });
  
          columns.push({
              id: "scheme",
              title: WebInspector.NetworkLogView._columnTitles["scheme"],
              weight: 6
          });
  
          columns.push({
              id: "domain",
              title: WebInspector.NetworkLogView._columnTitles["domain"],
              weight: 6
          });
  
          columns.push({
              id: "remoteAddress",
              title: WebInspector.NetworkLogView._columnTitles["remoteAddress"],
              weight: 10,
              align: WebInspector.DataGrid.Align.Right
          });
  
          columns.push({
              id: "type",
              title: WebInspector.NetworkLogView._columnTitles["type"],
              weight: 6
          });
  
          columns.push({
              id: "initiator",
              title: WebInspector.NetworkLogView._columnTitles["initiator"],
              weight: 10
          });
  
          columns.push({
              id: "cookies",
              title: WebInspector.NetworkLogView._columnTitles["cookies"],
              weight: 6,
              align: WebInspector.DataGrid.Align.Right
          });
  
          columns.push({
              id: "setCookies",
              title: WebInspector.NetworkLogView._columnTitles["setCookies"],
              weight: 6,
              align: WebInspector.DataGrid.Align.Right
          });
  
          columns.push({
              id: "size",
              titleDOMFragment: this._makeHeaderFragment(WebInspector.UIString("Size"), WebInspector.UIString("Content")),
              title: WebInspector.NetworkLogView._columnTitles["size"],
              weight: 6,
              align: WebInspector.DataGrid.Align.Right
          });
  
          columns.push({
              id: "time",
              titleDOMFragment: this._makeHeaderFragment(WebInspector.UIString("Time"), WebInspector.UIString("Latency")),
              title: WebInspector.NetworkLogView._columnTitles["time"],
              weight: 6,
              align: WebInspector.DataGrid.Align.Right
          });
  
          columns.push({
              id: "priority",
              title: WebInspector.NetworkLogView._columnTitles["priority"],
              weight: 6
          });
  
          columns.push({
              id: "connectionId",
              title: WebInspector.NetworkLogView._columnTitles["connectionId"],
              weight: 6
          });
  
          var responseHeaderColumns = WebInspector.NetworkLogView._responseHeaderColumns;
          for (var i = 0; i < responseHeaderColumns.length; ++i) {
              var headerName = responseHeaderColumns[i];
              var descriptor = {
                  id: headerName,
                  title: WebInspector.NetworkLogView._columnTitles[headerName],
                  weight: 6
              };
              if (headerName === "Content-Length")
                  descriptor.align = WebInspector.DataGrid.Align.Right;
              columns.push(descriptor);
          }
  
          columns.push({
              id: "timeline",
              title: WebInspector.NetworkLogView._columnTitles["timeline"],
              sortable: false,
              weight: 40,
              sort: WebInspector.DataGrid.Order.Ascending
          });
  
          for (var column of columns) {
              column.sortable = column.id !== "timeline";
              column.nonSelectable = column.id !== "name";
          }
  
          this._dataGrid = new WebInspector.SortableDataGrid(columns);
          this._dataGrid.setStickToBottom(true);
          this._updateColumns();
          this._dataGrid.setName("networkLog");
          this._dataGrid.setResizeMethod(WebInspector.DataGrid.ResizeMethod.Last);
          this._dataGrid.element.classList.add("network-log-grid");
          this._dataGrid.element.addEventListener("contextmenu", this._contextMenu.bind(this), true);
          this._dataGrid.element.addEventListener("mousedown", this._dataGridMouseDown.bind(this), true);
          this._dataGrid.element.addEventListener("mousemove", this._dataGridMouseMove.bind(this), true);
          this._dataGrid.element.addEventListener("mouseleave", this._highlightInitiatorChain.bind(this, null), true);
          this._dataGrid.asWidget().show(this.element);
  
          // Event listeners need to be added _after_ we attach to the document, so that owner document is properly update.
          this._dataGrid.addEventListener(WebInspector.DataGrid.Events.SortingChanged, this._sortItems, this);
          this._dataGrid.addEventListener(WebInspector.DataGrid.Events.ColumnsResized, this._updateDividersIfNeeded, this);
  
          this._patchTimelineHeader();
          this._dataGrid.sortNodes(this._sortingFunctions.startTime, false);
      },
  
      /**
       * @param {!Event} event
       */
      _dataGridMouseDown: function(event)
      {
          if ((!this._dataGrid.selectedNode && event.button) || event.target.enclosingNodeOrSelfWithNodeName("a"))
              event.consume();
      },
  
      /**
       * @param {!Event} event
       */
      _dataGridMouseMove: function(event)
      {
          var node = event.shiftKey ? this._dataGrid.dataGridNodeFromNode(event.target) : null;
          this._highlightInitiatorChain(node ? node.request() : null);
      },
  
      /**
       * @param {?WebInspector.NetworkRequest} request
       */
      _highlightInitiatorChain: function(request)
      {
          if (this._requestWithHighlightedInitiators === request)
              return;
          this._requestWithHighlightedInitiators = request;
  
          if (!request) {
              for (var node of this._nodesByRequestId.values()) {
                  if (!node.dataGrid)
                      continue;
                  node.element().classList.remove("network-node-on-initiator-path", "network-node-on-initiated-path");
              }
              return;
          }
  
          var initiators = request.initiatorChain();
          var initiated = new Set();
          for (var node of this._nodesByRequestId.values()) {
              if (!node.dataGrid)
                  continue;
              var localInitiators = node.request().initiatorChain();
              if (localInitiators.has(request))
                  initiated.add(node.request());
          }
  
          for (var node of this._nodesByRequestId.values()) {
              if (!node.dataGrid)
                  continue;
              node.element().classList.toggle("network-node-on-initiator-path", node.request() !== request && initiators.has(node.request()));
              node.element().classList.toggle("network-node-on-initiated-path", node.request() !== request && initiated.has(node.request()));
          }
      },
  
      /**
       * @param {string} title
       * @param {string} subtitle
       * @return {!DocumentFragment}
       */
      _makeHeaderFragment: function(title, subtitle)
      {
          var fragment = createDocumentFragment();
          fragment.createTextChild(title);
          var subtitleDiv = fragment.createChild("div", "network-header-subtitle");
          subtitleDiv.createTextChild(subtitle);
          return fragment;
      },
  
      _patchTimelineHeader: function()
      {
          var timelineSorting = createElement("select");
  
          var option = createElement("option");
          option.value = "startTime";
          option.label = WebInspector.UIString("Timeline");
          option.disabled = true;
          timelineSorting.appendChild(option);
  
          option = createElement("option");
          option.value = "startTime";
          option.label = WebInspector.UIString("Timeline \u2013 Start Time");
          option.sortOrder = WebInspector.DataGrid.Order.Ascending;
          timelineSorting.appendChild(option);
  
          option = createElement("option");
          option.value = "responseTime";
          option.label = WebInspector.UIString("Timeline \u2013 Response Time");
          option.sortOrder = WebInspector.DataGrid.Order.Ascending;
          timelineSorting.appendChild(option);
  
          option = createElement("option");
          option.value = "endTime";
          option.label = WebInspector.UIString("Timeline \u2013 End Time");
          option.sortOrder = WebInspector.DataGrid.Order.Ascending;
          timelineSorting.appendChild(option);
  
          option = createElement("option");
          option.value = "duration";
          option.label = WebInspector.UIString("Timeline \u2013 Total Duration");
          option.sortOrder = WebInspector.DataGrid.Order.Descending;
          timelineSorting.appendChild(option);
  
          option = createElement("option");
          option.value = "latency";
          option.label = WebInspector.UIString("Timeline \u2013 Latency");
          option.sortOrder = WebInspector.DataGrid.Order.Descending;
          timelineSorting.appendChild(option);
  
          var header = this._dataGrid.headerTableHeader("timeline");
          header.replaceChild(timelineSorting, header.firstChild);
          header.createChild("div", "sort-order-icon-container").createChild("div", "sort-order-icon");
  
          timelineSorting.selectedIndex = 1;
          timelineSorting.addEventListener("click", function(event) { event.consume(); }, false);
          timelineSorting.addEventListener("change", this._sortByTimeline.bind(this), false);
          this._timelineSortSelector = timelineSorting;
      },
  
      _createSortingFunctions: function()
      {
          this._sortingFunctions = {};
          this._sortingFunctions.name = WebInspector.NetworkDataGridNode.NameComparator;
          this._sortingFunctions.method = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "requestMethod");
          this._sortingFunctions.status = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "statusCode");
          this._sortingFunctions.protocol = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "protocol");
          this._sortingFunctions.scheme = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "scheme");
          this._sortingFunctions.domain = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "domain");
          this._sortingFunctions.remoteAddress = WebInspector.NetworkDataGridNode.RemoteAddressComparator;
          this._sortingFunctions.type = WebInspector.NetworkDataGridNode.TypeComparator;
          this._sortingFunctions.initiator = WebInspector.NetworkDataGridNode.InitiatorComparator;
          this._sortingFunctions.cookies = WebInspector.NetworkDataGridNode.RequestCookiesCountComparator;
          this._sortingFunctions.setCookies = WebInspector.NetworkDataGridNode.ResponseCookiesCountComparator;
          this._sortingFunctions.size = WebInspector.NetworkDataGridNode.SizeComparator;
          this._sortingFunctions.time = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "duration");
          this._sortingFunctions.connectionId = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "connectionId");
          this._sortingFunctions.priority = WebInspector.NetworkDataGridNode.InitialPriorityComparator;
          this._sortingFunctions.timeline = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "startTime");
          this._sortingFunctions.startTime = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "startTime");
          this._sortingFunctions.endTime = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "endTime");
          this._sortingFunctions.responseTime = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "responseReceivedTime");
          this._sortingFunctions.duration = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "duration");
          this._sortingFunctions.latency = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "latency");
  
          this._sortingFunctions["Cache-Control"] = WebInspector.NetworkDataGridNode.ResponseHeaderStringComparator.bind(null, "Cache-Control");
          this._sortingFunctions["Connection"] = WebInspector.NetworkDataGridNode.ResponseHeaderStringComparator.bind(null, "Connection");
          this._sortingFunctions["Content-Encoding"] = WebInspector.NetworkDataGridNode.ResponseHeaderStringComparator.bind(null, "Content-Encoding");
          this._sortingFunctions["Content-Length"] = WebInspector.NetworkDataGridNode.ResponseHeaderNumberComparator.bind(null, "Content-Length");
          this._sortingFunctions["ETag"] = WebInspector.NetworkDataGridNode.ResponseHeaderStringComparator.bind(null, "ETag");
          this._sortingFunctions["Keep-Alive"] = WebInspector.NetworkDataGridNode.ResponseHeaderStringComparator.bind(null, "Keep-Alive");
          this._sortingFunctions["Last-Modified"] = WebInspector.NetworkDataGridNode.ResponseHeaderDateComparator.bind(null, "Last-Modified");
          this._sortingFunctions["Server"] = WebInspector.NetworkDataGridNode.ResponseHeaderStringComparator.bind(null, "Server");
          this._sortingFunctions["Vary"] = WebInspector.NetworkDataGridNode.ResponseHeaderStringComparator.bind(null, "Vary");
      },
  
      _createCalculators: function()
      {
          /** @type {!WebInspector.NetworkTransferTimeCalculator} */
          this._timeCalculator = new WebInspector.NetworkTransferTimeCalculator();
          /** @type {!WebInspector.NetworkTransferDurationCalculator} */
          this._durationCalculator = new WebInspector.NetworkTransferDurationCalculator();
  
          /** @type {!Object.<string, !WebInspector.NetworkTimeCalculator>} */
          this._calculators = {};
          this._calculators.timeline = this._timeCalculator;
          this._calculators.startTime = this._timeCalculator;
          this._calculators.endTime = this._timeCalculator;
          this._calculators.responseTime = this._timeCalculator;
          this._calculators.duration = this._durationCalculator;
          this._calculators.latency = this._durationCalculator;
  
          this._calculator = this._timeCalculator;
      },
  
      _sortItems: function()
      {
          this._removeAllNodeHighlights();
          var columnIdentifier = this._dataGrid.sortColumnIdentifier();
          if (columnIdentifier === "timeline") {
              this._sortByTimeline();
              return;
          }
          var sortingFunction = this._sortingFunctions[columnIdentifier];
          if (!sortingFunction)
              return;
  
          this._dataGrid.sortNodes(sortingFunction, !this._dataGrid.isSortOrderAscending());
          this._highlightNthMatchedRequestForSearch(this._updateMatchCountAndFindMatchIndex(this._currentMatchedRequestNode), false);
          this._timelineSortSelector.selectedIndex = 0;
      },
  
      _sortByTimeline: function()
      {
          this._removeAllNodeHighlights();
          var selectedIndex = this._timelineSortSelector.selectedIndex;
          if (!selectedIndex)
              selectedIndex = 1; // Sort by start time by default.
          var selectedOption = this._timelineSortSelector[selectedIndex];
          var value = selectedOption.value;
  
          this._setCalculator(this._calculators[value]);
          var sortingFunction = this._sortingFunctions[value];
          this._dataGrid.sortNodes(sortingFunction);
          this._highlightNthMatchedRequestForSearch(this._updateMatchCountAndFindMatchIndex(this._currentMatchedRequestNode), false);
          this._dataGrid.markColumnAsSortedBy("timeline", selectedOption.sortOrder);
      },
  
      _updateSummaryBar: function()
      {
          var requestsNumber = this._nodesByRequestId.size;
  
          if (!requestsNumber) {
              this._showRecordingHint();
              return;
          }
          this._hideRecordingHint();
  
          var transferSize = 0;
          var selectedRequestsNumber = 0;
          var selectedTransferSize = 0;
          var baseTime = -1;
          var maxTime = -1;
          var nodes = this._nodesByRequestId.valuesArray();
          for (var i = 0; i < nodes.length; ++i) {
              var request = nodes[i].request();
              var requestTransferSize = request.transferSize;
              transferSize += requestTransferSize;
              if (!nodes[i][WebInspector.NetworkLogView._isFilteredOutSymbol]) {
                  selectedRequestsNumber++;
                  selectedTransferSize += requestTransferSize;
              }
              if (request.url === request.target().resourceTreeModel.inspectedPageURL() && request.resourceType() === WebInspector.resourceTypes.Document)
                  baseTime = request.startTime;
              if (request.endTime > maxTime)
                  maxTime = request.endTime;
          }
  
          var summaryBar = this._summaryBarElement;
          summaryBar.removeChildren();
          var separator = "\u2002\u2758\u2002";
          var text = "";
          /**
           * @param {string} chunk
           * @return {!Element}
           */
          function appendChunk(chunk)
          {
              var span = summaryBar.createChild("span");
              span.textContent = chunk;
              text += chunk;
              return span;
          }
  
          if (selectedRequestsNumber !== requestsNumber) {
              appendChunk(WebInspector.UIString("%d / %d requests", selectedRequestsNumber, requestsNumber));
              appendChunk(separator);
              appendChunk(WebInspector.UIString("%s / %s transferred", Number.bytesToString(selectedTransferSize), Number.bytesToString(transferSize)));
          } else {
              appendChunk(WebInspector.UIString("%d requests", requestsNumber));
              appendChunk(separator);
              appendChunk(WebInspector.UIString("%s transferred", Number.bytesToString(transferSize)));
          }
          if (baseTime !== -1 && maxTime !== -1) {
              appendChunk(separator);
              appendChunk(WebInspector.UIString("Finish: %s", Number.secondsToString(maxTime - baseTime)));
              if (this._mainRequestDOMContentLoadedTime !== -1 && this._mainRequestDOMContentLoadedTime > baseTime) {
                  appendChunk(separator);
                  var domContentLoadedText = WebInspector.UIString("DOMContentLoaded: %s", Number.secondsToString(this._mainRequestDOMContentLoadedTime - baseTime));
                  appendChunk(domContentLoadedText).classList.add("summary-blue");
              }
              if (this._mainRequestLoadTime !== -1) {
                  appendChunk(separator);
                  var loadText = WebInspector.UIString("Load: %s", Number.secondsToString(this._mainRequestLoadTime - baseTime));
                  appendChunk(loadText).classList.add("summary-red");
              }
          }
          summaryBar.title = text;
      },
  
      _scheduleRefresh: function()
      {
          if (this._needsRefresh)
              return;
  
          this._needsRefresh = true;
  
          if (this.isShowing() && !this._refreshTimeout)
              this._refreshTimeout = setTimeout(this.refresh.bind(this), WebInspector.NetworkLogView._defaultRefreshDelay);
      },
  
      _updateDividersIfNeeded: function()
      {
          if (!this.isShowing()) {
              this._scheduleRefresh();
              return;
          }
  
          var timelineOffset = this._dataGrid.columnOffset("timeline");
          // Position timline grid location.
          if (timelineOffset)
              this._timelineGrid.element.style.left = timelineOffset + "px";
  
          var calculator = this.calculator();
          calculator.setDisplayWindow(this._timelineGrid.dividersElement.clientWidth);
          this._timelineGrid.updateDividers(calculator, 75);
  
          if (calculator.startAtZero) {
              // If our current sorting method starts at zero, that means it shows all
              // requests starting at the same point, and so onLoad event and DOMContent
              // event lines really wouldn't make much sense here, so don't render them.
              return;
          }
  
          this._updateEventDividers();
      },
  
      /**
       * @param {!Array<number>} times
       */
      addFilmStripFrames: function(times)
      {
          this._addEventDividers(times, "network-frame-divider");
      },
  
      /**
       * @param {number} time
       */
      selectFilmStripFrame: function(time)
      {
          for (var divider of this._eventDividers)
              divider.element.classList.toggle("network-frame-divider-selected", divider.time === time);
      },
  
      clearFilmStripFrame: function()
      {
          for (var divider of this._eventDividers)
              divider.element.classList.toggle("network-frame-divider-selected", false);
      },
  
      /**
       * @param {!Array<number>} times
       * @param {string} className
       */
      _addEventDividers: function(times, className)
      {
          for (var i = 0; i < times.length; ++i) {
              var element = createElementWithClass("div", "network-event-divider " + className);
              this._timelineGrid.addEventDivider(element);
              this._eventDividers.push({time: times[i], element: element});
          }
          // Update event dividers immediately
          this._updateEventDividers();
          // Schedule refresh in case dividers change the calculator span.
          this._scheduleRefresh();
      },
  
      _updateEventDividers: function()
      {
          var calculator = this.calculator();
          for (var divider of this._eventDividers) {
              var timePercent = calculator.computePercentageFromEventTime(divider.time);
              divider.element.classList.toggle("invisible", timePercent < 0);
              divider.element.style.left = timePercent + "%";
          }
      },
  
      _refreshIfNeeded: function()
      {
          if (this._needsRefresh)
              this.refresh();
      },
  
      _invalidateAllItems: function()
      {
          var requestIds = this._nodesByRequestId.keysArray();
          for (var i = 0; i < requestIds.length; ++i)
              this._staleRequestIds[requestIds[i]] = true;
          this.refresh();
      },
  
      /**
       * @return {!WebInspector.NetworkTimeCalculator}
       */
      timeCalculator: function()
      {
          return this._timeCalculator;
      },
  
      /**
       * @return {!WebInspector.NetworkTimeCalculator}
       */
      calculator: function()
      {
          return this._calculator;
      },
  
      /**
       * @param {!WebInspector.NetworkTimeCalculator} x
       */
      _setCalculator: function(x)
      {
          if (!x || this._calculator === x)
              return;
  
          this._calculator = x;
          this._calculator.reset();
  
          if (this._calculator.startAtZero)
              this._timelineGrid.hideEventDividers();
          else
              this._timelineGrid.showEventDividers();
  
          this._invalidateAllItems();
      },
  
      /**
       * @param {!WebInspector.Event} event
       */
      _loadEventFired: function(event)
      {
          if (!this._recording)
              return;
  
          var data = /** @type {number} */ (event.data);
          if (data) {
              this._mainRequestLoadTime = data;
              this._addEventDividers([data], "network-red-divider");
          }
      },
  
      /**
       * @param {!WebInspector.Event} event
       */
      _domContentLoadedEventFired: function(event)
      {
          if (!this._recording)
              return;
          var data = /** @type {number} */ (event.data);
          if (data) {
              this._mainRequestDOMContentLoadedTime = data;
              this._addEventDividers([data], "network-blue-divider");
          }
      },
  
      wasShown: function()
      {
          this._refreshIfNeeded();
      },
  
      willHide: function()
      {
          this._popoverHelper.hidePopover();
      },
  
      refresh: function()
      {
          this._needsRefresh = false;
          if (this._refreshTimeout) {
              clearTimeout(this._refreshTimeout);
              delete this._refreshTimeout;
          }
  
          this._removeAllNodeHighlights();
  
          var oldBoundary = this.calculator().boundary();
          this._timeCalculator.updateBoundariesForEventTime(this._mainRequestLoadTime);
          this._durationCalculator.updateBoundariesForEventTime(this._mainRequestLoadTime);
          this._timeCalculator.updateBoundariesForEventTime(this._mainRequestDOMContentLoadedTime);
          this._durationCalculator.updateBoundariesForEventTime(this._mainRequestDOMContentLoadedTime);
  
          var dataGrid = this._dataGrid;
          var rootNode = dataGrid.rootNode();
          /** @type {!Array<!WebInspector.NetworkDataGridNode> } */
          var nodesToInsert = [];
          /** @type {!Array<!WebInspector.NetworkDataGridNode> } */
          var nodesToRefresh = [];
          for (var requestId in this._staleRequestIds) {
              var node = this._nodesByRequestId.get(requestId);
              if (!node)
                  continue;
              var isFilteredOut = !this._applyFilter(node);
              if (node[WebInspector.NetworkLogView._isFilteredOutSymbol] !== isFilteredOut) {
                  if (!node[WebInspector.NetworkLogView._isFilteredOutSymbol])
                      rootNode.removeChild(node);
  
                  node[WebInspector.NetworkLogView._isFilteredOutSymbol] = isFilteredOut;
  
                  if (!node[WebInspector.NetworkLogView._isFilteredOutSymbol])
                      nodesToInsert.push(node);
              }
              if (!isFilteredOut)
                  nodesToRefresh.push(node);
              var request = node.request();
              this._timeCalculator.updateBoundaries(request);
              this._durationCalculator.updateBoundaries(request);
          }
  
          for (var i = 0; i < nodesToInsert.length; ++i) {
              var node = nodesToInsert[i];
              var request = node.request();
              dataGrid.insertChild(node);
              node[WebInspector.NetworkLogView._isMatchingSearchQuerySymbol] = this._matchRequest(request);
          }
  
          for (var node of nodesToRefresh)
              node.refresh();
  
          this._highlightNthMatchedRequestForSearch(this._updateMatchCountAndFindMatchIndex(this._currentMatchedRequestNode), false);
  
          if (!this.calculator().boundary().equals(oldBoundary)) {
              // The boundaries changed, so all item graphs are stale.
              this._updateDividersIfNeeded();
              var nodes = this._nodesByRequestId.valuesArray();
              for (var i = 0; i < nodes.length; ++i)
                  nodes[i].refreshGraph();
          }
  
          this._staleRequestIds = {};
          this._updateSummaryBar();
      },
  
      reset: function()
      {
          this._requestWithHighlightedInitiators = null;
          this.dispatchEventToListeners(WebInspector.NetworkLogView.EventTypes.RequestSelected, null);
  
          this._clearSearchMatchedList();
          if (this._popoverHelper)
              this._popoverHelper.hidePopover();
  
          this._timeFilter = null;
          this._calculator.reset();
  
          this._timeCalculator.setWindow(null);
  
          var nodes = this._nodesByRequestId.valuesArray();
          for (var i = 0; i < nodes.length; ++i)
              nodes[i].dispose();
  
          this._nodesByRequestId.clear();
          this._staleRequestIds = {};
          this._resetSuggestionBuilder();
  
          this._mainRequestLoadTime = -1;
          this._mainRequestDOMContentLoadedTime = -1;
          this._eventDividers = [];
          this._timelineGrid.removeEventDividers();
  
          if (this._dataGrid) {
              this._dataGrid.rootNode().removeChildren();
              this._updateDividersIfNeeded();
              this._updateSummaryBar();
          }
      },
  
      /**
        * @param {string} filterString
        */
      setTextFilterValue: function(filterString)
      {
          this._textFilterUI.setValue(filterString);
      },
  
      /**
       * @param {!WebInspector.Event} event
       */
      _onRequestStarted: function(event)
      {
          if (!this._recording)
              return;
          var request = /** @type {!WebInspector.NetworkRequest} */ (event.data);
          this._appendRequest(request);
      },
  
      /**
       * @param {!WebInspector.NetworkRequest} request
       */
      _appendRequest: function(request)
      {
          var node = new WebInspector.NetworkDataGridNode(this, request);
          node[WebInspector.NetworkLogView._isFilteredOutSymbol] = true;
          node[WebInspector.NetworkLogView._isMatchingSearchQuerySymbol] = false;
  
          // In case of redirect request id is reassigned to a redirected
          // request and we need to update _nodesByRequestId and search results.
          var originalRequestNode = this._nodesByRequestId.get(request.requestId);
          if (originalRequestNode)
              this._nodesByRequestId.set(originalRequestNode.request().requestId, originalRequestNode);
          this._nodesByRequestId.set(request.requestId, node);
  
          // Pull all the redirects of the main request upon commit load.
          if (request.redirects) {
              for (var i = 0; i < request.redirects.length; ++i)
                  this._refreshRequest(request.redirects[i]);
          }
  
          this._refreshRequest(request);
      },
  
      /**
       * @param {!WebInspector.Event} event
       */
      _onRequestUpdated: function(event)
      {
          var request = /** @type {!WebInspector.NetworkRequest} */ (event.data);
          this._refreshRequest(request);
      },
  
      /**
       * @param {!WebInspector.NetworkRequest} request
       */
      _refreshRequest: function(request)
      {
          if (!this._nodesByRequestId.get(request.requestId))
              return;
  
          WebInspector.NetworkLogView._subdomains(request.domain).forEach(this._suggestionBuilder.addItem.bind(this._suggestionBuilder, WebInspector.NetworkLogView.FilterType.Domain));
          this._suggestionBuilder.addItem(WebInspector.NetworkLogView.FilterType.Method, request.requestMethod);
          this._suggestionBuilder.addItem(WebInspector.NetworkLogView.FilterType.MimeType, request.mimeType);
          this._suggestionBuilder.addItem(WebInspector.NetworkLogView.FilterType.Scheme, "" + request.scheme);
          this._suggestionBuilder.addItem(WebInspector.NetworkLogView.FilterType.StatusCode, "" + request.statusCode);
  
          if (request.mixedContentType !== "none") {
              this._suggestionBuilder.addItem(WebInspector.NetworkLogView.FilterType.MixedContent, WebInspector.NetworkLogView.MixedContentFilterValues.All);
          }
  
          if (request.mixedContentType === "optionally-blockable") {
              this._suggestionBuilder.addItem(WebInspector.NetworkLogView.FilterType.MixedContent, WebInspector.NetworkLogView.MixedContentFilterValues.Displayed);
          }
  
          if (request.mixedContentType === "blockable") {
              var suggestion = request.wasBlocked() ? WebInspector.NetworkLogView.MixedContentFilterValues.Blocked : WebInspector.NetworkLogView.MixedContentFilterValues.BlockOverridden;
              this._suggestionBuilder.addItem(WebInspector.NetworkLogView.FilterType.MixedContent, suggestion);
          }
  
          var responseHeaders = request.responseHeaders;
          for (var i = 0, l = responseHeaders.length; i < l; ++i)
              this._suggestionBuilder.addItem(WebInspector.NetworkLogView.FilterType.HasResponseHeader, responseHeaders[i].name);
          var cookies = request.responseCookies;
          for (var i = 0, l = cookies ? cookies.length : 0; i < l; ++i) {
              var cookie = cookies[i];
              this._suggestionBuilder.addItem(WebInspector.NetworkLogView.FilterType.SetCookieDomain, cookie.domain());
              this._suggestionBuilder.addItem(WebInspector.NetworkLogView.FilterType.SetCookieName, cookie.name());
              this._suggestionBuilder.addItem(WebInspector.NetworkLogView.FilterType.SetCookieValue, cookie.value());
          }
  
          this._staleRequestIds[request.requestId] = true;
          this.dispatchEventToListeners(WebInspector.NetworkLogView.EventTypes.UpdateRequest, request);
          this._scheduleRefresh();
      },
  
      /**
       * @param {!WebInspector.Event} event
       */
      _mainFrameNavigated: function(event)
      {
          if (!this._recording)
              return;
  
          var frame = /** @type {!WebInspector.ResourceTreeFrame} */ (event.data);
          var loaderId = frame.loaderId;
  
          // Pick provisional load requests.
          var requestsToPick = [];
          var requests = frame.target().networkLog.requests();
          for (var i = 0; i < requests.length; ++i) {
              var request = requests[i];
              if (request.loaderId === loaderId)
                  requestsToPick.push(request);
          }
  
          if (!this._preserveLog) {
              this.reset();
              for (var i = 0; i < requestsToPick.length; ++i)
                  this._appendRequest(requestsToPick[i]);
          }
          for (var i = 0; i < requestsToPick.length; ++i) {
              var request = requestsToPick[i];
              var node = this._nodesByRequestId.get(request.requestId);
              if (node) {
                  node.markAsNavigationRequest();
                  break;
              }
          }
      },
  
      /**
       * @param {boolean} gridMode
       */
      switchViewMode: function(gridMode)
      {
          if (this._gridMode === gridMode)
              return;
          this._gridMode = gridMode;
  
          if (gridMode) {
              if (this._dataGrid.selectedNode)
                  this._dataGrid.selectedNode.selected = false;
          } else {
              this._removeAllNodeHighlights();
              this._popoverHelper.hidePopover();
          }
  
          this.element.classList.toggle("brief-mode", !gridMode);
          this._updateColumns();
      },
  
      /**
       * @return {number}
       */
      rowHeight: function()
      {
          return this._rowHeight;
      },
  
      _updateRowsSize: function()
      {
          var largeRows = !!this._networkLogLargeRowsSetting.get();
          this._rowHeight = largeRows ? 41 : 21;
          this._dataGrid.element.classList.toggle("small", !largeRows);
          this._timelineGrid.element.classList.toggle("small", !largeRows);
          this._dataGrid.scheduleUpdate();
      },
  
      /**
       * @param {!Element} element
       * @param {!Event} event
       * @return {!Element|!AnchorBox|undefined}
       */
      _getPopoverAnchor: function(element, event)
      {
          if (!this._gridMode)
              return;
          var anchor = element.enclosingNodeOrSelfWithClass("network-graph-bar") || element.enclosingNodeOrSelfWithClass("network-graph-label");
          if (anchor && anchor.parentElement.request && anchor.parentElement.request.timing)
              return anchor;
          anchor = element.enclosingNodeOrSelfWithClass("network-script-initiated");
          if (anchor && anchor.request) {
              var initiator = /** @type {!WebInspector.NetworkRequest} */ (anchor.request).initiator();
              if (initiator && initiator.stack)
                  return anchor;
          }
      },
  
      /**
       * @param {!Element} anchor
       * @param {!WebInspector.Popover} popover
       */
      _showPopover: function(anchor, popover)
      {
          var content;
          if (anchor.classList.contains("network-script-initiated")) {
              var request = /** @type {!WebInspector.NetworkRequest} */ (anchor.request);
              var initiator = /** @type {!NetworkAgent.Initiator} */ (request.initiator());
              content = WebInspector.DOMPresentationUtils.buildStackTracePreviewContents(request.target(), this._popupLinkifier, initiator.stack);
              popover.setCanShrink(true);
          } else {
              content = WebInspector.RequestTimingView.createTimingTable(anchor.parentElement.request, this._timeCalculator.minimumBoundary());
              popover.setCanShrink(false);
          }
          popover.showForAnchor(content, anchor);
      },
  
      _onHidePopover: function()
      {
          this._popupLinkifier.reset();
      },
  
      _updateColumns: function()
      {
          if (!this._dataGrid)
              return;
          var gridMode = this._gridMode;
          var visibleColumns = {"name": true};
          if (gridMode)
              visibleColumns["timeline"] = true;
          if (gridMode) {
              var columnsVisibility = this._columnsVisibilitySetting.get();
              for (var columnIdentifier in columnsVisibility)
                  visibleColumns[columnIdentifier] = columnsVisibility[columnIdentifier];
          }
  
          this._dataGrid.setColumnsVisiblity(visibleColumns);
      },
  
      /**
       * @param {string} columnIdentifier
       */
      _toggleColumnVisibility: function(columnIdentifier)
      {
          var columnsVisibility = this._columnsVisibilitySetting.get();
          columnsVisibility[columnIdentifier] = !columnsVisibility[columnIdentifier];
          this._columnsVisibilitySetting.set(columnsVisibility);
  
          this._updateColumns();
      },
  
      /**
       * @return {!Array.<string>}
       */
      _getConfigurableColumnIDs: function()
      {
          if (this._configurableColumnIDs)
              return this._configurableColumnIDs;
  
          var columnTitles = WebInspector.NetworkLogView._columnTitles;
          function compare(id1, id2)
          {
              return columnTitles[id1].compareTo(columnTitles[id2]);
          }
  
          var columnIDs = Object.keys(this._columnsVisibilitySetting.get());
          this._configurableColumnIDs = columnIDs.sort(compare);
          return this._configurableColumnIDs;
      },
  
      /**
       * @param {!Event} event
       */
      _contextMenu: function(event)
      {
          var contextMenu = new WebInspector.ContextMenu(event);
  
          if (this._gridMode && event.target.isSelfOrDescendant(this._dataGrid.headerTableBody)) {
              var columnsVisibility = this._columnsVisibilitySetting.get();
              var columnIDs = this._getConfigurableColumnIDs();
              var columnTitles = WebInspector.NetworkLogView._columnTitles;
              for (var i = 0; i < columnIDs.length; ++i) {
                  var columnIdentifier = columnIDs[i];
                  contextMenu.appendCheckboxItem(columnTitles[columnIdentifier], this._toggleColumnVisibility.bind(this, columnIdentifier), !!columnsVisibility[columnIdentifier]);
              }
              contextMenu.show();
              return;
          }
  
          var gridNode = this._dataGrid.dataGridNodeFromNode(event.target);
          var request = gridNode && gridNode.request();
  
          /**
           * @param {string} url
           */
          function openResourceInNewTab(url)
          {
              InspectorFrontendHost.openInNewTab(url);
          }
  
          if (request) {
              contextMenu.appendApplicableItems(request);
              if (request.requestHeadersText())
                  contextMenu.appendItem(WebInspector.UIString.capitalize("Copy ^request ^headers"), this._copyRequestHeaders.bind(this, request));
              if (request.responseHeadersText)
                  contextMenu.appendItem(WebInspector.UIString.capitalize("Copy ^response ^headers"), this._copyResponseHeaders.bind(this, request));
              if (request.finished)
                  contextMenu.appendItem(WebInspector.UIString.capitalize("Copy ^response"), this._copyResponse.bind(this, request));
  
              if (WebInspector.isWin()) {
                  contextMenu.appendItem(WebInspector.UIString("Copy as cURL (cmd)"), this._copyCurlCommand.bind(this, request, "win"));
                  contextMenu.appendItem(WebInspector.UIString("Copy as cURL (bash)"), this._copyCurlCommand.bind(this, request, "unix"));
              } else {
                  contextMenu.appendItem(WebInspector.UIString("Copy as cURL"), this._copyCurlCommand.bind(this, request, "unix"));
              }
          }
          contextMenu.appendItem(WebInspector.UIString.capitalize("Copy ^all as HAR"), this._copyAll.bind(this));
  
          contextMenu.appendSeparator();
          contextMenu.appendItem(WebInspector.UIString.capitalize("Save as HAR with ^content"), this._exportAll.bind(this));
  
          contextMenu.appendSeparator();
          contextMenu.appendItem(WebInspector.UIString.capitalize("Clear ^browser ^cache"), this._clearBrowserCache.bind(this));
          contextMenu.appendItem(WebInspector.UIString.capitalize("Clear ^browser ^cookies"), this._clearBrowserCookies.bind(this));
  
          var blockedSetting = WebInspector.moduleSetting("blockedURLs");
          if (request && Runtime.experiments.isEnabled("requestBlocking")) {  // Disabled until ready.
              contextMenu.appendSeparator();
  
              var urlWithoutScheme = request.parsedURL.urlWithoutScheme();
              if (urlWithoutScheme && blockedSetting.get().indexOf(urlWithoutScheme) === -1)
                  contextMenu.appendItem(WebInspector.UIString.capitalize("Block ^request URL"), addBlockedURL.bind(null, urlWithoutScheme));
  
              var domain = request.parsedURL.domain();
              if (domain && blockedSetting.get().indexOf(domain) === -1)
                  contextMenu.appendItem(WebInspector.UIString.capitalize("Block ^request ^domain"), addBlockedURL.bind(null, domain));
  
              function addBlockedURL(url)
              {
                  var list = blockedSetting.get();
                  list.push(url);
                  blockedSetting.set(list);
                  WebInspector.inspectorView.showViewInDrawer("network.blocked-urls");
              }
          }
  
          if (request && request.resourceType() === WebInspector.resourceTypes.XHR) {
              contextMenu.appendSeparator();
              contextMenu.appendItem(WebInspector.UIString("Replay XHR"), request.replayXHR.bind(request));
              contextMenu.appendSeparator();
          }
  
          contextMenu.show();
      },
  
      _harRequests: function()
      {
          var requests = this._nodesByRequestId.valuesArray().map(function(node) { return node.request(); });
          var httpRequests = requests.filter(WebInspector.NetworkLogView.HTTPRequestsFilter);
          return httpRequests.filter(WebInspector.NetworkLogView.FinishedRequestsFilter);
      },
  
      _copyAll: function()
      {
          var harArchive = {
              log: (new WebInspector.HARLog(this._harRequests())).build()
          };
          InspectorFrontendHost.copyText(JSON.stringify(harArchive, null, 2));
      },
  
      /**
       * @param {!WebInspector.NetworkRequest} request
       */
      _copyRequestHeaders: function(request)
      {
          InspectorFrontendHost.copyText(request.requestHeadersText());
      },
  
      /**
       * @param {!WebInspector.NetworkRequest} request
       */
      _copyResponse: function(request)
      {
          /**
           * @param {?string} content
           */
          function callback(content)
          {
              if (request.contentEncoded)
                  content = request.asDataURL();
              InspectorFrontendHost.copyText(content || "");
          }
          request.requestContent().then(callback);
      },
  
      /**
       * @param {!WebInspector.NetworkRequest} request
       */
      _copyResponseHeaders: function(request)
      {
          InspectorFrontendHost.copyText(request.responseHeadersText);
      },
  
      /**
       * @param {!WebInspector.NetworkRequest} request
       * @param {string} platform
       */
      _copyCurlCommand: function(request, platform)
      {
          InspectorFrontendHost.copyText(this._generateCurlCommand(request, platform));
      },
  
      _exportAll: function()
      {
          var filename = WebInspector.targetManager.inspectedPageDomain() + ".har";
          var stream = new WebInspector.FileOutputStream();
          stream.open(filename, openCallback.bind(this));
  
          /**
           * @param {boolean} accepted
           * @this {WebInspector.NetworkLogView}
           */
          function openCallback(accepted)
          {
              if (!accepted)
                  return;
              var progressIndicator = new WebInspector.ProgressIndicator();
              this._progressBarContainer.appendChild(progressIndicator.element);
              var harWriter = new WebInspector.HARWriter();
              harWriter.write(stream, this._harRequests(), progressIndicator);
          }
      },
  
      _clearBrowserCache: function()
      {
          if (confirm(WebInspector.UIString("Are you sure you want to clear browser cache?")))
              WebInspector.multitargetNetworkManager.clearBrowserCache();
      },
  
      _clearBrowserCookies: function()
      {
          if (confirm(WebInspector.UIString("Are you sure you want to clear browser cookies?")))
              WebInspector.multitargetNetworkManager.clearBrowserCookies();
      },
  
      /**
       * @param {!WebInspector.NetworkRequest} request
       * @return {boolean}
       */
      _matchRequest: function(request)
      {
          var re = this._searchRegExp;
          if (!re)
              return false;
          return re.test(request.name()) || (this._networkLogLargeRowsSetting.get() && re.test(request.path()));
      },
  
      _clearSearchMatchedList: function()
      {
          this._matchedRequestCount = -1;
          this._currentMatchedRequestNode = null;
          this._removeAllHighlights();
      },
  
      _removeAllHighlights: function()
      {
          this._removeAllNodeHighlights();
          for (var i = 0; i < this._highlightedSubstringChanges.length; ++i)
              WebInspector.revertDomChanges(this._highlightedSubstringChanges[i]);
          this._highlightedSubstringChanges = [];
      },
  
      /**
       * @param {number} n
       * @param {boolean} reveal
       */
      _highlightNthMatchedRequestForSearch: function(n, reveal)
      {
          this._removeAllHighlights();
  
          /** @type {!Array.<!WebInspector.NetworkDataGridNode>} */
          var nodes = this._dataGrid.rootNode().children;
          var matchCount = 0;
          var node = null;
          for (var i = 0; i < nodes.length; ++i) {
              if (nodes[i][WebInspector.NetworkLogView._isMatchingSearchQuerySymbol]) {
                  if (matchCount === n) {
                      node = nodes[i];
                      break;
                  }
                  matchCount++;
              }
          }
          if (!node) {
              this._currentMatchedRequestNode = null;
              return;
          }
  
          var request = node.request();
          if (reveal)
              WebInspector.Revealer.reveal(request);
          var highlightedSubstringChanges = node.highlightMatchedSubstring(this._searchRegExp);
          this._highlightedSubstringChanges.push(highlightedSubstringChanges);
  
          this._currentMatchedRequestNode = node;
          this._currentMatchedRequestIndex = n;
          this.dispatchEventToListeners(WebInspector.NetworkLogView.EventTypes.SearchIndexUpdated, n);
      },
  
      /**
       * @override
       * @param {!WebInspector.SearchableView.SearchConfig} searchConfig
       * @param {boolean} shouldJump
       * @param {boolean=} jumpBackwards
       */
      performSearch: function(searchConfig, shouldJump, jumpBackwards)
      {
          var query = searchConfig.query;
          var currentMatchedRequestNode = this._currentMatchedRequestNode;
          this._clearSearchMatchedList();
          this._searchRegExp = createPlainTextSearchRegex(query, "i");
  
          /** @type {!Array.<!WebInspector.NetworkDataGridNode>} */
          var nodes = this._dataGrid.rootNode().children;
          for (var i = 0; i < nodes.length; ++i)
              nodes[i][WebInspector.NetworkLogView._isMatchingSearchQuerySymbol] = this._matchRequest(nodes[i].request());
          var newMatchedRequestIndex = this._updateMatchCountAndFindMatchIndex(currentMatchedRequestNode);
          if (!newMatchedRequestIndex && jumpBackwards)
              newMatchedRequestIndex = this._matchedRequestCount - 1;
          this._highlightNthMatchedRequestForSearch(newMatchedRequestIndex, shouldJump);
      },
  
      /**
       * @override
       * @return {boolean}
       */
      supportsCaseSensitiveSearch: function()
      {
          return false;
      },
  
      /**
       * @override
       * @return {boolean}
       */
      supportsRegexSearch: function()
      {
          return true;
      },
  
      /**
       * @param {?WebInspector.NetworkDataGridNode} node
       * @return {number}
       */
      _updateMatchCountAndFindMatchIndex: function(node)
      {
          /** @type {!Array.<!WebInspector.NetworkDataGridNode>} */
          var nodes = this._dataGrid.rootNode().children;
          var matchCount = 0;
          var matchIndex = 0;
          for (var i = 0; i < nodes.length; ++i) {
              if (!nodes[i][WebInspector.NetworkLogView._isMatchingSearchQuerySymbol])
                  continue;
              if (node === nodes[i])
                  matchIndex = matchCount;
              matchCount++;
          }
          if (this._matchedRequestCount !== matchCount) {
              this._matchedRequestCount = matchCount;
              this.dispatchEventToListeners(WebInspector.NetworkLogView.EventTypes.SearchCountUpdated, matchCount);
          }
          return matchIndex;
      },
  
      /**
       * @param {number} index
       * @return {number}
       */
      _normalizeSearchResultIndex: function(index)
      {
          return (index + this._matchedRequestCount) % this._matchedRequestCount;
      },
  
      /**
       * @param {!WebInspector.NetworkDataGridNode} node
       * @return {boolean}
       */
      _applyFilter: function(node)
      {
          var request = node.request();
          if (this._timeFilter && !this._timeFilter(request))
              return false;
          var categoryName = request.resourceType().category().title;
          if (!this._resourceCategoryFilterUI.accept(categoryName))
              return false;
          if (this._dataURLFilterUI.checked() && request.parsedURL.isDataURL())
              return false;
          if (request.statusText === "Service Worker Fallback Required")
              return false;
          for (var i = 0; i < this._filters.length; ++i) {
              if (!this._filters[i](request))
                  return false;
          }
          return true;
      },
  
      /**
       * @param {string} query
       */
      _parseFilterQuery: function(query)
      {
          var parsedQuery;
          if (this._textFilterUI.isRegexChecked() && query !== "")
              parsedQuery = {text: [query], filters: []};
          else
              parsedQuery = this._suggestionBuilder.parseQuery(query);
  
          this._filters = parsedQuery.text.map(this._createTextFilter, this);
  
          var n = parsedQuery.filters.length;
          for (var i = 0; i < n; ++i) {
              var filter = parsedQuery.filters[i];
              var filterType = /** @type {!WebInspector.NetworkLogView.FilterType} */ (filter.type.toLowerCase());
              this._filters.push(this._createFilter(filterType, filter.data, filter.negative));
          }
      },
  
      /**
       * @param {string} text
       * @return {!WebInspector.NetworkLogView.Filter}
       */
      _createTextFilter: function(text)
      {
          var negative = false;
          if (!this._textFilterUI.isRegexChecked() && text[0] === "-" && text.length > 1) {
              negative = true;
              text = text.substring(1);
          }
          var regexp = this._textFilterUI.regex();
  
          var filter = WebInspector.NetworkLogView._requestNameOrPathFilter.bind(null, regexp);
          if (negative)
              filter = WebInspector.NetworkLogView._negativeFilter.bind(null, filter);
          return filter;
      },
  
      /**
       * @param {!WebInspector.NetworkLogView.FilterType} type
       * @param {string} value
       * @param {boolean} negative
       * @return {!WebInspector.NetworkLogView.Filter}
       */
      _createFilter: function(type, value, negative)
      {
          var filter = this._createSpecialFilter(type, value);
          if (!filter)
              return this._createTextFilter((negative ? "-" : "") + type + ":" + value);
          if (negative)
              return WebInspector.NetworkLogView._negativeFilter.bind(null, filter);
          return filter;
      },
  
      /**
       * @param {!WebInspector.NetworkLogView.FilterType} type
       * @param {string} value
       * @return {?WebInspector.NetworkLogView.Filter}
       */
      _createSpecialFilter: function(type, value)
      {
          switch (type) {
          case WebInspector.NetworkLogView.FilterType.Domain:
              return WebInspector.NetworkLogView._createRequestDomainFilter(value);
  
          case WebInspector.NetworkLogView.FilterType.HasResponseHeader:
              return WebInspector.NetworkLogView._requestResponseHeaderFilter.bind(null, value);
  
          case WebInspector.NetworkLogView.FilterType.Is:
              if (value.toLowerCase() === WebInspector.NetworkLogView.IsFilterType.Running)
                  return WebInspector.NetworkLogView._runningRequestFilter;
              break;
  
          case WebInspector.NetworkLogView.FilterType.LargerThan:
              return this._createSizeFilter(value.toLowerCase());
  
          case WebInspector.NetworkLogView.FilterType.Method:
              return WebInspector.NetworkLogView._requestMethodFilter.bind(null, value);
  
          case WebInspector.NetworkLogView.FilterType.MimeType:
              return WebInspector.NetworkLogView._requestMimeTypeFilter.bind(null, value);
  
          case WebInspector.NetworkLogView.FilterType.MixedContent:
              return WebInspector.NetworkLogView._requestMixedContentFilter.bind(null, /** @type {!WebInspector.NetworkLogView.MixedContentFilterValues} */ (value));
  
          case WebInspector.NetworkLogView.FilterType.Scheme:
              return WebInspector.NetworkLogView._requestSchemeFilter.bind(null, value);
  
          case WebInspector.NetworkLogView.FilterType.SetCookieDomain:
              return WebInspector.NetworkLogView._requestSetCookieDomainFilter.bind(null, value);
  
          case WebInspector.NetworkLogView.FilterType.SetCookieName:
              return WebInspector.NetworkLogView._requestSetCookieNameFilter.bind(null, value);
  
          case WebInspector.NetworkLogView.FilterType.SetCookieValue:
              return WebInspector.NetworkLogView._requestSetCookieValueFilter.bind(null, value);
  
          case WebInspector.NetworkLogView.FilterType.StatusCode:
              return WebInspector.NetworkLogView._statusCodeFilter.bind(null, value);
          }
          return null;
      },
  
      /**
       * @param {string} value
       * @return {?WebInspector.NetworkLogView.Filter}
       */
      _createSizeFilter: function(value)
      {
          var multiplier = 1;
          if (value.endsWith("k")) {
              multiplier = 1024;
              value = value.substring(0, value.length - 1);
          } else if (value.endsWith("m")) {
              multiplier = 1024 * 1024;
              value = value.substring(0, value.length - 1);
          }
          var quantity  = Number(value);
          if (isNaN(quantity))
              return null;
          return WebInspector.NetworkLogView._requestSizeLargerThanFilter.bind(null, quantity * multiplier);
      },
  
      _filterRequests: function()
      {
          this._removeAllHighlights();
          this._invalidateAllItems();
      },
  
      /**
       * @override
       */
      jumpToPreviousSearchResult: function()
      {
          if (!this._matchedRequestCount)
              return;
          var index = this._normalizeSearchResultIndex(this._currentMatchedRequestIndex - 1);
          this._highlightNthMatchedRequestForSearch(index, true);
      },
  
      /**
       * @override
       */
      jumpToNextSearchResult: function()
      {
          if (!this._matchedRequestCount)
              return;
          var index = this._normalizeSearchResultIndex(this._currentMatchedRequestIndex + 1);
          this._highlightNthMatchedRequestForSearch(index, true);
      },
  
      /**
       * @override
       */
      searchCanceled: function()
      {
          delete this._searchRegExp;
          this._clearSearchMatchedList();
          this.dispatchEventToListeners(WebInspector.NetworkLogView.EventTypes.SearchCountUpdated, 0);
      },
  
      /**
       * @param {!WebInspector.NetworkRequest} request
       */
      revealAndHighlightRequest: function(request)
      {
          this._removeAllNodeHighlights();
  
          var node = this._nodesByRequestId.get(request.requestId);
          if (node) {
              node.reveal();
              this._highlightNode(node);
          }
      },
  
      _removeAllNodeHighlights: function()
      {
          if (this._highlightedNode) {
              this._highlightedNode.element().classList.remove("highlighted-row");
              delete this._highlightedNode;
          }
      },
  
      /**
       * @param {!WebInspector.NetworkDataGridNode} node
       */
      _highlightNode: function(node)
      {
          WebInspector.runCSSAnimationOnce(node.element(), "highlighted-row");
          this._highlightedNode = node;
      },
  
      /**
       * @param {!WebInspector.NetworkRequest} request
       * @param {string} platform
       * @return {string}
       */
      _generateCurlCommand: function(request, platform)
      {
          var command = ["curl"];
          // These headers are derived from URL (except "version") and would be added by cURL anyway.
          var ignoredHeaders = {"host": 1, "method": 1, "path": 1, "scheme": 1, "version": 1};
  
          function escapeStringWin(str)
          {
              /* Replace quote by double quote (but not by \") because it is
                 recognized by both cmd.exe and MS Crt arguments parser.
  
                 Replace % by "%" because it could be expanded to an environment
                 variable value. So %% becomes "%""%". Even if an env variable ""
                 (2 doublequotes) is declared, the cmd.exe will not
                 substitute it with its value.
  
                 Replace each backslash with double backslash to make sure
                 MS Crt arguments parser won't collapse them.
  
                 Replace new line outside of quotes since cmd.exe doesn't let
                 to do it inside.
              */
              return "\"" + str.replace(/"/g, "\"\"")
                               .replace(/%/g, "\"%\"")
                               .replace(/\\/g, "\\\\")
                               .replace(/[\r\n]+/g, "\"^$&\"") + "\"";
          }
  
          function escapeStringPosix(str)
          {
              function escapeCharacter(x)
              {
                  var code = x.charCodeAt(0);
                  if (code < 256) {
                      // Add leading zero when needed to not care about the next character.
                      return code < 16 ? "\\x0" + code.toString(16) : "\\x" + code.toString(16);
                   }
                   code = code.toString(16);
                   return "\\u" + ("0000" + code).substr(code.length, 4);
               }
  
              if (/[^\x20-\x7E]|\'/.test(str)) {
                  // Use ANSI-C quoting syntax.
                  return "$\'" + str.replace(/\\/g, "\\\\")
                                    .replace(/\'/g, "\\\'")
                                    .replace(/\n/g, "\\n")
                                    .replace(/\r/g, "\\r")
                                    .replace(/[^\x20-\x7E]/g, escapeCharacter) + "'";
              } else {
                  // Use single quote syntax.
                  return "'" + str + "'";
              }
          }
  
          // cURL command expected to run on the same platform that DevTools run
          // (it may be different from the inspected page platform).
          var escapeString = platform === "win" ? escapeStringWin : escapeStringPosix;
  
          command.push(escapeString(request.url).replace(/[[{}\]]/g, "\\$&"));
  
          var inferredMethod = "GET";
          var data = [];
          var requestContentType = request.requestContentType();
          if (requestContentType && requestContentType.startsWith("application/x-www-form-urlencoded") && request.requestFormData) {
             data.push("--data");
             data.push(escapeString(request.requestFormData));
             ignoredHeaders["content-length"] = true;
             inferredMethod = "POST";
          } else if (request.requestFormData) {
             data.push("--data-binary");
             data.push(escapeString(request.requestFormData));
             ignoredHeaders["content-length"] = true;
             inferredMethod = "POST";
          }
  
          if (request.requestMethod !== inferredMethod) {
              command.push("-X");
              command.push(request.requestMethod);
          }
  
          var requestHeaders = request.requestHeaders();
          for (var i = 0; i < requestHeaders.length; i++) {
              var header = requestHeaders[i];
              var name = header.name.replace(/^:/, ""); // Translate SPDY v3 headers to HTTP headers.
              if (name.toLowerCase() in ignoredHeaders)
                  continue;
              command.push("-H");
              command.push(escapeString(name + ": " + header.value));
          }
          command = command.concat(data);
          command.push("--compressed");
  
          if (request.securityState() === SecurityAgent.SecurityState.Insecure)
              command.push("--insecure");
          return command.join(" ");
      },
  
      __proto__: WebInspector.VBox.prototype
  }
  
  /** @typedef {function(!WebInspector.NetworkRequest): boolean} */
  WebInspector.NetworkLogView.Filter;
  
  /**
   * @param {!WebInspector.NetworkLogView.Filter} filter
   * @param {!WebInspector.NetworkRequest} request
   * @return {boolean}
   */
  WebInspector.NetworkLogView._negativeFilter = function(filter, request)
  {
      return !filter(request);
  }
  
  /**
   * @param {?RegExp} regex
   * @param {!WebInspector.NetworkRequest} request
   * @return {boolean}
   */
  WebInspector.NetworkLogView._requestNameOrPathFilter = function(regex, request)
  {
      if (!regex)
          return false;
      return regex.test(request.name()) || regex.test(request.path());
  }
  
  /**
   * @param {string} domain
   * @return {!Array.<string>}
   */
  WebInspector.NetworkLogView._subdomains = function(domain)
  {
      var result = [domain];
      var indexOfPeriod = domain.indexOf(".");
      while (indexOfPeriod !== -1) {
          result.push("*" + domain.substring(indexOfPeriod));
          indexOfPeriod = domain.indexOf(".", indexOfPeriod + 1);
      }
      return result;
  }
  
  /**
   * @param {string} value
   * @return {!WebInspector.NetworkLogView.Filter}
   */
  WebInspector.NetworkLogView._createRequestDomainFilter = function(value)
  {
      /**
       * @param {string} string
       * @return {string}
       */
      function escapeForRegExp(string)
      {
          return string.escapeForRegExp();
      }
      var escapedPattern = value.split("*").map(escapeForRegExp).join(".*");
      return WebInspector.NetworkLogView._requestDomainFilter.bind(null, new RegExp("^" + escapedPattern + "$", "i"));
  }
  
  /**
   * @param {!RegExp} regex
   * @param {!WebInspector.NetworkRequest} request
   * @return {boolean}
   */
  WebInspector.NetworkLogView._requestDomainFilter = function(regex, request)
  {
      return regex.test(request.domain);
  }
  
  /**
   * @param {!WebInspector.NetworkRequest} request
   * @return {boolean}
   */
  WebInspector.NetworkLogView._runningRequestFilter = function(request)
  {
      return !request.finished;
  }
  
  /**
   * @param {string} value
   * @param {!WebInspector.NetworkRequest} request
   * @return {boolean}
   */
  WebInspector.NetworkLogView._requestResponseHeaderFilter = function(value, request)
  {
      return request.responseHeaderValue(value) !== undefined;
  }
  
  /**
   * @param {string} value
   * @param {!WebInspector.NetworkRequest} request
   * @return {boolean}
   */
  WebInspector.NetworkLogView._requestMethodFilter = function(value, request)
  {
      return request.requestMethod === value;
  }
  
  /**
   * @param {string} value
   * @param {!WebInspector.NetworkRequest} request
   * @return {boolean}
   */
  WebInspector.NetworkLogView._requestMimeTypeFilter = function(value, request)
  {
      return request.mimeType === value;
  }
  
  /**
   * @param {!WebInspector.NetworkLogView.MixedContentFilterValues} value
   * @param {!WebInspector.NetworkRequest} request
   * @return {boolean}
   */
  WebInspector.NetworkLogView._requestMixedContentFilter = function(value, request)
  {
      if (value === WebInspector.NetworkLogView.MixedContentFilterValues.Displayed) {
          return request.mixedContentType === "optionally-blockable";
      } else if (value === WebInspector.NetworkLogView.MixedContentFilterValues.Blocked) {
          return request.mixedContentType === "blockable" && request.wasBlocked();
      } else if (value === WebInspector.NetworkLogView.MixedContentFilterValues.BlockOverridden) {
          return request.mixedContentType === "blockable" && !request.wasBlocked();
      } else if (value === WebInspector.NetworkLogView.MixedContentFilterValues.All) {
          return request.mixedContentType !== "none";
      }
      return false;
  }
  
  /**
   * @param {string} value
   * @param {!WebInspector.NetworkRequest} request
   * @return {boolean}
   */
  WebInspector.NetworkLogView._requestSchemeFilter = function(value, request)
  {
      return request.scheme === value;
  }
  
  /**
   * @param {string} value
   * @param {!WebInspector.NetworkRequest} request
   * @return {boolean}
   */
  WebInspector.NetworkLogView._requestSetCookieDomainFilter = function(value, request)
  {
      var cookies = request.responseCookies;
      for (var i = 0, l = cookies ? cookies.length : 0; i < l; ++i) {
          if (cookies[i].domain() === value)
              return true;
      }
      return false;
  }
  
  /**
   * @param {string} value
   * @param {!WebInspector.NetworkRequest} request
   * @return {boolean}
   */
  WebInspector.NetworkLogView._requestSetCookieNameFilter = function(value, request)
  {
      var cookies = request.responseCookies;
      for (var i = 0, l = cookies ? cookies.length : 0; i < l; ++i) {
          if (cookies[i].name() === value)
              return true;
      }
      return false;
  }
  
  /**
   * @param {string} value
   * @param {!WebInspector.NetworkRequest} request
   * @return {boolean}
   */
  WebInspector.NetworkLogView._requestSetCookieValueFilter = function(value, request)
  {
      var cookies = request.responseCookies;
      for (var i = 0, l = cookies ? cookies.length : 0; i < l; ++i) {
          if (cookies[i].value() === value)
              return true;
      }
      return false;
  }
  
  /**
   * @param {number} value
   * @param {!WebInspector.NetworkRequest} request
   * @return {boolean}
   */
  WebInspector.NetworkLogView._requestSizeLargerThanFilter = function(value, request)
  {
      return request.transferSize >= value;
  }
  
  /**
   * @param {string} value
   * @param {!WebInspector.NetworkRequest} request
   * @return {boolean}
   */
  WebInspector.NetworkLogView._statusCodeFilter = function(value, request)
  {
      return ("" + request.statusCode) === value;
  }
  
  /**
   * @param {!WebInspector.NetworkRequest} request
   * @return {boolean}
   */
  WebInspector.NetworkLogView.HTTPRequestsFilter = function(request)
  {
      return request.parsedURL.isValid && (request.scheme in WebInspector.NetworkLogView.HTTPSchemas);
  }
  
  /**
   * @param {!WebInspector.NetworkRequest} request
   * @return {boolean}
   */
  WebInspector.NetworkLogView.FinishedRequestsFilter = function(request)
  {
      return request.finished;
  }
  
  /**
   * @param {number} windowStart
   * @param {number} windowEnd
   * @param {!WebInspector.NetworkRequest} request
   * @return {boolean}
   */
  WebInspector.NetworkLogView._requestTimeFilter = function(windowStart, windowEnd, request)
  {
      if (request.issueTime() > windowEnd)
          return false;
      if (request.endTime !== -1 && request.endTime < windowStart)
          return false;
      return true;
  }
  
  WebInspector.NetworkLogView.EventTypes = {
      RequestSelected: "RequestSelected",
      SearchCountUpdated: "SearchCountUpdated",
      SearchIndexUpdated: "SearchIndexUpdated",
      UpdateRequest: "UpdateRequest"
  };
  