import{NetworkNode,NetworkRequestNode}from'./NetworkDataGridNode.js';import{NetworkLogView}from'./NetworkLogView.js';import{NetworkManageCustomHeadersView}from'./NetworkManageCustomHeadersView.js';import{NetworkTimeCalculator,NetworkTransferDurationCalculator,NetworkTransferTimeCalculator,}from'./NetworkTimeCalculator.js';import{NetworkWaterfallColumn}from'./NetworkWaterfallColumn.js';import{RequestInitiatorView}from'./RequestInitiatorView.js';export class NetworkLogViewColumns{constructor(networkLogView,timeCalculator,durationCalculator,networkLogLargeRowsSetting){this._networkLogView=networkLogView;this._persistantSettings=self.Common.settings.createSetting('networkLogColumns',{});this._networkLogLargeRowsSetting=networkLogLargeRowsSetting;this._networkLogLargeRowsSetting.addChangeListener(this._updateRowsSize,this);this._eventDividers=new Map();this._eventDividersShown=false;this._gridMode=true;this._columns=[];this._waterfallRequestsAreStale=false;this._waterfallScrollerWidthIsStale=true;this._popupLinkifier=new Components.Linkifier();this._calculatorsMap=new Map();this._calculatorsMap.set(_calculatorTypes.Time,timeCalculator);this._calculatorsMap.set(_calculatorTypes.Duration,durationCalculator);this._lastWheelTime=0;this._setupDataGrid();this._setupWaterfall();}
static _convertToDataGridDescriptor(columnConfig){return({id:columnConfig.id,title:columnConfig.title,sortable:columnConfig.sortable,align:columnConfig.align,nonSelectable:columnConfig.nonSelectable,weight:columnConfig.weight,allowInSortByEvenWhenHidden:columnConfig.allowInSortByEvenWhenHidden,});}
wasShown(){this._updateRowsSize();}
willHide(){this._popoverHelper.hidePopover();}
reset(){if(this._popoverHelper){this._popoverHelper.hidePopover();}
this._eventDividers.clear();}
_setupDataGrid(){const defaultColumns=_defaultColumns;const defaultColumnConfig=_defaultColumnConfig;this._columns=([]);for(const currentConfigColumn of defaultColumns){const columnConfig=(Object.assign({},defaultColumnConfig,currentConfigColumn));columnConfig.id=columnConfig.id;if(columnConfig.subtitle){columnConfig.titleDOMFragment=this._makeHeaderFragment(columnConfig.title,columnConfig.subtitle);}
this._columns.push(columnConfig);}
this._loadCustomColumnsAndSettings();this._popoverHelper=new UI.PopoverHelper(this._networkLogView.element,this._getPopoverRequest.bind(this));this._popoverHelper.setHasPadding(true);this._popoverHelper.setTimeout(300,300);this._dataGrid=new DataGrid.SortableDataGrid({displayName:ls`Network Log`,columns:this._columns.map(NetworkLogViewColumns._convertToDataGridDescriptor)});this._dataGrid.element.addEventListener('mousedown',event=>{if(!this._dataGrid.selectedNode&&event.button){event.consume();}},true);this._dataGridScroller=this._dataGrid.scrollContainer;this._updateColumns();this._dataGrid.addEventListener(DataGrid.DataGrid.Events.SortingChanged,this._sortHandler,this);this._dataGrid.setHeaderContextMenuCallback(this._innerHeaderContextMenu.bind(this));this._activeWaterfallSortId=WaterfallSortIds.StartTime;this._dataGrid.markColumnAsSortedBy(_initialSortColumn,DataGrid.DataGrid.Order.Ascending);this._splitWidget=new UI.SplitWidget(true,true,'networkPanelSplitViewWaterfall',200);const widget=this._dataGrid.asWidget();widget.setMinimumSize(150,0);this._splitWidget.setMainWidget(widget);}
_setupWaterfall(){this._waterfallColumn=new NetworkWaterfallColumn(this._networkLogView.calculator());this._waterfallColumn.element.addEventListener('contextmenu',handleContextMenu.bind(this));this._waterfallColumn.element.addEventListener('mousewheel',this._onMouseWheel.bind(this,false),{passive:true});this._dataGridScroller.addEventListener('mousewheel',this._onMouseWheel.bind(this,true),true);this._waterfallScroller=this._waterfallColumn.contentElement.createChild('div','network-waterfall-v-scroll');this._waterfallScrollerContent=this._waterfallScroller.createChild('div','network-waterfall-v-scroll-content');this._dataGrid.addEventListener(DataGrid.DataGrid.Events.PaddingChanged,()=>{this._waterfallScrollerWidthIsStale=true;this._syncScrollers();});this._dataGrid.addEventListener(DataGrid.ViewportDataGrid.Events.ViewportCalculated,this._redrawWaterfallColumn.bind(this));this._createWaterfallHeader();this._waterfallColumn.contentElement.classList.add('network-waterfall-view');this._waterfallColumn.setMinimumSize(100,0);this._splitWidget.setSidebarWidget(this._waterfallColumn);this.switchViewMode(false);function handleContextMenu(event){const node=this._waterfallColumn.getNodeFromPoint(event.offsetX,event.offsetY);if(!node){return;}
const request=node.request();if(!request){return;}
const contextMenu=new UI.ContextMenu(event);this._networkLogView.handleContextMenuForRequest(contextMenu,request);contextMenu.show();}}
_onMouseWheel(shouldConsume,event){if(shouldConsume){event.consume(true);}
const hasRecentWheel=Date.now()-this._lastWheelTime<80;this._activeScroller.scrollBy({top:-event.wheelDeltaY,behavior:hasRecentWheel?'instant':'smooth'});this._syncScrollers();this._lastWheelTime=Date.now();}
_syncScrollers(){if(!this._waterfallColumn.isShowing()){return;}
this._waterfallScrollerContent.style.height=this._dataGridScroller.scrollHeight+'px';this._updateScrollerWidthIfNeeded();this._dataGridScroller.scrollTop=this._waterfallScroller.scrollTop;}
_updateScrollerWidthIfNeeded(){if(this._waterfallScrollerWidthIsStale){this._waterfallScrollerWidthIsStale=false;this._waterfallColumn.setRightPadding(this._waterfallScroller.offsetWidth-this._waterfallScrollerContent.offsetWidth);}}
_redrawWaterfallColumn(){if(!this._waterfallRequestsAreStale){this._updateScrollerWidthIfNeeded();this._waterfallColumn.update(this._activeScroller.scrollTop,this._eventDividersShown?this._eventDividers:undefined);return;}
this._syncScrollers();const nodes=this._networkLogView.flatNodesList();this._waterfallColumn.update(this._activeScroller.scrollTop,this._eventDividers,nodes);}
_createWaterfallHeader(){this._waterfallHeaderElement=this._waterfallColumn.contentElement.createChild('div','network-waterfall-header');this._waterfallHeaderElement.addEventListener('click',waterfallHeaderClicked.bind(this));this._waterfallHeaderElement.addEventListener('contextmenu',event=>this._innerHeaderContextMenu(new UI.ContextMenu(event)));const innerElement=this._waterfallHeaderElement.createChild('div');innerElement.textContent=Common.UIString('Waterfall');this._waterfallColumnSortIcon=UI.Icon.create('','sort-order-icon');this._waterfallHeaderElement.createChild('div','sort-order-icon-container').appendChild(this._waterfallColumnSortIcon);function waterfallHeaderClicked(){const sortOrders=DataGrid.DataGrid.Order;const wasSortedByWaterfall=this._dataGrid.sortColumnId()==='waterfall';const wasSortedAscending=this._dataGrid.isSortOrderAscending();const sortOrder=wasSortedByWaterfall&&wasSortedAscending?sortOrders.Descending:sortOrders.Ascending;this._dataGrid.markColumnAsSortedBy('waterfall',sortOrder);this._sortHandler();}}
setCalculator(x){this._waterfallColumn.setCalculator(x);}
scheduleRefresh(){this._waterfallColumn.scheduleDraw();}
_updateRowsSize(){const largeRows=!!this._networkLogLargeRowsSetting.get();this._dataGrid.element.classList.toggle('small',!largeRows);this._dataGrid.scheduleUpdate();this._waterfallScrollerWidthIsStale=true;this._waterfallColumn.setRowHeight(largeRows?41:21);this._waterfallScroller.classList.toggle('small',!largeRows);this._waterfallHeaderElement.classList.toggle('small',!largeRows);window.requestAnimationFrame(()=>{this._waterfallColumn.setHeaderHeight(this._waterfallScroller.offsetTop);});}
show(element){this._splitWidget.show(element);}
setHidden(value){UI.ARIAUtils.setHidden(this._splitWidget.element,value);}
dataGrid(){return this._dataGrid;}
sortByCurrentColumn(){this._sortHandler();}
_sortHandler(){const columnId=this._dataGrid.sortColumnId();this._networkLogView.removeAllNodeHighlights();this._waterfallRequestsAreStale=true;if(columnId==='waterfall'){if(this._dataGrid.sortOrder()===DataGrid.DataGrid.Order.Ascending){this._waterfallColumnSortIcon.setIconType('smallicon-triangle-up');}else{this._waterfallColumnSortIcon.setIconType('smallicon-triangle-down');}
const sortFunction=NetworkRequestNode.RequestPropertyComparator.bind(null,this._activeWaterfallSortId);this._dataGrid.sortNodes(sortFunction,!this._dataGrid.isSortOrderAscending());this._dataGridSortedForTest();return;}
this._waterfallColumnSortIcon.setIconType('');const columnConfig=this._columns.find(columnConfig=>columnConfig.id===columnId);if(!columnConfig||!columnConfig.sortingFunction){return;}
this._dataGrid.sortNodes(columnConfig.sortingFunction,!this._dataGrid.isSortOrderAscending());this._dataGridSortedForTest();}
_dataGridSortedForTest(){}
_updateColumns(){if(!this._dataGrid){return;}
const visibleColumns=({});if(this._gridMode){for(const columnConfig of this._columns){visibleColumns[columnConfig.id]=columnConfig.visible;}}else{const visibleColumn=this._columns.find(c=>c.hideableGroup==='path'&&c.visible);if(visibleColumn){visibleColumns[visibleColumn.id]=true;}else{visibleColumns.name=true;}}
this._dataGrid.setColumnsVisiblity(visibleColumns);}
switchViewMode(gridMode){if(this._gridMode===gridMode){return;}
this._gridMode=gridMode;if(gridMode){this._splitWidget.showBoth();this._activeScroller=this._waterfallScroller;this._waterfallScroller.scrollTop=this._dataGridScroller.scrollTop;this._dataGrid.setScrollContainer(this._waterfallScroller);}else{this._networkLogView.removeAllNodeHighlights();this._splitWidget.hideSidebar();this._activeScroller=this._dataGridScroller;this._dataGrid.setScrollContainer(this._dataGridScroller);}
this._networkLogView.element.classList.toggle('brief-mode',!gridMode);this._updateColumns();this._updateRowsSize();}
_toggleColumnVisibility(columnConfig){this._loadCustomColumnsAndSettings();columnConfig.visible=!columnConfig.visible;this._saveColumnsSettings();this._updateColumns();}
_saveColumnsSettings(){const saveableSettings={};for(const columnConfig of this._columns){saveableSettings[columnConfig.id]={visible:columnConfig.visible,title:columnConfig.title};}
this._persistantSettings.set(saveableSettings);}
_loadCustomColumnsAndSettings(){const savedSettings=this._persistantSettings.get();const columnIds=Object.keys(savedSettings);for(const columnId of columnIds){const setting=savedSettings[columnId];let columnConfig=this._columns.find(columnConfig=>columnConfig.id===columnId);if(!columnConfig){columnConfig=this._addCustomHeader(setting.title,columnId);}
if(columnConfig.hideable&&typeof setting.visible==='boolean'){columnConfig.visible=!!setting.visible;}
if(typeof setting.title==='string'){columnConfig.title=setting.title;}}}
_makeHeaderFragment(title,subtitle){const fragment=createDocumentFragment();fragment.createTextChild(title);const subtitleDiv=fragment.createChild('div','network-header-subtitle');subtitleDiv.createTextChild(subtitle);return fragment;}
_innerHeaderContextMenu(contextMenu){const columnConfigs=this._columns.filter(columnConfig=>columnConfig.hideable);const nonResponseHeaders=columnConfigs.filter(columnConfig=>!columnConfig.isResponseHeader);const hideableGroups=new Map();const nonResponseHeadersWithoutGroup=[];for(const columnConfig of nonResponseHeaders){if(!columnConfig.hideableGroup){nonResponseHeadersWithoutGroup.push(columnConfig);}else{const name=columnConfig.hideableGroup;if(!hideableGroups.has(name)){hideableGroups.set(name,[]);}
hideableGroups.get(name).push(columnConfig);}}
for(const group of hideableGroups.values()){const visibleColumns=group.filter(columnConfig=>columnConfig.visible);for(const columnConfig of group){const isDisabled=visibleColumns.length===1&&visibleColumns[0]===columnConfig;contextMenu.headerSection().appendCheckboxItem(columnConfig.title,this._toggleColumnVisibility.bind(this,columnConfig),columnConfig.visible,isDisabled);}
contextMenu.headerSection().appendSeparator();}
for(const columnConfig of nonResponseHeadersWithoutGroup){contextMenu.headerSection().appendCheckboxItem(columnConfig.title,this._toggleColumnVisibility.bind(this,columnConfig),columnConfig.visible);}
const responseSubMenu=contextMenu.footerSection().appendSubMenuItem(Common.UIString('Response Headers'));const responseHeaders=columnConfigs.filter(columnConfig=>columnConfig.isResponseHeader);for(const columnConfig of responseHeaders){responseSubMenu.defaultSection().appendCheckboxItem(columnConfig.title,this._toggleColumnVisibility.bind(this,columnConfig),columnConfig.visible);}
responseSubMenu.footerSection().appendItem(Common.UIString('Manage Header Columns\u2026'),this._manageCustomHeaderDialog.bind(this));const waterfallSortIds=WaterfallSortIds;const waterfallSubMenu=contextMenu.footerSection().appendSubMenuItem(Common.UIString('Waterfall'));waterfallSubMenu.defaultSection().appendCheckboxItem(Common.UIString('Start Time'),setWaterfallMode.bind(this,waterfallSortIds.StartTime),this._activeWaterfallSortId===waterfallSortIds.StartTime);waterfallSubMenu.defaultSection().appendCheckboxItem(Common.UIString('Response Time'),setWaterfallMode.bind(this,waterfallSortIds.ResponseTime),this._activeWaterfallSortId===waterfallSortIds.ResponseTime);waterfallSubMenu.defaultSection().appendCheckboxItem(Common.UIString('End Time'),setWaterfallMode.bind(this,waterfallSortIds.EndTime),this._activeWaterfallSortId===waterfallSortIds.EndTime);waterfallSubMenu.defaultSection().appendCheckboxItem(Common.UIString('Total Duration'),setWaterfallMode.bind(this,waterfallSortIds.Duration),this._activeWaterfallSortId===waterfallSortIds.Duration);waterfallSubMenu.defaultSection().appendCheckboxItem(Common.UIString('Latency'),setWaterfallMode.bind(this,waterfallSortIds.Latency),this._activeWaterfallSortId===waterfallSortIds.Latency);function setWaterfallMode(sortId){let calculator=this._calculatorsMap.get(_calculatorTypes.Time);const waterfallSortIds=WaterfallSortIds;if(sortId===waterfallSortIds.Duration||sortId===waterfallSortIds.Latency){calculator=this._calculatorsMap.get(_calculatorTypes.Duration);}
this._networkLogView.setCalculator(calculator);this._activeWaterfallSortId=sortId;this._dataGrid.markColumnAsSortedBy('waterfall',DataGrid.DataGrid.Order.Ascending);this._sortHandler();}}
_manageCustomHeaderDialog(){const customHeaders=[];for(const columnConfig of this._columns){if(columnConfig.isResponseHeader){customHeaders.push({title:columnConfig.title,editable:columnConfig.isCustomHeader});}}
const manageCustomHeaders=new NetworkManageCustomHeadersView(customHeaders,headerTitle=>!!this._addCustomHeader(headerTitle),this._changeCustomHeader.bind(this),this._removeCustomHeader.bind(this));const dialog=new UI.Dialog();manageCustomHeaders.show(dialog.contentElement);dialog.setSizeBehavior(UI.GlassPane.SizeBehavior.MeasureContent);dialog.show(this._networkLogView.element);}
_removeCustomHeader(headerId){headerId=headerId.toLowerCase();const index=this._columns.findIndex(columnConfig=>columnConfig.id===headerId);if(index===-1){return false;}
this._columns.splice(index,1);this._dataGrid.removeColumn(headerId);this._saveColumnsSettings();this._updateColumns();return true;}
_addCustomHeader(headerTitle,headerId,index){if(!headerId){headerId=headerTitle.toLowerCase();}
if(index===undefined){index=this._columns.length-1;}
const currentColumnConfig=this._columns.find(columnConfig=>columnConfig.id===headerId);if(currentColumnConfig){return null;}
const columnConfigBase=Object.assign({},_defaultColumnConfig,{id:headerId,title:headerTitle,isResponseHeader:true,isCustomHeader:true,visible:true,sortingFunction:NetworkRequestNode.ResponseHeaderStringComparator.bind(null,headerId)});const columnConfig=(columnConfigBase);this._columns.splice(index,0,columnConfig);if(this._dataGrid){this._dataGrid.addColumn(NetworkLogViewColumns._convertToDataGridDescriptor(columnConfig),index);}
this._saveColumnsSettings();this._updateColumns();return columnConfig;}
_changeCustomHeader(oldHeaderId,newHeaderTitle,newHeaderId){if(!newHeaderId){newHeaderId=newHeaderTitle.toLowerCase();}
oldHeaderId=oldHeaderId.toLowerCase();const oldIndex=this._columns.findIndex(columnConfig=>columnConfig.id===oldHeaderId);const oldColumnConfig=this._columns[oldIndex];const currentColumnConfig=this._columns.find(columnConfig=>columnConfig.id===newHeaderId);if(!oldColumnConfig||(currentColumnConfig&&oldHeaderId!==newHeaderId)){return false;}
this._removeCustomHeader(oldHeaderId);this._addCustomHeader(newHeaderTitle,newHeaderId,oldIndex);return true;}
_getPopoverRequest(event){if(!this._gridMode){return null;}
const hoveredNode=this._networkLogView.hoveredNode();if(!hoveredNode){return null;}
const anchor=event.target.enclosingNodeOrSelfWithClass('network-script-initiated');if(!anchor){return null;}
const request=hoveredNode.request();if(!request){return null;}
return{box:anchor.boxInWindow(),show:popover=>{const content=RequestInitiatorView.createStackTracePreview((request),this._popupLinkifier,false,()=>popover.setSizeBehavior(UI.GlassPane.SizeBehavior.MeasureContent));popover.contentElement.appendChild(content.element);return Promise.resolve(true);},hide:this._popupLinkifier.reset.bind(this._popupLinkifier)};}
addEventDividers(times,className){let color='transparent';switch(className){case'network-dcl-divider':color='#0867CB';break;case'network-load-divider':color='#B31412';break;default:return;}
const currentTimes=this._eventDividers.get(color)||[];this._eventDividers.set(color,currentTimes.concat(times));this._networkLogView.scheduleRefresh();}
hideEventDividers(){this._eventDividersShown=true;this._redrawWaterfallColumn();}
showEventDividers(){this._eventDividersShown=false;this._redrawWaterfallColumn();}
selectFilmStripFrame(time){this._eventDividers.set(_filmStripDividerColor,[time]);this._redrawWaterfallColumn();}
clearFilmStripFrame(){this._eventDividers.delete(_filmStripDividerColor);this._redrawWaterfallColumn();}}
export const _initialSortColumn='waterfall';export const _calculatorTypes={Duration:'Duration',Time:'Time'};export const _defaultColumnConfig={subtitle:null,visible:false,weight:6,sortable:true,hideable:true,hideableGroup:null,nonSelectable:false,isResponseHeader:false,isCustomHeader:false,allowInSortByEvenWhenHidden:false};export const _defaultColumns=[{id:'name',title:Common.UIString('Name'),subtitle:Common.UIString('Path'),visible:true,weight:20,hideable:true,hideableGroup:'path',sortingFunction:NetworkRequestNode.NameComparator},{id:'path',title:ls`Path`,hideable:true,hideableGroup:'path',sortingFunction:NetworkRequestNode.RequestPropertyComparator.bind(null,'path')},{id:'url',title:ls`Url`,hideable:true,hideableGroup:'path',sortingFunction:NetworkRequestNode.RequestPropertyComparator.bind(null,'url')},{id:'method',title:Common.UIString('Method'),sortingFunction:NetworkRequestNode.RequestPropertyComparator.bind(null,'requestMethod')},{id:'status',title:Common.UIString('Status'),visible:true,subtitle:Common.UIString('Text'),sortingFunction:NetworkRequestNode.RequestPropertyComparator.bind(null,'statusCode')},{id:'protocol',title:Common.UIString('Protocol'),sortingFunction:NetworkRequestNode.RequestPropertyComparator.bind(null,'protocol')},{id:'scheme',title:Common.UIString('Scheme'),sortingFunction:NetworkRequestNode.RequestPropertyComparator.bind(null,'scheme')},{id:'domain',title:Common.UIString('Domain'),sortingFunction:NetworkRequestNode.RequestPropertyComparator.bind(null,'domain')},{id:'remoteaddress',title:Common.UIString('Remote Address'),weight:10,align:DataGrid.DataGrid.Align.Right,sortingFunction:NetworkRequestNode.RemoteAddressComparator},{id:'type',title:Common.UIString('Type'),visible:true,sortingFunction:NetworkRequestNode.TypeComparator},{id:'initiator',title:Common.UIString('Initiator'),visible:true,weight:10,sortingFunction:NetworkRequestNode.InitiatorComparator},{id:'cookies',title:Common.UIString('Cookies'),align:DataGrid.DataGrid.Align.Right,sortingFunction:NetworkRequestNode.RequestCookiesCountComparator},{id:'setcookies',title:Common.UIString('Set Cookies'),align:DataGrid.DataGrid.Align.Right,sortingFunction:NetworkRequestNode.ResponseCookiesCountComparator},{id:'size',title:Common.UIString('Size'),visible:true,subtitle:Common.UIString('Content'),align:DataGrid.DataGrid.Align.Right,sortingFunction:NetworkRequestNode.SizeComparator},{id:'time',title:Common.UIString('Time'),visible:true,subtitle:Common.UIString('Latency'),align:DataGrid.DataGrid.Align.Right,sortingFunction:NetworkRequestNode.RequestPropertyComparator.bind(null,'duration')},{id:'priority',title:Common.UIString('Priority'),sortingFunction:NetworkRequestNode.PriorityComparator},{id:'connectionid',title:Common.UIString('Connection ID'),sortingFunction:NetworkRequestNode.RequestPropertyComparator.bind(null,'connectionId')},{id:'cache-control',isResponseHeader:true,title:Common.UIString('Cache-Control'),sortingFunction:NetworkRequestNode.ResponseHeaderStringComparator.bind(null,'cache-control')},{id:'connection',isResponseHeader:true,title:ls`${'Connection'}`,sortingFunction:NetworkRequestNode.ResponseHeaderStringComparator.bind(null,'connection')},{id:'content-encoding',isResponseHeader:true,title:Common.UIString('Content-Encoding'),sortingFunction:NetworkRequestNode.ResponseHeaderStringComparator.bind(null,'content-encoding')},{id:'content-length',isResponseHeader:true,title:Common.UIString('Content-Length'),align:DataGrid.DataGrid.Align.Right,sortingFunction:NetworkRequestNode.ResponseHeaderNumberComparator.bind(null,'content-length')},{id:'etag',isResponseHeader:true,title:Common.UIString('ETag'),sortingFunction:NetworkRequestNode.ResponseHeaderStringComparator.bind(null,'etag')},{id:'keep-alive',isResponseHeader:true,title:Common.UIString('Keep-Alive'),sortingFunction:NetworkRequestNode.ResponseHeaderStringComparator.bind(null,'keep-alive')},{id:'last-modified',isResponseHeader:true,title:Common.UIString('Last-Modified'),sortingFunction:NetworkRequestNode.ResponseHeaderDateComparator.bind(null,'last-modified')},{id:'server',isResponseHeader:true,title:Common.UIString('Server'),sortingFunction:NetworkRequestNode.ResponseHeaderStringComparator.bind(null,'server')},{id:'vary',isResponseHeader:true,title:Common.UIString('Vary'),sortingFunction:NetworkRequestNode.ResponseHeaderStringComparator.bind(null,'vary')},{id:'waterfall',title:ls`Waterfall`,visible:false,hideable:false,allowInSortByEvenWhenHidden:true}];export const _filmStripDividerColor='#fccc49';export const WaterfallSortIds={StartTime:'startTime',ResponseTime:'responseReceivedTime',EndTime:'endTime',Duration:'duration',Latency:'latency'};