import{ObjectWrapper,EventTarget,ParsedURL,UIString,Settings,Linkifier}from'../common/common.js';import{SDKModel,ServiceWorkerManager,RuntimeModel,ChildTargetManager,DOMModel,ResourceTreeModel,NetworkManager}from'../sdk/sdk.js';import{DeviceModeModel,EmulatedDevices,InspectedPagePlaceholder}from'../emulation/emulation.js';import{userMetrics}from'../host/host.js';import{UIUtils,Toolbar,ARIAUtils,Fragment,Tooltip,Widget,XLink,Dialog,Utils,GlassPane,Geometry,Panel,DropTarget}from'../ui/ui.js';import'../protocol_client/protocol_client.js';import{Linkifier as Linkifier$1}from'../components/components.js';import{TimelinePanel}from'../timeline/timeline.js';'use strict';const ELLIPSIS='\u2026';const NBSP='\xa0';const PASS_THRESHOLD=0.9;const SCREENSHOT_PREFIX='data:image/jpeg;base64,';const RATINGS={PASS:{label:'pass',minScore:PASS_THRESHOLD},AVERAGE:{label:'average',minScore:0.5},FAIL:{label:'fail'},ERROR:{label:'error'},};const listOfTlds=['com','co','gov','edu','ac','org','go','gob','or','net','in','ne','nic','gouv','web','spb','blog','jus','kiev','mil','wi','qc','ca','bel','on',];class Util{static get PASS_THRESHOLD(){return PASS_THRESHOLD;}
static get MS_DISPLAY_VALUE(){return`%10d${NBSP}ms`;}
static prepareReportResult(result){const clone=(JSON.parse(JSON.stringify(result)));if(!clone.configSettings.locale){clone.configSettings.locale='en';}
for(const audit of Object.values(clone.audits)){if(audit.scoreDisplayMode==='not_applicable'||audit.scoreDisplayMode==='not-applicable'){audit.scoreDisplayMode='notApplicable';}
if(audit.details){if(audit.details.type===undefined||audit.details.type==='diagnostic'){audit.details.type='debugdata';}
if(audit.details.type==='filmstrip'){for(const screenshot of audit.details.items){if(!screenshot.data.startsWith(SCREENSHOT_PREFIX)){screenshot.data=SCREENSHOT_PREFIX+screenshot.data;}}}}}
if(typeof clone.categories!=='object')throw new Error('No categories provided.');for(const category of Object.values(clone.categories)){category.auditRefs.forEach(auditRef=>{const result=clone.audits[auditRef.id];auditRef.result=result;if(clone.stackPacks){clone.stackPacks.forEach(pack=>{if(pack.descriptions[auditRef.id]){auditRef.stackPacks=auditRef.stackPacks||[];auditRef.stackPacks.push({title:pack.title,iconDataURL:pack.iconDataURL,description:pack.descriptions[auditRef.id],});}});}});}
return clone;}
static showAsPassed(audit){switch(audit.scoreDisplayMode){case'manual':case'notApplicable':return true;case'error':case'informative':return false;case'numeric':case'binary':default:return Number(audit.score)>=RATINGS.PASS.minScore;}}
static calculateRating(score,scoreDisplayMode){if(scoreDisplayMode==='manual'||scoreDisplayMode==='notApplicable'){return RATINGS.PASS.label;}else if(scoreDisplayMode==='error'){return RATINGS.ERROR.label;}else if(score===null){return RATINGS.FAIL.label;}
let rating=RATINGS.FAIL.label;if(score>=RATINGS.PASS.minScore){rating=RATINGS.PASS.label;}else if(score>=RATINGS.AVERAGE.minScore){rating=RATINGS.AVERAGE.label;}
return rating;}
static splitMarkdownCodeSpans(text){const segments=[];const parts=text.split(/`(.*?)`/g);for(let i=0;i<parts.length;i++){const text=parts[i];if(!text)continue;const isCode=i%2!==0;segments.push({isCode,text,});}
return segments;}
static splitMarkdownLink(text){const segments=[];const parts=text.split(/\[([^\]]+?)\]\((https?:\/\/.*?)\)/g);while(parts.length){const[preambleText,linkText,linkHref]=parts.splice(0,3);if(preambleText){segments.push({isLink:false,text:preambleText,});}
if(linkText&&linkHref){segments.push({isLink:true,text:linkText,linkHref,});}}
return segments;}
static getURLDisplayName(parsedUrl,options){options=options||{numPathParts:undefined,preserveQuery:undefined,preserveHost:undefined};const numPathParts=options.numPathParts!==undefined?options.numPathParts:2;const preserveQuery=options.preserveQuery!==undefined?options.preserveQuery:true;const preserveHost=options.preserveHost||false;let name;if(parsedUrl.protocol==='about:'||parsedUrl.protocol==='data:'){name=parsedUrl.href;}else{name=parsedUrl.pathname;const parts=name.split('/').filter(part=>part.length);if(numPathParts&&parts.length>numPathParts){name=ELLIPSIS+parts.slice(-1*numPathParts).join('/');}
if(preserveHost){name=`${parsedUrl.host}/${name.replace(/^\//, '')}`;}
if(preserveQuery){name=`${name}${parsedUrl.search}`;}}
const MAX_LENGTH=64;name=name.replace(/([a-f0-9]{7})[a-f0-9]{13}[a-f0-9]*/g,`$1${ELLIPSIS}`);name=name.replace(/([a-zA-Z0-9-_]{9})(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])[a-zA-Z0-9-_]{10,}/g,`$1${ELLIPSIS}`);name=name.replace(/(\d{3})\d{6,}/g,`$1${ELLIPSIS}`);name=name.replace(/\u2026+/g,ELLIPSIS);if(name.length>MAX_LENGTH&&name.includes('?')){name=name.replace(/\?([^=]*)(=)?.*/,`?$1$2${ELLIPSIS}`);if(name.length>MAX_LENGTH){name=name.replace(/\?.*/,`?${ELLIPSIS}`);}}
if(name.length>MAX_LENGTH){const dotIndex=name.lastIndexOf('.');if(dotIndex>=0){name=name.slice(0,MAX_LENGTH-1-(name.length-dotIndex))+`${ELLIPSIS}${name.slice(dotIndex)}`;}else{name=name.slice(0,MAX_LENGTH-1)+ELLIPSIS;}}
return name;}
static parseURL(url){const parsedUrl=new URL(url);return{file:Util.getURLDisplayName(parsedUrl),hostname:parsedUrl.hostname,origin:parsedUrl.origin,};}
static createOrReturnURL(value){if(value instanceof URL){return value;}
return new URL(value);}
static getTld(hostname){const tlds=hostname.split('.').slice(-2);if(!listOfTlds.includes(tlds[0])){return`.${tlds[tlds.length - 1]}`;}
return`.${tlds.join('.')}`;}
static getRootDomain(url){const hostname=Util.createOrReturnURL(url).hostname;const tld=Util.getTld(hostname);const splitTld=tld.split('.');return hostname.split('.').slice(-splitTld.length).join('.');}
static getEnvironmentDisplayValues(settings){const emulationDesc=Util.getEmulationDescriptions(settings);return[{name:Util.i18n.strings.runtimeSettingsDevice,description:emulationDesc.deviceEmulation,},{name:Util.i18n.strings.runtimeSettingsNetworkThrottling,description:emulationDesc.networkThrottling,},{name:Util.i18n.strings.runtimeSettingsCPUThrottling,description:emulationDesc.cpuThrottling,},];}
static getEmulationDescriptions(settings){let cpuThrottling;let networkThrottling;const throttling=settings.throttling;switch(settings.throttlingMethod){case'provided':cpuThrottling=Util.i18n.strings.throttlingProvided;networkThrottling=Util.i18n.strings.throttlingProvided;break;case'devtools':{const{cpuSlowdownMultiplier,requestLatencyMs}=throttling;cpuThrottling=`${Util.i18n.formatNumber(cpuSlowdownMultiplier)}x slowdown (DevTools)`;networkThrottling=`${Util.i18n.formatNumber(requestLatencyMs)}${NBSP}ms HTTP RTT, `+`${Util.i18n.formatNumber(throttling.downloadThroughputKbps)}${NBSP}Kbps down, `+`${Util.i18n.formatNumber(throttling.uploadThroughputKbps)}${NBSP}Kbps up (DevTools)`;break;}
case'simulate':{const{cpuSlowdownMultiplier,rttMs,throughputKbps}=throttling;cpuThrottling=`${Util.i18n.formatNumber(cpuSlowdownMultiplier)}x slowdown (Simulated)`;networkThrottling=`${Util.i18n.formatNumber(rttMs)}${NBSP}ms TCP RTT, `+`${Util.i18n.formatNumber(throughputKbps)}${NBSP}Kbps throughput (Simulated)`;break;}
default:cpuThrottling=Util.i18n.strings.runtimeUnknown;networkThrottling=Util.i18n.strings.runtimeUnknown;}
let deviceEmulation=Util.i18n.strings.runtimeNoEmulation;if(settings.emulatedFormFactor==='mobile'){deviceEmulation=Util.i18n.strings.runtimeMobileEmulation;}else if(settings.emulatedFormFactor==='desktop'){deviceEmulation=Util.i18n.strings.runtimeDesktopEmulation;}
return{deviceEmulation,cpuThrottling,networkThrottling,};}
static filterRelevantLines(lines,lineMessages,surroundingLineCount){if(lineMessages.length===0){return lines.slice(0,surroundingLineCount*2+1);}
const minGapSize=3;const lineNumbersToKeep=new Set();lineMessages=lineMessages.sort((a,b)=>(a.lineNumber||0)-(b.lineNumber||0));lineMessages.forEach(({lineNumber})=>{let firstSurroundingLineNumber=lineNumber-surroundingLineCount;let lastSurroundingLineNumber=lineNumber+surroundingLineCount;while(firstSurroundingLineNumber<1){firstSurroundingLineNumber++;lastSurroundingLineNumber++;}
if(lineNumbersToKeep.has(firstSurroundingLineNumber-minGapSize-1)){firstSurroundingLineNumber-=minGapSize;}
for(let i=firstSurroundingLineNumber;i<=lastSurroundingLineNumber;i++){const surroundingLineNumber=i;lineNumbersToKeep.add(surroundingLineNumber);}});return lines.filter(line=>lineNumbersToKeep.has(line.lineNumber));}
static isPluginCategory(categoryId){return categoryId.startsWith('lighthouse-plugin-');}}
Util.reportJson=null;Util.i18n=null;Util.UIStrings={varianceDisclaimer:'Values are estimated and may vary. The [performance score is calculated](https://web.dev/performance-scoring/) directly from these metrics.',calculatorLink:'See calculator.',opportunityResourceColumnLabel:'Opportunity',opportunitySavingsColumnLabel:'Estimated Savings',errorMissingAuditInfo:'Report error: no audit information',errorLabel:'Error!',warningHeader:'Warnings: ',auditGroupExpandTooltip:'Show audits',warningAuditsGroupTitle:'Passed audits but with warnings',passedAuditsGroupTitle:'Passed audits',notApplicableAuditsGroupTitle:'Not applicable',manualAuditsGroupTitle:'Additional items to manually check',toplevelWarningsMessage:'There were issues affecting this run of Lighthouse:',crcInitialNavigation:'Initial Navigation',crcLongestDurationLabel:'Maximum critical path latency:',snippetExpandButtonLabel:'Expand snippet',snippetCollapseButtonLabel:'Collapse snippet',lsPerformanceCategoryDescription:'[Lighthouse](https://developers.google.com/web/tools/lighthouse/) analysis of the current page on an emulated mobile network. Values are estimated and may vary.',labDataTitle:'Lab Data',thirdPartyResourcesLabel:'Show 3rd-party resources',dropdownPrintSummary:'Print Summary',dropdownPrintExpanded:'Print Expanded',dropdownCopyJSON:'Copy JSON',dropdownSaveHTML:'Save as HTML',dropdownSaveJSON:'Save as JSON',dropdownViewer:'Open in Viewer',dropdownSaveGist:'Save as Gist',dropdownDarkTheme:'Toggle Dark Theme',runtimeSettingsTitle:'Runtime Settings',runtimeSettingsUrl:'URL',runtimeSettingsFetchTime:'Fetch Time',runtimeSettingsDevice:'Device',runtimeSettingsNetworkThrottling:'Network throttling',runtimeSettingsCPUThrottling:'CPU throttling',runtimeSettingsChannel:'Channel',runtimeSettingsUA:'User agent (host)',runtimeSettingsUANetwork:'User agent (network)',runtimeSettingsBenchmark:'CPU/Memory Power',footerIssue:'File an issue',runtimeNoEmulation:'No emulation',runtimeMobileEmulation:'Emulated Moto G4',runtimeDesktopEmulation:'Emulated Desktop',runtimeUnknown:'Unknown',throttlingProvided:'Provided by environment',};if(typeof module!=='undefined'&&module.exports){module.exports=Util;}else{self.Util=Util;};'use strict';class DOM$1{constructor(document){this._document=document;this._lighthouseChannel='unknown';}
createElement(name,className,attrs={}){const element=this._document.createElement(name);if(className){element.className=className;}
Object.keys(attrs).forEach(key=>{const value=attrs[key];if(typeof value!=='undefined'){element.setAttribute(key,value);}});return element;}
createFragment(){return this._document.createDocumentFragment();}
createChildOf(parentElem,elementName,className,attrs){const element=this.createElement(elementName,className,attrs);parentElem.appendChild(element);return element;}
cloneTemplate(selector,context){const template=(context.querySelector(selector));if(!template){throw new Error(`Template not found: template${selector}`);}
const clone=this._document.importNode(template.content,true);if(template.hasAttribute('data-stamped')){this.findAll('style',clone).forEach(style=>style.remove());}
template.setAttribute('data-stamped','true');return clone;}
resetTemplates(){this.findAll('template[data-stamped]',this._document).forEach(t=>{t.removeAttribute('data-stamped');});}
convertMarkdownLinkSnippets(text){const element=this.createElement('span');for(const segment of Util.splitMarkdownLink(text)){if(!segment.isLink){element.appendChild(this._document.createTextNode(segment.text));continue;}
const url=new URL(segment.linkHref);const DOCS_ORIGINS=['https://developers.google.com','https://web.dev'];if(DOCS_ORIGINS.includes(url.origin)){url.searchParams.set('utm_source','lighthouse');url.searchParams.set('utm_medium',this._lighthouseChannel);}
const a=this.createElement('a');a.rel='noopener';a.target='_blank';a.textContent=segment.text;a.href=url.href;element.appendChild(a);}
return element;}
convertMarkdownCodeSnippets(markdownText){const element=this.createElement('span');for(const segment of Util.splitMarkdownCodeSpans(markdownText)){if(segment.isCode){const pre=this.createElement('code');pre.textContent=segment.text;element.appendChild(pre);}else{element.appendChild(this._document.createTextNode(segment.text));}}
return element;}
setLighthouseChannel(lighthouseChannel){this._lighthouseChannel=lighthouseChannel;}
document(){return this._document;}
isDevTools(){return!!this._document.querySelector('.lh-devtools');}
find(query,context){const result=context.querySelector(query);if(result===null){throw new Error(`query ${query} not found`);}
return result;}
findAll(query,context){return Array.from(context.querySelectorAll(query));}}
if(typeof module!=='undefined'&&module.exports){module.exports=DOM$1;}else{self.DOM=DOM$1;};(function(){"use strict";var element=document.createElement("details");var elementIsNative=typeof HTMLDetailsElement!="undefined"&&element instanceof HTMLDetailsElement;var support={open:"open"in element||elementIsNative,toggle:"ontoggle"in element};var styles='\ndetails, summary {\n  display: block;\n}\ndetails:not([open]) > *:not(summary) {\n  display: none;\n}\nsummary::before {\n  content: "►";\n  padding-right: 0.3rem;\n  font-size: 0.6rem;\n  cursor: default;\n}\n[open] > summary::before {\n  content: "▼";\n}\n';var _ref=[],forEach=_ref.forEach,slice=_ref.slice;if(!support.open){polyfillStyles();polyfillProperties();polyfillToggle();polyfillAccessibility();}
if(support.open&&!support.toggle){polyfillToggleEvent();}
function polyfillStyles(){document.head.insertAdjacentHTML("afterbegin","<style>"+styles+"</style>");}
function polyfillProperties(){var prototype=document.createElement("details").constructor.prototype;var setAttribute=prototype.setAttribute,removeAttribute=prototype.removeAttribute;var open=Object.getOwnPropertyDescriptor(prototype,"open");Object.defineProperties(prototype,{open:{get:function get(){if(this.tagName=="DETAILS"){return this.hasAttribute("open");}else{if(open&&open.get){return open.get.call(this);}}},set:function set(value){if(this.tagName=="DETAILS"){return value?this.setAttribute("open",""):this.removeAttribute("open");}else{if(open&&open.set){return open.set.call(this,value);}}}},setAttribute:{value:function value(name,_value){var _this=this;var call=function call(){return setAttribute.call(_this,name,_value);};if(name=="open"&&this.tagName=="DETAILS"){var wasOpen=this.hasAttribute("open");var result=call();if(!wasOpen){var summary=this.querySelector("summary");if(summary)summary.setAttribute("aria-expanded",true);triggerToggle(this);}
return result;}
return call();}},removeAttribute:{value:function value(name){var _this2=this;var call=function call(){return removeAttribute.call(_this2,name);};if(name=="open"&&this.tagName=="DETAILS"){var wasOpen=this.hasAttribute("open");var result=call();if(wasOpen){var summary=this.querySelector("summary");if(summary)summary.setAttribute("aria-expanded",false);triggerToggle(this);}
return result;}
return call();}}});}
function polyfillToggle(){onTogglingTrigger(function(element){element.hasAttribute("open")?element.removeAttribute("open"):element.setAttribute("open","");});}
function polyfillToggleEvent(){if(window.MutationObserver){new MutationObserver(function(mutations){forEach.call(mutations,function(mutation){var target=mutation.target,attributeName=mutation.attributeName;if(target.tagName=="DETAILS"&&attributeName=="open"){triggerToggle(target);}});}).observe(document.documentElement,{attributes:true,subtree:true});}else{onTogglingTrigger(function(element){var wasOpen=element.getAttribute("open");setTimeout(function(){var isOpen=element.getAttribute("open");if(wasOpen!=isOpen){triggerToggle(element);}},1);});}}
function polyfillAccessibility(){setAccessibilityAttributes(document);if(window.MutationObserver){new MutationObserver(function(mutations){forEach.call(mutations,function(mutation){forEach.call(mutation.addedNodes,setAccessibilityAttributes);});}).observe(document.documentElement,{subtree:true,childList:true});}else{document.addEventListener("DOMNodeInserted",function(event){setAccessibilityAttributes(event.target);});}}
function setAccessibilityAttributes(root){findElementsWithTagName(root,"SUMMARY").forEach(function(summary){var details=findClosestElementWithTagName(summary,"DETAILS");summary.setAttribute("aria-expanded",details.hasAttribute("open"));if(!summary.hasAttribute("tabindex"))summary.setAttribute("tabindex","0");if(!summary.hasAttribute("role"))summary.setAttribute("role","button");});}
function eventIsSignificant(event){return!(event.defaultPrevented||event.ctrlKey||event.metaKey||event.shiftKey||event.target.isContentEditable);}
function onTogglingTrigger(callback){addEventListener("click",function(event){if(eventIsSignificant(event)){if(event.which<=1){var element=findClosestElementWithTagName(event.target,"SUMMARY");if(element&&element.parentNode&&element.parentNode.tagName=="DETAILS"){callback(element.parentNode);}}}},false);addEventListener("keydown",function(event){if(eventIsSignificant(event)){if(event.keyCode==13||event.keyCode==32){var element=findClosestElementWithTagName(event.target,"SUMMARY");if(element&&element.parentNode&&element.parentNode.tagName=="DETAILS"){callback(element.parentNode);event.preventDefault();}}}},false);}
function triggerToggle(element){var event=document.createEvent("Event");event.initEvent("toggle",false,false);element.dispatchEvent(event);}
function findElementsWithTagName(root,tagName){return(root.tagName==tagName?[root]:[]).concat(typeof root.getElementsByTagName=="function"?slice.call(root.getElementsByTagName(tagName)):[]);}
function findClosestElementWithTagName(element,tagName){if(typeof element.closest=="function"){return element.closest(tagName);}else{while(element){if(element.tagName==tagName){return element;}else{element=element.parentNode;}}}}})();;'use strict';const URL_PREFIXES=['http://','https://','data:'];class DetailsRenderer{constructor(dom){this._dom=dom;this._templateContext;}
setTemplateContext(context){this._templateContext=context;}
render(details){switch(details.type){case'filmstrip':return this._renderFilmstrip(details);case'list':return this._renderList(details);case'table':return this._renderTable(details);case'criticalrequestchain':return CriticalRequestChainRenderer.render(this._dom,this._templateContext,details,this);case'opportunity':return this._renderTable(details);case'screenshot':case'debugdata':return null;default:{return this._renderUnknown(details.type,details);}}}
_renderBytes(details){const value=Util.i18n.formatBytesToKB(details.value,details.granularity);return this._renderText(value);}
_renderMilliseconds(details){let value=Util.i18n.formatMilliseconds(details.value,details.granularity);if(details.displayUnit==='duration'){value=Util.i18n.formatDuration(details.value);}
return this._renderText(value);}
renderTextURL(text){const url=text;let displayedPath;let displayedHost;let title;try{const parsed=Util.parseURL(url);displayedPath=parsed.file==='/'?parsed.origin:parsed.file;displayedHost=parsed.file==='/'?'':`(${parsed.hostname})`;title=url;}catch(e){displayedPath=url;}
const element=this._dom.createElement('div','lh-text__url');element.appendChild(this._renderLink({text:displayedPath,url}));if(displayedHost){const hostElem=this._renderText(displayedHost);hostElem.classList.add('lh-text__url-host');element.appendChild(hostElem);}
if(title){element.title=url;element.dataset.url=url;}
return element;}
_renderLink(details){const allowedProtocols=['https:','http:'];let url;try{url=new URL(details.url);}catch(_){}
if(!url||!allowedProtocols.includes(url.protocol)){return this._renderText(details.text);}
const a=this._dom.createElement('a');a.rel='noopener';a.target='_blank';a.textContent=details.text;a.href=url.href;return a;}
_renderText(text){const element=this._dom.createElement('div','lh-text');element.textContent=text;return element;}
_renderNumeric(text){const element=this._dom.createElement('div','lh-numeric');element.textContent=text;return element;}
_renderThumbnail(details){const element=this._dom.createElement('img','lh-thumbnail');const strValue=details;element.src=strValue;element.title=strValue;element.alt='';return element;}
_renderUnknown(type,value){console.error(`Unknown details type: ${type}`,value);const element=this._dom.createElement('details','lh-unknown');this._dom.createChildOf(element,'summary').textContent=`We don't know how to render audit details of type \`${type}\`. `+'The Lighthouse version that collected this data is likely newer than the Lighthouse '+'version of the report renderer. Expand for the raw JSON.';this._dom.createChildOf(element,'pre').textContent=JSON.stringify(value,null,2);return element;}
_renderTableValue(value,heading){if(typeof value==='undefined'||value===null){return null;}
if(typeof value==='object'){switch(value.type){case'code':{return this._renderCode(value.value);}
case'link':{return this._renderLink(value);}
case'node':{return this.renderNode(value);}
case'source-location':{return this.renderSourceLocation(value);}
case'url':{return this.renderTextURL(value.value);}
default:{return this._renderUnknown(value.type,value);}}}
switch(heading.valueType){case'bytes':{const numValue=Number(value);return this._renderBytes({value:numValue,granularity:heading.granularity});}
case'code':{const strValue=String(value);return this._renderCode(strValue);}
case'ms':{const msValue={value:Number(value),granularity:heading.granularity,displayUnit:heading.displayUnit,};return this._renderMilliseconds(msValue);}
case'numeric':{const strValue=String(value);return this._renderNumeric(strValue);}
case'text':{const strValue=String(value);return this._renderText(strValue);}
case'thumbnail':{const strValue=String(value);return this._renderThumbnail(strValue);}
case'timespanMs':{const numValue=Number(value);return this._renderMilliseconds({value:numValue});}
case'url':{const strValue=String(value);if(URL_PREFIXES.some(prefix=>strValue.startsWith(prefix))){return this.renderTextURL(strValue);}else{return this._renderCode(strValue);}}
default:{return this._renderUnknown(heading.valueType,value);}}}
_getCanonicalizedHeadingsFromTable(tableLike){if(tableLike.type==='opportunity'){return tableLike.headings;}
return tableLike.headings.map(heading=>this._getCanonicalizedHeading(heading));}
_getCanonicalizedHeading(heading){let subRows;if(heading.subRows){subRows=this._getCanonicalizedHeading(heading.subRows);if(!subRows.key){console.warn('key should not be null');}
subRows={...subRows,key:subRows.key||''};}
return{key:heading.key,valueType:heading.itemType,subRows,label:heading.text,displayUnit:heading.displayUnit,granularity:heading.granularity,};}
_renderSubRows(values,heading){const subRowsElement=this._dom.createElement('div','lh-sub-rows');for(const childValue of values){const subRowElement=this._renderTableValue(childValue,heading);if(!subRowElement)continue;subRowElement.classList.add('lh-sub-row');subRowsElement.appendChild(subRowElement);}
return subRowsElement;}
_renderTable(details){if(!details.items.length)return this._dom.createElement('span');const tableElem=this._dom.createElement('table','lh-table');const theadElem=this._dom.createChildOf(tableElem,'thead');const theadTrElem=this._dom.createChildOf(theadElem,'tr');const headings=this._getCanonicalizedHeadingsFromTable(details);for(const heading of headings){const valueType=heading.valueType||'text';const classes=`lh-table-column--${valueType}`;const labelEl=this._dom.createElement('div','lh-text');labelEl.textContent=heading.label;this._dom.createChildOf(theadTrElem,'th',classes).appendChild(labelEl);}
const tbodyElem=this._dom.createChildOf(tableElem,'tbody');for(const row of details.items){const rowElem=this._dom.createChildOf(tbodyElem,'tr');for(const heading of headings){const valueFragment=this._dom.createFragment();if(heading.key===null&&!heading.subRows){console.warn('A header with a null `key` should define `subRows`.');}
if(heading.key===null){const emptyElement=this._dom.createElement('div');emptyElement.innerHTML='&nbsp;';valueFragment.appendChild(emptyElement);}else{const value=row[heading.key];const valueElement=value!==undefined&&!Array.isArray(value)&&this._renderTableValue(value,heading);if(valueElement)valueFragment.appendChild(valueElement);}
if(heading.subRows){const subRowsHeading={key:heading.subRows.key,valueType:heading.subRows.valueType||heading.valueType,granularity:heading.subRows.granularity||heading.granularity,displayUnit:heading.subRows.displayUnit||heading.displayUnit,label:'',};const values=row[subRowsHeading.key];if(Array.isArray(values)){const subRowsElement=this._renderSubRows(values,subRowsHeading);valueFragment.appendChild(subRowsElement);}}
if(valueFragment.childElementCount){const classes=`lh-table-column--${heading.valueType}`;this._dom.createChildOf(rowElem,'td',classes).appendChild(valueFragment);}else{this._dom.createChildOf(rowElem,'td','lh-table-column--empty');}}}
return tableElem;}
_renderList(details){const listContainer=this._dom.createElement('div','lh-list');details.items.forEach(item=>{const snippetEl=SnippetRenderer.render(this._dom,this._templateContext,item,this);listContainer.appendChild(snippetEl);});return listContainer;}
renderNode(item){const element=this._dom.createElement('span','lh-node');if(item.nodeLabel){const nodeLabelEl=this._dom.createElement('div');nodeLabelEl.textContent=item.nodeLabel;element.appendChild(nodeLabelEl);}
if(item.snippet){const snippetEl=this._dom.createElement('div');snippetEl.classList.add('lh-node__snippet');snippetEl.textContent=item.snippet;element.appendChild(snippetEl);}
if(item.selector){element.title=item.selector;}
if(item.path)element.setAttribute('data-path',item.path);if(item.selector)element.setAttribute('data-selector',item.selector);if(item.snippet)element.setAttribute('data-snippet',item.snippet);return element;}
renderSourceLocation(item){if(!item.url){return null;}
const line=item.line+1;const column=item.column;let element;if(item.urlProvider==='network'){element=this.renderTextURL(item.url);this._dom.find('a',element).textContent+=`:${line}:${column}`;}else{element=this._renderText(`${item.url}:${line}:${column} (from sourceURL)`);}
element.classList.add('lh-source-location');element.setAttribute('data-source-url',item.url);element.setAttribute('data-source-line',String(item.line));element.setAttribute('data-source-column',String(item.column));return element;}
_renderFilmstrip(details){const filmstripEl=this._dom.createElement('div','lh-filmstrip');for(const thumbnail of details.items){const frameEl=this._dom.createChildOf(filmstripEl,'div','lh-filmstrip__frame');this._dom.createChildOf(frameEl,'img','lh-filmstrip__thumbnail',{src:thumbnail.data,alt:`Screenshot`,});}
return filmstripEl;}
_renderCode(text){const pre=this._dom.createElement('pre','lh-code');pre.textContent=text;return pre;}}
if(typeof module!=='undefined'&&module.exports){module.exports=DetailsRenderer;}else{self.DetailsRenderer=DetailsRenderer;};'use strict';class CriticalRequestChainRenderer{static initTree(tree){let startTime=0;const rootNodes=Object.keys(tree);if(rootNodes.length>0){const node=tree[rootNodes[0]];startTime=node.request.startTime;}
return{tree,startTime,transferSize:0};}
static createSegment(parent,id,startTime,transferSize,treeMarkers,parentIsLastChild){const node=parent[id];const siblings=Object.keys(parent);const isLastChild=siblings.indexOf(id)===(siblings.length-1);const hasChildren=!!node.children&&Object.keys(node.children).length>0;const newTreeMarkers=Array.isArray(treeMarkers)?treeMarkers.slice(0):[];if(typeof parentIsLastChild!=='undefined'){newTreeMarkers.push(!parentIsLastChild);}
return{node,isLastChild,hasChildren,startTime,transferSize:transferSize+node.request.transferSize,treeMarkers:newTreeMarkers,};}
static createChainNode(dom,tmpl,segment,detailsRenderer){const chainsEl=dom.cloneTemplate('#tmpl-lh-crc__chains',tmpl);dom.find('.crc-node',chainsEl).setAttribute('title',segment.node.request.url);const treeMarkeEl=dom.find('.crc-node__tree-marker',chainsEl);segment.treeMarkers.forEach(separator=>{if(separator){treeMarkeEl.appendChild(dom.createElement('span','tree-marker vert'));treeMarkeEl.appendChild(dom.createElement('span','tree-marker'));}else{treeMarkeEl.appendChild(dom.createElement('span','tree-marker'));treeMarkeEl.appendChild(dom.createElement('span','tree-marker'));}});if(segment.isLastChild){treeMarkeEl.appendChild(dom.createElement('span','tree-marker up-right'));treeMarkeEl.appendChild(dom.createElement('span','tree-marker right'));}else{treeMarkeEl.appendChild(dom.createElement('span','tree-marker vert-right'));treeMarkeEl.appendChild(dom.createElement('span','tree-marker right'));}
if(segment.hasChildren){treeMarkeEl.appendChild(dom.createElement('span','tree-marker horiz-down'));}else{treeMarkeEl.appendChild(dom.createElement('span','tree-marker right'));}
const url=segment.node.request.url;const linkEl=detailsRenderer.renderTextURL(url);const treevalEl=dom.find('.crc-node__tree-value',chainsEl);treevalEl.appendChild(linkEl);if(!segment.hasChildren){const{startTime,endTime,transferSize}=segment.node.request;const span=dom.createElement('span','crc-node__chain-duration');span.textContent=' - '+Util.i18n.formatMilliseconds((endTime-startTime)*1000)+', ';const span2=dom.createElement('span','crc-node__chain-duration');span2.textContent=Util.i18n.formatBytesToKB(transferSize,0.01);treevalEl.appendChild(span);treevalEl.appendChild(span2);}
return chainsEl;}
static buildTree(dom,tmpl,segment,elem,details,detailsRenderer){elem.appendChild(CRCRenderer.createChainNode(dom,tmpl,segment,detailsRenderer));if(segment.node.children){for(const key of Object.keys(segment.node.children)){const childSegment=CRCRenderer.createSegment(segment.node.children,key,segment.startTime,segment.transferSize,segment.treeMarkers,segment.isLastChild);CRCRenderer.buildTree(dom,tmpl,childSegment,elem,details,detailsRenderer);}}}
static render(dom,templateContext,details,detailsRenderer){const tmpl=dom.cloneTemplate('#tmpl-lh-crc',templateContext);const containerEl=dom.find('.lh-crc',tmpl);dom.find('.crc-initial-nav',tmpl).textContent=Util.i18n.strings.crcInitialNavigation;dom.find('.lh-crc__longest_duration_label',tmpl).textContent=Util.i18n.strings.crcLongestDurationLabel;dom.find('.lh-crc__longest_duration',tmpl).textContent=Util.i18n.formatMilliseconds(details.longestChain.duration);const root=CRCRenderer.initTree(details.chains);for(const key of Object.keys(root.tree)){const segment=CRCRenderer.createSegment(root.tree,key,root.startTime,root.transferSize);CRCRenderer.buildTree(dom,tmpl,segment,containerEl,details,detailsRenderer);}
return dom.find('.lh-crc-container',tmpl);}}
const CRCRenderer=CriticalRequestChainRenderer;if(typeof module!=='undefined'&&module.exports){module.exports=CriticalRequestChainRenderer;}else{self.CriticalRequestChainRenderer=CriticalRequestChainRenderer;};'use strict';const LineVisibility={ALWAYS:0,WHEN_COLLAPSED:1,WHEN_EXPANDED:2,};const LineContentType={CONTENT_NORMAL:0,CONTENT_HIGHLIGHTED:1,PLACEHOLDER:2,MESSAGE:3,};const classNamesByContentType={[LineContentType.CONTENT_NORMAL]:['lh-snippet__line--content'],[LineContentType.CONTENT_HIGHLIGHTED]:['lh-snippet__line--content','lh-snippet__line--content-highlighted',],[LineContentType.PLACEHOLDER]:['lh-snippet__line--placeholder'],[LineContentType.MESSAGE]:['lh-snippet__line--message'],};function getLineAndPreviousLine(lines,lineNumber){return{line:lines.find(l=>l.lineNumber===lineNumber),previousLine:lines.find(l=>l.lineNumber===lineNumber-1),};}
function getMessagesForLineNumber(messages,lineNumber){return messages.filter(h=>h.lineNumber===lineNumber);}
function getLinesWhenCollapsed(details){const SURROUNDING_LINES_TO_SHOW_WHEN_COLLAPSED=2;return Util.filterRelevantLines(details.lines,details.lineMessages,SURROUNDING_LINES_TO_SHOW_WHEN_COLLAPSED);}
class SnippetRenderer{static renderHeader(dom,tmpl,details,detailsRenderer,toggleExpandedFn){const linesWhenCollapsed=getLinesWhenCollapsed(details);const canExpand=linesWhenCollapsed.length<details.lines.length;const header=dom.cloneTemplate('#tmpl-lh-snippet__header',tmpl);dom.find('.lh-snippet__title',header).textContent=details.title;const{snippetCollapseButtonLabel,snippetExpandButtonLabel,}=Util.i18n.strings;dom.find('.lh-snippet__btn-label-collapse',header).textContent=snippetCollapseButtonLabel;dom.find('.lh-snippet__btn-label-expand',header).textContent=snippetExpandButtonLabel;const toggleExpandButton=dom.find('.lh-snippet__toggle-expand',header);if(!canExpand){toggleExpandButton.remove();}else{toggleExpandButton.addEventListener('click',()=>toggleExpandedFn());}
if(details.node&&dom.isDevTools()){const nodeContainer=dom.find('.lh-snippet__node',header);nodeContainer.appendChild(detailsRenderer.renderNode(details.node));}
return header;}
static renderSnippetLine(dom,tmpl,{content,lineNumber,truncated,contentType,visibility}){const clonedTemplate=dom.cloneTemplate('#tmpl-lh-snippet__line',tmpl);const contentLine=dom.find('.lh-snippet__line',clonedTemplate);const{classList}=contentLine;classNamesByContentType[contentType].forEach(typeClass=>classList.add(typeClass));if(visibility===LineVisibility.WHEN_COLLAPSED){classList.add('lh-snippet__show-if-collapsed');}else if(visibility===LineVisibility.WHEN_EXPANDED){classList.add('lh-snippet__show-if-expanded');}
const lineContent=content+(truncated?'…':'');const lineContentEl=dom.find('.lh-snippet__line code',contentLine);if(contentType===LineContentType.MESSAGE){lineContentEl.appendChild(dom.convertMarkdownLinkSnippets(lineContent));}else{lineContentEl.textContent=lineContent;}
dom.find('.lh-snippet__line-number',contentLine).textContent=lineNumber.toString();return contentLine;}
static renderMessage(dom,tmpl,message){return SnippetRenderer.renderSnippetLine(dom,tmpl,{lineNumber:' ',content:message.message,contentType:LineContentType.MESSAGE,});}
static renderOmittedLinesPlaceholder(dom,tmpl,visibility){return SnippetRenderer.renderSnippetLine(dom,tmpl,{lineNumber:'…',content:'',visibility,contentType:LineContentType.PLACEHOLDER,});}
static renderSnippetContent(dom,tmpl,details){const template=dom.cloneTemplate('#tmpl-lh-snippet__content',tmpl);const snippetEl=dom.find('.lh-snippet__snippet-inner',template);details.generalMessages.forEach(m=>snippetEl.append(SnippetRenderer.renderMessage(dom,tmpl,m)));snippetEl.append(SnippetRenderer.renderSnippetLines(dom,tmpl,details));return template;}
static renderSnippetLines(dom,tmpl,details){const{lineMessages,generalMessages,lineCount,lines}=details;const linesWhenCollapsed=getLinesWhenCollapsed(details);const hasOnlyGeneralMessages=generalMessages.length>0&&lineMessages.length===0;const lineContainer=dom.createFragment();let hasPendingOmittedLinesPlaceholderForCollapsedState=false;for(let lineNumber=1;lineNumber<=lineCount;lineNumber++){const{line,previousLine}=getLineAndPreviousLine(lines,lineNumber);const{line:lineWhenCollapsed,previousLine:previousLineWhenCollapsed,}=getLineAndPreviousLine(linesWhenCollapsed,lineNumber);const showLineWhenCollapsed=!!lineWhenCollapsed;const showPreviousLineWhenCollapsed=!!previousLineWhenCollapsed;if(showPreviousLineWhenCollapsed&&!showLineWhenCollapsed){hasPendingOmittedLinesPlaceholderForCollapsedState=true;}
if(showLineWhenCollapsed&&hasPendingOmittedLinesPlaceholderForCollapsedState){lineContainer.append(SnippetRenderer.renderOmittedLinesPlaceholder(dom,tmpl,LineVisibility.WHEN_COLLAPSED));hasPendingOmittedLinesPlaceholderForCollapsedState=false;}
const isFirstOmittedLineWhenExpanded=!line&&!!previousLine;const isFirstLineOverallAndIsOmittedWhenExpanded=!line&&lineNumber===1;if(isFirstOmittedLineWhenExpanded||isFirstLineOverallAndIsOmittedWhenExpanded){const hasRenderedAllLinesVisibleWhenCollapsed=!linesWhenCollapsed.some(l=>l.lineNumber>lineNumber);const onlyShowWhenExpanded=hasRenderedAllLinesVisibleWhenCollapsed||lineNumber===1;lineContainer.append(SnippetRenderer.renderOmittedLinesPlaceholder(dom,tmpl,onlyShowWhenExpanded?LineVisibility.WHEN_EXPANDED:LineVisibility.ALWAYS));hasPendingOmittedLinesPlaceholderForCollapsedState=false;}
if(!line){continue;}
const messages=getMessagesForLineNumber(lineMessages,lineNumber);const highlightLine=messages.length>0||hasOnlyGeneralMessages;const contentLineDetails=Object.assign({},line,{contentType:highlightLine?LineContentType.CONTENT_HIGHLIGHTED:LineContentType.CONTENT_NORMAL,visibility:lineWhenCollapsed?LineVisibility.ALWAYS:LineVisibility.WHEN_EXPANDED,});lineContainer.append(SnippetRenderer.renderSnippetLine(dom,tmpl,contentLineDetails));messages.forEach(message=>{lineContainer.append(SnippetRenderer.renderMessage(dom,tmpl,message));});}
return lineContainer;}
static render(dom,templateContext,details,detailsRenderer){const tmpl=dom.cloneTemplate('#tmpl-lh-snippet',templateContext);const snippetEl=dom.find('.lh-snippet',tmpl);const header=SnippetRenderer.renderHeader(dom,tmpl,details,detailsRenderer,()=>snippetEl.classList.toggle('lh-snippet--expanded'));const content=SnippetRenderer.renderSnippetContent(dom,tmpl,details);snippetEl.append(header,content);return snippetEl;}}
if(typeof module!=='undefined'&&module.exports){module.exports=SnippetRenderer;}else{self.SnippetRenderer=SnippetRenderer;};'use strict';function getFilenamePrefix(lhr){const hostname=new URL(lhr.finalUrl).hostname;const date=(lhr.fetchTime&&new Date(lhr.fetchTime))||new Date();const timeStr=date.toLocaleTimeString('en-US',{hour12:false});const dateParts=date.toLocaleDateString('en-US',{year:'numeric',month:'2-digit',day:'2-digit',}).split('/');dateParts.unshift(dateParts.pop());const dateStr=dateParts.join('-');const filenamePrefix=`${hostname}_${dateStr}_${timeStr}`;return filenamePrefix.replace(/[/?<>\\:*|"]/g,'-');}
if(typeof module!=='undefined'&&module.exports){module.exports={getFilenamePrefix};};'use strict';class Logger{constructor(element){this.el=element;this._id=undefined;}
log(msg,autoHide=true){this._id&&clearTimeout(this._id);this.el.textContent=msg;this.el.classList.add('show');if(autoHide){this._id=setTimeout(_=>{this.el.classList.remove('show');},7000);}}
warn(msg){this.log('Warning: '+msg);}
error(msg){this.log(msg);setTimeout(_=>{throw new Error(msg);},0);}
hide(){this._id&&clearTimeout(this._id);this.el.classList.remove('show');}}
if(typeof module!=='undefined'&&module.exports){module.exports=Logger;};'use strict';function getTableRows(tableEl){return Array.from(tableEl.tBodies[0].rows);}
class ReportUIFeatures$1{constructor(dom){this.json;this._dom=dom;this._document=this._dom.document();this._templateContext=this._dom.document();this._dropDown=new DropDown(this._dom);this._copyAttempt=false;this.topbarEl;this.scoreScaleEl;this.stickyHeaderEl;this.highlightEl;this.onMediaQueryChange=this.onMediaQueryChange.bind(this);this.onCopy=this.onCopy.bind(this);this.onDropDownMenuClick=this.onDropDownMenuClick.bind(this);this.onKeyUp=this.onKeyUp.bind(this);this.collapseAllDetails=this.collapseAllDetails.bind(this);this.expandAllDetails=this.expandAllDetails.bind(this);this._toggleDarkTheme=this._toggleDarkTheme.bind(this);this._updateStickyHeaderOnScroll=this._updateStickyHeaderOnScroll.bind(this);}
initFeatures(report){this.json=report;this._setupMediaQueryListeners();this._dropDown.setup(this.onDropDownMenuClick);this._setupThirdPartyFilter();this._setUpCollapseDetailsAfterPrinting();this._resetUIState();this._document.addEventListener('keyup',this.onKeyUp);this._document.addEventListener('copy',this.onCopy);const topbarLogo=this._dom.find('.lh-topbar__logo',this._document);topbarLogo.addEventListener('click',()=>this._toggleDarkTheme());let turnOffTheLights=false;if(!this._dom.isDevTools()&&window.matchMedia('(prefers-color-scheme: dark)').matches){turnOffTheLights=true;}
const scoresAll100=Object.values(report.categories).every(cat=>cat.score===1);const hasAllCoreCategories=Object.keys(report.categories).filter(id=>!Util.isPluginCategory(id)).length>=5;if(scoresAll100&&hasAllCoreCategories){turnOffTheLights=true;this._enableFireworks();}
if(turnOffTheLights){this._toggleDarkTheme(true);}
if(Object.keys(this.json.categories).length>=2){this._setupStickyHeaderElements();const containerEl=this._dom.find('.lh-container',this._document);const elToAddScrollListener=this._getScrollParent(containerEl);elToAddScrollListener.addEventListener('scroll',this._updateStickyHeaderOnScroll);if(this._dom.isDevTools()){const resizeObserver=new window.ResizeObserver(this._updateStickyHeaderOnScroll);resizeObserver.observe(containerEl);}else{window.addEventListener('resize',this._updateStickyHeaderOnScroll);}}
const hasMetricError=report.categories.performance&&report.categories.performance.auditRefs.some(audit=>Boolean(audit.group==='metrics'&&report.audits[audit.id].errorMessage));if(hasMetricError){const toggleInputEl=(this._dom.find('.lh-metrics-toggle__input',this._document));toggleInputEl.checked=true;}
for(const node of this._dom.findAll('[data-i18n]',this._dom.document())){const i18nAttr=(node.getAttribute('data-i18n'));node.textContent=Util.i18n.strings[i18nAttr];}}
setTemplateContext(context){this._templateContext=context;}
_getScrollParent(element){const{overflowY}=window.getComputedStyle(element);const isScrollable=overflowY!=='visible'&&overflowY!=='hidden';if(isScrollable){return element;}
if(element.parentElement){return this._getScrollParent(element.parentElement);}
return document;}
_enableFireworks(){const scoresContainer=this._dom.find('.lh-scores-container',this._document);scoresContainer.classList.add('score100');scoresContainer.addEventListener('click',_=>{scoresContainer.classList.toggle('fireworks-paused');});}
_fireEventOn(name,target=this._document,detail){const event=new CustomEvent(name,detail?{detail}:undefined);target.dispatchEvent(event);}
_setupMediaQueryListeners(){const mediaQuery=self.matchMedia('(max-width: 500px)');mediaQuery.addListener(this.onMediaQueryChange);this.onMediaQueryChange(mediaQuery);}
onMediaQueryChange(mql){const root=this._dom.find('.lh-root',this._document);root.classList.toggle('lh-narrow',mql.matches);}
_setupThirdPartyFilter(){const thirdPartyFilterAuditExclusions=['uses-rel-preconnect',];const thirdPartyFilterAuditHideByDefault=['legacy-javascript',];const tables=Array.from(this._document.querySelectorAll('.lh-table'));const tablesWithUrls=tables.filter(el=>el.querySelector('td.lh-table-column--url, td.lh-table-column--source-location')).filter(el=>{const containingAudit=el.closest('.lh-audit');if(!containingAudit)throw new Error('.lh-table not within audit');return!thirdPartyFilterAuditExclusions.includes(containingAudit.id);});tablesWithUrls.forEach((tableEl,index)=>{const rowEls=getTableRows(tableEl);const thirdPartyRows=this._getThirdPartyRows(rowEls,this.json.finalUrl);const filterTemplate=this._dom.cloneTemplate('#tmpl-lh-3p-filter',this._templateContext);const filterInput=(this._dom.find('input',filterTemplate));const id=`lh-3p-filter-label--${index}`;filterInput.id=id;filterInput.addEventListener('change',e=>{if(e.target instanceof HTMLInputElement&&!e.target.checked){for(const row of thirdPartyRows.values()){row.remove();}}else{for(const[position,row]of thirdPartyRows.entries()){const childrenArr=getTableRows(tableEl);tableEl.tBodies[0].insertBefore(row,childrenArr[position]);}}});this._dom.find('label',filterTemplate).setAttribute('for',id);this._dom.find('.lh-3p-filter-count',filterTemplate).textContent=`${thirdPartyRows.size}`;this._dom.find('.lh-3p-ui-string',filterTemplate).textContent=Util.i18n.strings.thirdPartyResourcesLabel;const allThirdParty=thirdPartyRows.size===rowEls.length;const allFirstParty=!thirdPartyRows.size;if(allThirdParty||allFirstParty){filterInput.disabled=true;filterInput.checked=allThirdParty;}
if(!tableEl.parentNode)return;tableEl.parentNode.insertBefore(filterTemplate,tableEl);const containingAudit=tableEl.closest('.lh-audit');if(!containingAudit)throw new Error('.lh-table not within audit');if(thirdPartyFilterAuditHideByDefault.includes(containingAudit.id)&&!allThirdParty){filterInput.click();}});}
_getThirdPartyRows(rowEls,finalUrl){const thirdPartyRows=new Map();const finalUrlRootDomain=Util.getRootDomain(finalUrl);rowEls.forEach((rowEl,rowPosition)=>{const urlItem=rowEl.querySelector('.lh-text__url');if(!urlItem)return;const datasetUrl=urlItem.dataset.url;if(!datasetUrl)return;const isThirdParty=Util.getRootDomain(datasetUrl)!==finalUrlRootDomain;if(!isThirdParty)return;thirdPartyRows.set(Number(rowPosition),rowEl);});return thirdPartyRows;}
_getUrlItems(tableEl){return this._dom.findAll('.lh-text__url',tableEl);}
_setupStickyHeaderElements(){this.topbarEl=this._dom.find('.lh-topbar',this._document);this.scoreScaleEl=this._dom.find('.lh-scorescale',this._document);this.stickyHeaderEl=this._dom.find('.lh-sticky-header',this._document);this.highlightEl=this._dom.createChildOf(this.stickyHeaderEl,'div','lh-highlighter');}
onCopy(e){if(this._copyAttempt&&e.clipboardData){e.preventDefault();e.clipboardData.setData('text/plain',JSON.stringify(this.json,null,2));this._fireEventOn('lh-log',this._document,{cmd:'log',msg:'Report JSON copied to clipboard',});}
this._copyAttempt=false;}
onCopyButtonClick(){this._fireEventOn('lh-analytics',this._document,{cmd:'send',fields:{hitType:'event',eventCategory:'report',eventAction:'copy'},});try{if(this._document.queryCommandSupported('copy')){this._copyAttempt=true;if(!this._document.execCommand('copy')){this._copyAttempt=false;this._fireEventOn('lh-log',this._document,{cmd:'warn',msg:'Your browser does not support copy to clipboard.',});}}}catch(e){this._copyAttempt=false;this._fireEventOn('lh-log',this._document,{cmd:'log',msg:e.message});}}
_resetUIState(){this._dropDown.close();this._dom.resetTemplates();}
onDropDownMenuClick(e){e.preventDefault();const el=(e.target);if(!el||!el.hasAttribute('data-action')){return;}
switch(el.getAttribute('data-action')){case'copy':this.onCopyButtonClick();break;case'print-summary':this.collapseAllDetails();this._print();break;case'print-expanded':this.expandAllDetails();this._print();break;case'save-json':{const jsonStr=JSON.stringify(this.json,null,2);this._saveFile(new Blob([jsonStr],{type:'application/json'}));break;}
case'save-html':{const htmlStr=this.getReportHtml();try{this._saveFile(new Blob([htmlStr],{type:'text/html'}));}catch(e){this._fireEventOn('lh-log',this._document,{cmd:'error',msg:'Could not export as HTML. '+e.message,});}
break;}
case'open-viewer':{const viewerPath='/lighthouse/viewer/';ReportUIFeatures$1.openTabAndSendJsonReport(this.json,viewerPath);break;}
case'save-gist':{this.saveAsGist();break;}
case'toggle-dark':{this._toggleDarkTheme();break;}}
this._dropDown.close();}
_print(){self.print();}
onKeyUp(e){if((e.ctrlKey||e.metaKey)&&e.keyCode===80){this._dropDown.close();}}
static openTabAndSendJsonReport(reportJson,viewerPath){const VIEWER_ORIGIN='https://googlechrome.github.io';const json=reportJson;window.addEventListener('message',function msgHandler(messageEvent){if(messageEvent.origin!==VIEWER_ORIGIN){return;}
if(popup&&messageEvent.data.opened){popup.postMessage({lhresults:json},VIEWER_ORIGIN);window.removeEventListener('message',msgHandler);}});const fallbackFetchTime=(json.generatedTime);const fetchTime=json.fetchTime||fallbackFetchTime;const windowName=`${json.lighthouseVersion}-${json.requestedUrl}-${fetchTime}`;const popup=window.open(`${VIEWER_ORIGIN}${viewerPath}`,windowName);}
expandAllDetails(){const details=(this._dom.findAll('.lh-categories details',this._document));details.map(detail=>detail.open=true);}
collapseAllDetails(){const details=(this._dom.findAll('.lh-categories details',this._document));details.map(detail=>detail.open=false);}
_setUpCollapseDetailsAfterPrinting(){if('onbeforeprint'in self){self.addEventListener('afterprint',this.collapseAllDetails);}else{const win=(self);win.matchMedia('print').addListener(mql=>{if(mql.matches){this.expandAllDetails();}else{this.collapseAllDetails();}});}}
getReportHtml(){this._resetUIState();return this._document.documentElement.outerHTML;}
saveAsGist(){throw new Error('Cannot save as gist from base report');}
_saveFile(blob){const filename=getFilenamePrefix({finalUrl:this.json.finalUrl,fetchTime:this.json.fetchTime,});const ext=blob.type.match('json')?'.json':'.html';const href=URL.createObjectURL(blob);const a=this._dom.createElement('a');a.download=`${filename}${ext}`;a.href=href;this._document.body.appendChild(a);a.click();this._document.body.removeChild(a);setTimeout(_=>URL.revokeObjectURL(href),500);}
_toggleDarkTheme(force){const el=this._dom.find('.lh-vars',this._document);if(typeof force==='undefined'){el.classList.toggle('dark');}else{el.classList.toggle('dark',force);}}
_updateStickyHeaderOnScroll(){const topbarBottom=this.topbarEl.getBoundingClientRect().bottom;const scoreScaleTop=this.scoreScaleEl.getBoundingClientRect().top;const showStickyHeader=topbarBottom>=scoreScaleTop;const categoryEls=Array.from(this._document.querySelectorAll('.lh-category'));const categoriesAboveTheMiddle=categoryEls.filter(el=>el.getBoundingClientRect().top-window.innerHeight/2<0);const highlightIndex=categoriesAboveTheMiddle.length>0?categoriesAboveTheMiddle.length-1:0;const gaugeWrapperEls=this.stickyHeaderEl.querySelectorAll('.lh-gauge__wrapper');const gaugeToHighlight=gaugeWrapperEls[highlightIndex];const origin=gaugeWrapperEls[0].getBoundingClientRect().left;const offset=gaugeToHighlight.getBoundingClientRect().left-origin;this.highlightEl.style.transform=`translate(${offset}px)`;this.stickyHeaderEl.classList.toggle('lh-sticky-header--visible',showStickyHeader);}}
class DropDown{constructor(dom){this._dom=dom;this._toggleEl;this._menuEl;this.onDocumentKeyDown=this.onDocumentKeyDown.bind(this);this.onToggleClick=this.onToggleClick.bind(this);this.onToggleKeydown=this.onToggleKeydown.bind(this);this.onMenuFocusOut=this.onMenuFocusOut.bind(this);this.onMenuKeydown=this.onMenuKeydown.bind(this);this._getNextMenuItem=this._getNextMenuItem.bind(this);this._getNextSelectableNode=this._getNextSelectableNode.bind(this);this._getPreviousMenuItem=this._getPreviousMenuItem.bind(this);}
setup(menuClickHandler){this._toggleEl=this._dom.find('.lh-tools__button',this._dom.document());this._toggleEl.addEventListener('click',this.onToggleClick);this._toggleEl.addEventListener('keydown',this.onToggleKeydown);this._menuEl=this._dom.find('.lh-tools__dropdown',this._dom.document());this._menuEl.addEventListener('keydown',this.onMenuKeydown);this._menuEl.addEventListener('click',menuClickHandler);}
close(){this._toggleEl.classList.remove('active');this._toggleEl.setAttribute('aria-expanded','false');if(this._menuEl.contains(this._dom.document().activeElement)){this._toggleEl.focus();}
this._menuEl.removeEventListener('focusout',this.onMenuFocusOut);this._dom.document().removeEventListener('keydown',this.onDocumentKeyDown);}
open(firstFocusElement){if(this._toggleEl.classList.contains('active')){firstFocusElement.focus();}else{this._menuEl.addEventListener('transitionend',()=>{firstFocusElement.focus();},{once:true});}
this._toggleEl.classList.add('active');this._toggleEl.setAttribute('aria-expanded','true');this._menuEl.addEventListener('focusout',this.onMenuFocusOut);this._dom.document().addEventListener('keydown',this.onDocumentKeyDown);}
onToggleClick(e){e.preventDefault();e.stopImmediatePropagation();if(this._toggleEl.classList.contains('active')){this.close();}else{this.open(this._getNextMenuItem());}}
onToggleKeydown(e){switch(e.code){case'ArrowUp':e.preventDefault();this.open(this._getPreviousMenuItem());break;case'ArrowDown':case'Enter':case' ':e.preventDefault();this.open(this._getNextMenuItem());break;default:}}
onMenuKeydown(e){const el=(e.target);switch(e.code){case'ArrowUp':e.preventDefault();this._getPreviousMenuItem(el).focus();break;case'ArrowDown':e.preventDefault();this._getNextMenuItem(el).focus();break;case'Home':e.preventDefault();this._getNextMenuItem().focus();break;case'End':e.preventDefault();this._getPreviousMenuItem().focus();break;default:}}
onDocumentKeyDown(e){if(e.keyCode===27){this.close();}}
onMenuFocusOut(e){const focusEvent=(e);const focusedEl=(focusEvent.relatedTarget);if(!this._menuEl.contains(focusedEl)){this.close();}}
_getNextSelectableNode(allNodes,startNode){const nodes=allNodes.filter((node)=>{if(!(node instanceof HTMLElement)){return false;}
if(node.hasAttribute('disabled')){return false;}
if(window.getComputedStyle(node).display==='none'){return false;}
return true;});let nextIndex=startNode?(nodes.indexOf(startNode)+1):0;if(nextIndex>=nodes.length){nextIndex=0;}
return nodes[nextIndex];}
_getNextMenuItem(startEl){const nodes=Array.from(this._menuEl.childNodes);return(this._getNextSelectableNode(nodes,startEl));}
_getPreviousMenuItem(startEl){const nodes=Array.from(this._menuEl.childNodes).reverse();return(this._getNextSelectableNode(nodes,startEl));}}
if(typeof module!=='undefined'&&module.exports){module.exports=ReportUIFeatures$1;}else{self.ReportUIFeatures=ReportUIFeatures$1;};'use strict';class CategoryRenderer{constructor(dom,detailsRenderer){this.dom=dom;this.detailsRenderer=detailsRenderer;this.templateContext=this.dom.document();this.detailsRenderer.setTemplateContext(this.templateContext);}
get _clumpTitles(){return{warning:Util.i18n.strings.warningAuditsGroupTitle,manual:Util.i18n.strings.manualAuditsGroupTitle,passed:Util.i18n.strings.passedAuditsGroupTitle,notApplicable:Util.i18n.strings.notApplicableAuditsGroupTitle,};}
renderAudit(audit){const tmpl=this.dom.cloneTemplate('#tmpl-lh-audit',this.templateContext);return this.populateAuditValues(audit,tmpl);}
populateAuditValues(audit,tmpl){const strings=Util.i18n.strings;const auditEl=this.dom.find('.lh-audit',tmpl);auditEl.id=audit.result.id;const scoreDisplayMode=audit.result.scoreDisplayMode;if(audit.result.displayValue){this.dom.find('.lh-audit__display-text',auditEl).textContent=audit.result.displayValue;}
const titleEl=this.dom.find('.lh-audit__title',auditEl);titleEl.appendChild(this.dom.convertMarkdownCodeSnippets(audit.result.title));this.dom.find('.lh-audit__description',auditEl).appendChild(this.dom.convertMarkdownLinkSnippets(audit.result.description));if(audit.stackPacks){audit.stackPacks.forEach(pack=>{const packElm=this.dom.createElement('div');packElm.classList.add('lh-audit__stackpack');const packElmImg=this.dom.createElement('img');packElmImg.classList.add('lh-audit__stackpack__img');packElmImg.src=pack.iconDataURL;packElmImg.alt=pack.title;packElm.appendChild(packElmImg);packElm.appendChild(this.dom.convertMarkdownLinkSnippets(pack.description));this.dom.find('.lh-audit__stackpacks',auditEl).appendChild(packElm);});}
const header=(this.dom.find('details',auditEl));if(audit.result.details){const elem=this.detailsRenderer.render(audit.result.details);if(elem){elem.classList.add('lh-details');header.appendChild(elem);}}
this.dom.find('.lh-chevron-container',auditEl).appendChild(this._createChevron());this._setRatingClass(auditEl,audit.result.score,scoreDisplayMode);if(audit.result.scoreDisplayMode==='error'){auditEl.classList.add(`lh-audit--error`);const textEl=this.dom.find('.lh-audit__display-text',auditEl);textEl.textContent=strings.errorLabel;textEl.classList.add('tooltip-boundary');const tooltip=this.dom.createChildOf(textEl,'div','tooltip tooltip--error');tooltip.textContent=audit.result.errorMessage||strings.errorMissingAuditInfo;}else if(audit.result.explanation){const explEl=this.dom.createChildOf(titleEl,'div','lh-audit-explanation');explEl.textContent=audit.result.explanation;}
const warnings=audit.result.warnings;if(!warnings||warnings.length===0)return auditEl;const summaryEl=this.dom.find('summary',header);const warningsEl=this.dom.createChildOf(summaryEl,'div','lh-warnings');this.dom.createChildOf(warningsEl,'span').textContent=strings.warningHeader;if(warnings.length===1){warningsEl.appendChild(this.dom.document().createTextNode(warnings.join('')));}else{const warningsUl=this.dom.createChildOf(warningsEl,'ul');for(const warning of warnings){const item=this.dom.createChildOf(warningsUl,'li');item.textContent=warning;}}
return auditEl;}
_createChevron(){const chevronTmpl=this.dom.cloneTemplate('#tmpl-lh-chevron',this.templateContext);const chevronEl=this.dom.find('.lh-chevron',chevronTmpl);return chevronEl;}
_setRatingClass(element,score,scoreDisplayMode){const rating=Util.calculateRating(score,scoreDisplayMode);element.classList.add(`lh-audit--${scoreDisplayMode.toLowerCase()}`);if(scoreDisplayMode!=='informative'){element.classList.add(`lh-audit--${rating}`);}
return element;}
renderCategoryHeader(category,groupDefinitions){const tmpl=this.dom.cloneTemplate('#tmpl-lh-category-header',this.templateContext);const gaugeContainerEl=this.dom.find('.lh-score__gauge',tmpl);const gaugeEl=this.renderScoreGauge(category,groupDefinitions);gaugeContainerEl.appendChild(gaugeEl);if(category.description){const descEl=this.dom.convertMarkdownLinkSnippets(category.description);this.dom.find('.lh-category-header__description',tmpl).appendChild(descEl);}
return(tmpl.firstElementChild);}
renderAuditGroup(group){const groupEl=this.dom.createElement('div','lh-audit-group');const auditGroupHeader=this.dom.createElement('div','lh-audit-group__header');this.dom.createChildOf(auditGroupHeader,'span','lh-audit-group__title').textContent=group.title;if(group.description){const descriptionEl=this.dom.convertMarkdownLinkSnippets(group.description);descriptionEl.classList.add('lh-audit-group__description');auditGroupHeader.appendChild(descriptionEl);}
groupEl.appendChild(auditGroupHeader);return groupEl;}
_renderGroupedAudits(auditRefs,groupDefinitions){const grouped=new Map();const notAGroup='NotAGroup';grouped.set(notAGroup,[]);for(const auditRef of auditRefs){const groupId=auditRef.group||notAGroup;const groupAuditRefs=grouped.get(groupId)||[];groupAuditRefs.push(auditRef);grouped.set(groupId,groupAuditRefs);}
const auditElements=[];for(const[groupId,groupAuditRefs]of grouped){if(groupId===notAGroup){for(const auditRef of groupAuditRefs){auditElements.push(this.renderAudit(auditRef));}
continue;}
const groupDef=groupDefinitions[groupId];const auditGroupElem=this.renderAuditGroup(groupDef);for(const auditRef of groupAuditRefs){auditGroupElem.appendChild(this.renderAudit(auditRef));}
auditGroupElem.classList.add(`lh-audit-group--${groupId}`);auditElements.push(auditGroupElem);}
return auditElements;}
renderUnexpandableClump(auditRefs,groupDefinitions){const clumpElement=this.dom.createElement('div');const elements=this._renderGroupedAudits(auditRefs,groupDefinitions);elements.forEach(elem=>clumpElement.appendChild(elem));return clumpElement;}
renderClump(clumpId,{auditRefs,description}){const clumpTmpl=this.dom.cloneTemplate('#tmpl-lh-clump',this.templateContext);const clumpElement=this.dom.find('.lh-clump',clumpTmpl);if(clumpId==='warning'){clumpElement.setAttribute('open','');}
const summaryInnerEl=this.dom.find('.lh-audit-group__summary',clumpElement);const chevronEl=summaryInnerEl.appendChild(this._createChevron());chevronEl.title=Util.i18n.strings.auditGroupExpandTooltip;const headerEl=this.dom.find('.lh-audit-group__header',clumpElement);const title=this._clumpTitles[clumpId];this.dom.find('.lh-audit-group__title',headerEl).textContent=title;if(description){const descriptionEl=this.dom.convertMarkdownLinkSnippets(description);descriptionEl.classList.add('lh-audit-group__description');headerEl.appendChild(descriptionEl);}
const itemCountEl=this.dom.find('.lh-audit-group__itemcount',clumpElement);itemCountEl.textContent=`(${auditRefs.length})`;const auditElements=auditRefs.map(this.renderAudit.bind(this));clumpElement.append(...auditElements);clumpElement.classList.add(`lh-clump--${clumpId.toLowerCase()}`);return clumpElement;}
setTemplateContext(context){this.templateContext=context;this.detailsRenderer.setTemplateContext(context);}
renderScoreGauge(category,groupDefinitions){const tmpl=this.dom.cloneTemplate('#tmpl-lh-gauge',this.templateContext);const wrapper=(this.dom.find('.lh-gauge__wrapper',tmpl));wrapper.href=`#${category.id}`;wrapper.classList.add(`lh-gauge__wrapper--${Util.calculateRating(category.score)}`);if(Util.isPluginCategory(category.id)){wrapper.classList.add('lh-gauge__wrapper--plugin');}
const numericScore=Number(category.score);const gauge=this.dom.find('.lh-gauge',tmpl);const gaugeArc=gauge.querySelector('.lh-gauge-arc');if(gaugeArc)this._setGaugeArc(gaugeArc,numericScore);const scoreOutOf100=Math.round(numericScore*100);const percentageEl=this.dom.find('.lh-gauge__percentage',tmpl);percentageEl.textContent=scoreOutOf100.toString();if(category.score===null){percentageEl.textContent='?';percentageEl.title=Util.i18n.strings.errorLabel;}
this.dom.find('.lh-gauge__label',tmpl).textContent=category.title;return tmpl;}
_setGaugeArc(arcElem,percent){const circumferencePx=2*Math.PI*Number(arcElem.getAttribute('r'));const strokeWidthPx=Number(arcElem.getAttribute('stroke-width'));const rotationalAdjustmentPercent=0.25*strokeWidthPx/circumferencePx;arcElem.style.transform=`rotate(${-90 + rotationalAdjustmentPercent * 360}deg)`;let arcLengthPx=percent*circumferencePx-strokeWidthPx/2;if(percent===0)arcElem.style.opacity='0';if(percent===1)arcLengthPx=circumferencePx;arcElem.style.strokeDasharray=`${Math.max(arcLengthPx, 0)} ${circumferencePx}`;}
_auditHasWarning(audit){return Boolean(audit.result.warnings&&audit.result.warnings.length);}
_getClumpIdForAuditRef(auditRef){const scoreDisplayMode=auditRef.result.scoreDisplayMode;if(scoreDisplayMode==='manual'||scoreDisplayMode==='notApplicable'){return scoreDisplayMode;}
if(Util.showAsPassed(auditRef.result)){if(this._auditHasWarning(auditRef)){return'warning';}else{return'passed';}}else{return'failed';}}
render(category,groupDefinitions={}){const element=this.dom.createElement('div','lh-category');this.createPermalinkSpan(element,category.id);element.appendChild(this.renderCategoryHeader(category,groupDefinitions));const clumps=new Map();clumps.set('failed',[]);clumps.set('warning',[]);clumps.set('manual',[]);clumps.set('passed',[]);clumps.set('notApplicable',[]);for(const auditRef of category.auditRefs){const clumpId=this._getClumpIdForAuditRef(auditRef);const clump=(clumps.get(clumpId));clump.push(auditRef);clumps.set(clumpId,clump);}
for(const[clumpId,auditRefs]of clumps){if(auditRefs.length===0)continue;if(clumpId==='failed'){const clumpElem=this.renderUnexpandableClump(auditRefs,groupDefinitions);clumpElem.classList.add(`lh-clump--failed`);element.appendChild(clumpElem);continue;}
const description=clumpId==='manual'?category.manualDescription:undefined;const clumpElem=this.renderClump(clumpId,{auditRefs,description});element.appendChild(clumpElem);}
return element;}
createPermalinkSpan(element,id){const permalinkEl=this.dom.createChildOf(element,'span','lh-permalink');permalinkEl.id=id;}}
if(typeof module!=='undefined'&&module.exports){module.exports=CategoryRenderer;}else{self.CategoryRenderer=CategoryRenderer;};'use strict';class PerformanceCategoryRenderer extends CategoryRenderer{_renderMetric(audit){const tmpl=this.dom.cloneTemplate('#tmpl-lh-metric',this.templateContext);const element=this.dom.find('.lh-metric',tmpl);element.id=audit.result.id;const rating=Util.calculateRating(audit.result.score,audit.result.scoreDisplayMode);element.classList.add(`lh-metric--${rating}`);const titleEl=this.dom.find('.lh-metric__title',tmpl);titleEl.textContent=audit.result.title;const valueEl=this.dom.find('.lh-metric__value',tmpl);valueEl.textContent=audit.result.displayValue||'';const descriptionEl=this.dom.find('.lh-metric__description',tmpl);descriptionEl.appendChild(this.dom.convertMarkdownLinkSnippets(audit.result.description));if(audit.result.scoreDisplayMode==='error'){descriptionEl.textContent='';valueEl.textContent='Error!';const tooltip=this.dom.createChildOf(descriptionEl,'span');tooltip.textContent=audit.result.errorMessage||'Report error: no metric information';}
return element;}
_renderOpportunity(audit,scale){const oppTmpl=this.dom.cloneTemplate('#tmpl-lh-opportunity',this.templateContext);const element=this.populateAuditValues(audit,oppTmpl);element.id=audit.result.id;if(!audit.result.details||audit.result.scoreDisplayMode==='error'){return element;}
const details=audit.result.details;if(details.type!=='opportunity'){return element;}
const displayEl=this.dom.find('.lh-audit__display-text',element);const sparklineWidthPct=`${details.overallSavingsMs / scale * 100}%`;this.dom.find('.lh-sparkline__bar',element).style.width=sparklineWidthPct;displayEl.textContent=Util.i18n.formatSeconds(details.overallSavingsMs,0.01);if(audit.result.displayValue){const displayValue=audit.result.displayValue;this.dom.find('.lh-load-opportunity__sparkline',element).title=displayValue;displayEl.title=displayValue;}
return element;}
_getWastedMs(audit){if(audit.result.details&&audit.result.details.type==='opportunity'){const details=audit.result.details;if(typeof details.overallSavingsMs!=='number'){throw new Error('non-opportunity details passed to _getWastedMs');}
return details.overallSavingsMs;}else{return Number.MIN_VALUE;}}
_getScoringCalculatorHref(auditRefs){const v5andv6metrics=auditRefs.filter(audit=>audit.group==='metrics');const fci=auditRefs.find(audit=>audit.id==='first-cpu-idle');const fmp=auditRefs.find(audit=>audit.id==='first-meaningful-paint');if(fci)v5andv6metrics.push(fci);if(fmp)v5andv6metrics.push(fmp);const metricPairs=v5andv6metrics.map(audit=>{const value=typeof audit.result.numericValue!=='undefined'?audit.result.numericValue.toString():'null';return[audit.id,value];});const paramPairs=[...metricPairs];if(Util.reportJson){paramPairs.push(['device',Util.reportJson.configSettings.emulatedFormFactor]);paramPairs.push(['version',Util.reportJson.lighthouseVersion]);}
const params=new URLSearchParams(paramPairs);const url=new URL('https://googlechrome.github.io/lighthouse/scorecalc/');url.hash=params.toString();return url.href;}
render(category,groups,environment){const strings=Util.i18n.strings;const element=this.dom.createElement('div','lh-category');if(environment==='PSI'){const gaugeEl=this.dom.createElement('div','lh-score__gauge');gaugeEl.appendChild(this.renderScoreGauge(category,groups));element.appendChild(gaugeEl);}else{this.createPermalinkSpan(element,category.id);element.appendChild(this.renderCategoryHeader(category,groups));}
const metricAuditsEl=this.renderAuditGroup(groups.metrics);const toggleTmpl=this.dom.cloneTemplate('#tmpl-lh-metrics-toggle',this.templateContext);const _toggleEl=this.dom.find('.lh-metrics-toggle',toggleTmpl);metricAuditsEl.append(..._toggleEl.childNodes);const metricAudits=category.auditRefs.filter(audit=>audit.group==='metrics');const keyMetrics=metricAudits.slice(0,3);const otherMetrics=metricAudits.slice(3);const metricsBoxesEl=this.dom.createChildOf(metricAuditsEl,'div','lh-columns');const metricsColumn1El=this.dom.createChildOf(metricsBoxesEl,'div','lh-column');const metricsColumn2El=this.dom.createChildOf(metricsBoxesEl,'div','lh-column');keyMetrics.forEach(item=>{metricsColumn1El.appendChild(this._renderMetric(item));});otherMetrics.forEach(item=>{metricsColumn2El.appendChild(this._renderMetric(item));});if(environment!=='PSI'){const estValuesEl=this.dom.createChildOf(metricAuditsEl,'div','lh-metrics__disclaimer');const disclaimerEl=this.dom.convertMarkdownLinkSnippets(strings.varianceDisclaimer);estValuesEl.appendChild(disclaimerEl);const calculatorLink=this.dom.createChildOf(estValuesEl,'a','lh-calclink');calculatorLink.target='_blank';calculatorLink.textContent=strings.calculatorLink;calculatorLink.href=this._getScoringCalculatorHref(category.auditRefs);}
metricAuditsEl.classList.add('lh-audit-group--metrics');element.appendChild(metricAuditsEl);const timelineEl=this.dom.createChildOf(element,'div','lh-filmstrip-container');const thumbnailAudit=category.auditRefs.find(audit=>audit.id==='screenshot-thumbnails');const thumbnailResult=thumbnailAudit&&thumbnailAudit.result;if(thumbnailResult&&thumbnailResult.details){timelineEl.id=thumbnailResult.id;const filmstripEl=this.detailsRenderer.render(thumbnailResult.details);filmstripEl&&timelineEl.appendChild(filmstripEl);}
const budgetTableEls=[];['performance-budget','timing-budget'].forEach((id)=>{const audit=category.auditRefs.find(audit=>audit.id===id);if(audit&&audit.result.details){const table=this.detailsRenderer.render(audit.result.details);if(table){table.id=id;table.classList.add('lh-audit');budgetTableEls.push(table);}}});if(budgetTableEls.length>0){const budgetsGroupEl=this.renderAuditGroup(groups.budgets);budgetTableEls.forEach(table=>budgetsGroupEl.appendChild(table));budgetsGroupEl.classList.add('lh-audit-group--budgets');element.appendChild(budgetsGroupEl);}
const opportunityAudits=category.auditRefs.filter(audit=>audit.group==='load-opportunities'&&!Util.showAsPassed(audit.result)).sort((auditA,auditB)=>this._getWastedMs(auditB)-this._getWastedMs(auditA));if(opportunityAudits.length){const minimumScale=2000;const wastedMsValues=opportunityAudits.map(audit=>this._getWastedMs(audit));const maxWaste=Math.max(...wastedMsValues);const scale=Math.max(Math.ceil(maxWaste/1000)*1000,minimumScale);const groupEl=this.renderAuditGroup(groups['load-opportunities']);const tmpl=this.dom.cloneTemplate('#tmpl-lh-opportunity-header',this.templateContext);this.dom.find('.lh-load-opportunity__col--one',tmpl).textContent=strings.opportunityResourceColumnLabel;this.dom.find('.lh-load-opportunity__col--two',tmpl).textContent=strings.opportunitySavingsColumnLabel;const headerEl=this.dom.find('.lh-load-opportunity__header',tmpl);groupEl.appendChild(headerEl);opportunityAudits.forEach(item=>groupEl.appendChild(this._renderOpportunity(item,scale)));groupEl.classList.add('lh-audit-group--load-opportunities');element.appendChild(groupEl);}
const diagnosticAudits=category.auditRefs.filter(audit=>audit.group==='diagnostics'&&!Util.showAsPassed(audit.result)).sort((a,b)=>{const scoreA=a.result.scoreDisplayMode==='informative'?100:Number(a.result.score);const scoreB=b.result.scoreDisplayMode==='informative'?100:Number(b.result.score);return scoreA-scoreB;});if(diagnosticAudits.length){const groupEl=this.renderAuditGroup(groups['diagnostics']);diagnosticAudits.forEach(item=>groupEl.appendChild(this.renderAudit(item)));groupEl.classList.add('lh-audit-group--diagnostics');element.appendChild(groupEl);}
const passedAudits=category.auditRefs.filter(audit=>(audit.group==='load-opportunities'||audit.group==='diagnostics')&&Util.showAsPassed(audit.result));if(!passedAudits.length)return element;const clumpOpts={auditRefs:passedAudits,groupDefinitions:groups,};const passedElem=this.renderClump('passed',clumpOpts);element.appendChild(passedElem);return element;}}
if(typeof module!=='undefined'&&module.exports){module.exports=PerformanceCategoryRenderer;}else{self.PerformanceCategoryRenderer=PerformanceCategoryRenderer;};'use strict';const getUniqueSuffix=(()=>{let svgSuffix=0;return function(){return svgSuffix++;};})();class PwaCategoryRenderer extends CategoryRenderer{render(category,groupDefinitions={}){const categoryElem=this.dom.createElement('div','lh-category');this.createPermalinkSpan(categoryElem,category.id);categoryElem.appendChild(this.renderCategoryHeader(category,groupDefinitions));const auditRefs=category.auditRefs;const regularAuditRefs=auditRefs.filter(ref=>ref.result.scoreDisplayMode!=='manual');const auditsElem=this._renderAudits(regularAuditRefs,groupDefinitions);categoryElem.appendChild(auditsElem);const manualAuditRefs=auditRefs.filter(ref=>ref.result.scoreDisplayMode==='manual');const manualElem=this.renderClump('manual',{auditRefs:manualAuditRefs,description:category.manualDescription});categoryElem.appendChild(manualElem);return categoryElem;}
renderScoreGauge(category,groupDefinitions){if(category.score===null){return super.renderScoreGauge(category,groupDefinitions);}
const tmpl=this.dom.cloneTemplate('#tmpl-lh-gauge--pwa',this.templateContext);const wrapper=(this.dom.find('.lh-gauge--pwa__wrapper',tmpl));wrapper.href=`#${category.id}`;const svgRoot=tmpl.querySelector('svg');if(!svgRoot)throw new Error('no SVG element found in PWA score gauge template');PwaCategoryRenderer._makeSvgReferencesUnique(svgRoot);const allGroups=this._getGroupIds(category.auditRefs);const passingGroupIds=this._getPassingGroupIds(category.auditRefs);if(passingGroupIds.size===allGroups.size){wrapper.classList.add('lh-badged--all');}else{for(const passingGroupId of passingGroupIds){wrapper.classList.add(`lh-badged--${passingGroupId}`);}}
this.dom.find('.lh-gauge__label',tmpl).textContent=category.title;wrapper.title=this._getGaugeTooltip(category.auditRefs,groupDefinitions);return tmpl;}
_getGroupIds(auditRefs){const groupIds=auditRefs.map(ref=>ref.group).filter(g=>!!g);return new Set(groupIds);}
_getPassingGroupIds(auditRefs){const uniqueGroupIds=this._getGroupIds(auditRefs);for(const auditRef of auditRefs){if(!Util.showAsPassed(auditRef.result)&&auditRef.group){uniqueGroupIds.delete(auditRef.group);}}
return uniqueGroupIds;}
_getGaugeTooltip(auditRefs,groupDefinitions){const groupIds=this._getGroupIds(auditRefs);const tips=[];for(const groupId of groupIds){const groupAuditRefs=auditRefs.filter(ref=>ref.group===groupId);const auditCount=groupAuditRefs.length;const passedCount=groupAuditRefs.filter(ref=>Util.showAsPassed(ref.result)).length;const title=groupDefinitions[groupId].title;tips.push(`${title}: ${passedCount}/${auditCount}`);}
return tips.join(', ');}
_renderAudits(auditRefs,groupDefinitions){const auditsElem=this.renderUnexpandableClump(auditRefs,groupDefinitions);const passsingGroupIds=this._getPassingGroupIds(auditRefs);for(const groupId of passsingGroupIds){const groupElem=this.dom.find(`.lh-audit-group--${groupId}`,auditsElem);groupElem.classList.add('lh-badged');}
return auditsElem;}
static _makeSvgReferencesUnique(svgRoot){const defsEl=svgRoot.querySelector('defs');if(!defsEl)return;const idSuffix=getUniqueSuffix();const elementsToUpdate=defsEl.querySelectorAll('[id]');for(const el of elementsToUpdate){const oldId=el.id;const newId=`${oldId}-${idSuffix}`;el.id=newId;const useEls=svgRoot.querySelectorAll(`use[href="#${oldId}"]`);for(const useEl of useEls){useEl.setAttribute('href',`#${newId}`);}
const fillEls=svgRoot.querySelectorAll(`[fill="url(#${oldId})"]`);for(const fillEl of fillEls){fillEl.setAttribute('fill',`url(#${newId})`);}}}}
if(typeof module!=='undefined'&&module.exports){module.exports=PwaCategoryRenderer;}else{self.PwaCategoryRenderer=PwaCategoryRenderer;};'use strict';class ReportRenderer$1{constructor(dom){this._dom=dom;this._templateContext=this._dom.document();}
renderReport(result,container){this._dom.setLighthouseChannel(result.configSettings.channel||'unknown');const report=Util.prepareReportResult(result);container.textContent='';container.appendChild(this._renderReport(report));return container;}
setTemplateContext(context){this._templateContext=context;}
_renderReportTopbar(report){const el=this._dom.cloneTemplate('#tmpl-lh-topbar',this._templateContext);const metadataUrl=(this._dom.find('.lh-topbar__url',el));metadataUrl.href=metadataUrl.textContent=report.finalUrl;metadataUrl.title=report.finalUrl;return el;}
_renderReportHeader(){const el=this._dom.cloneTemplate('#tmpl-lh-heading',this._templateContext);const domFragment=this._dom.cloneTemplate('#tmpl-lh-scores-wrapper',this._templateContext);const placeholder=this._dom.find('.lh-scores-wrapper-placeholder',el);(placeholder.parentNode).replaceChild(domFragment,placeholder);return el;}
_renderReportFooter(report){const footer=this._dom.cloneTemplate('#tmpl-lh-footer',this._templateContext);const env=this._dom.find('.lh-env__items',footer);env.id='runtime-settings';this._dom.find('.lh-env__title',footer).textContent=Util.i18n.strings.runtimeSettingsTitle;const envValues=Util.getEnvironmentDisplayValues(report.configSettings||{});[{name:Util.i18n.strings.runtimeSettingsUrl,description:report.finalUrl},{name:Util.i18n.strings.runtimeSettingsFetchTime,description:Util.i18n.formatDateTime(report.fetchTime)},...envValues,{name:Util.i18n.strings.runtimeSettingsChannel,description:report.configSettings.channel},{name:Util.i18n.strings.runtimeSettingsUA,description:report.userAgent},{name:Util.i18n.strings.runtimeSettingsUANetwork,description:report.environment&&report.environment.networkUserAgent},{name:Util.i18n.strings.runtimeSettingsBenchmark,description:report.environment&&report.environment.benchmarkIndex.toFixed(0)},].forEach(runtime=>{if(!runtime.description)return;const item=this._dom.cloneTemplate('#tmpl-lh-env__items',env);this._dom.find('.lh-env__name',item).textContent=runtime.name;this._dom.find('.lh-env__description',item).textContent=runtime.description;env.appendChild(item);});this._dom.find('.lh-footer__version_issue',footer).textContent=Util.i18n.strings.footerIssue;this._dom.find('.lh-footer__version',footer).textContent=report.lighthouseVersion;return footer;}
_renderReportWarnings(report){if(!report.runWarnings||report.runWarnings.length===0){return this._dom.createElement('div');}
const container=this._dom.cloneTemplate('#tmpl-lh-warnings--toplevel',this._templateContext);const message=this._dom.find('.lh-warnings__msg',container);message.textContent=Util.i18n.strings.toplevelWarningsMessage;const warnings=this._dom.find('ul',container);for(const warningString of report.runWarnings){const warning=warnings.appendChild(this._dom.createElement('li'));warning.textContent=warningString;}
return container;}
_renderScoreGauges(report,categoryRenderer,specificCategoryRenderers){const defaultGauges=[];const customGauges=[];const pluginGauges=[];for(const category of Object.values(report.categories)){const renderer=specificCategoryRenderers[category.id]||categoryRenderer;const categoryGauge=renderer.renderScoreGauge(category,report.categoryGroups||{});if(Util.isPluginCategory(category.id)){pluginGauges.push(categoryGauge);}else if(renderer.renderScoreGauge===categoryRenderer.renderScoreGauge){defaultGauges.push(categoryGauge);}else{customGauges.push(categoryGauge);}}
return[...defaultGauges,...customGauges,...pluginGauges];}
_renderReport(report){const i18n=new I18n(report.configSettings.locale,{...Util.UIStrings,...report.i18n.rendererFormattedStrings,});Util.i18n=i18n;Util.reportJson=report;const detailsRenderer=new DetailsRenderer(this._dom);const categoryRenderer=new CategoryRenderer(this._dom,detailsRenderer);categoryRenderer.setTemplateContext(this._templateContext);const specificCategoryRenderers={performance:new PerformanceCategoryRenderer(this._dom,detailsRenderer),pwa:new PwaCategoryRenderer(this._dom,detailsRenderer),};Object.values(specificCategoryRenderers).forEach(renderer=>{renderer.setTemplateContext(this._templateContext);});const headerContainer=this._dom.createElement('div');headerContainer.appendChild(this._renderReportHeader());const reportContainer=this._dom.createElement('div','lh-container');const reportSection=this._dom.createElement('div','lh-report');reportSection.appendChild(this._renderReportWarnings(report));let scoreHeader;const isSoloCategory=Object.keys(report.categories).length===1;if(!isSoloCategory){scoreHeader=this._dom.createElement('div','lh-scores-header');}else{headerContainer.classList.add('lh-header--solo-category');}
if(scoreHeader){const scoreScale=this._dom.cloneTemplate('#tmpl-lh-scorescale',this._templateContext);const scoresContainer=this._dom.find('.lh-scores-container',headerContainer);scoreHeader.append(...this._renderScoreGauges(report,categoryRenderer,specificCategoryRenderers));scoresContainer.appendChild(scoreHeader);scoresContainer.appendChild(scoreScale);const stickyHeader=this._dom.createElement('div','lh-sticky-header');stickyHeader.append(...this._renderScoreGauges(report,categoryRenderer,specificCategoryRenderers));reportContainer.appendChild(stickyHeader);}
const categories=reportSection.appendChild(this._dom.createElement('div','lh-categories'));for(const category of Object.values(report.categories)){const renderer=specificCategoryRenderers[category.id]||categoryRenderer;const wrapper=renderer.dom.createChildOf(categories,'div','lh-category-wrapper');wrapper.appendChild(renderer.render(category,report.categoryGroups));}
const reportFragment=this._dom.createFragment();const topbarDocumentFragment=this._renderReportTopbar(report);reportFragment.appendChild(topbarDocumentFragment);reportFragment.appendChild(reportContainer);reportContainer.appendChild(headerContainer);reportContainer.appendChild(reportSection);reportSection.appendChild(this._renderReportFooter(report));return reportFragment;}}
if(typeof module!=='undefined'&&module.exports){module.exports=ReportRenderer$1;}else{self.ReportRenderer=ReportRenderer$1;};'use strict';const NBSP2='\xa0';class I18n{constructor(locale,strings){if(locale==='en-XA')locale='de';this._numberDateLocale=locale;this._numberFormatter=new Intl.NumberFormat(locale);this._strings=(strings||{});}
get strings(){return this._strings;}
formatNumber(number,granularity=0.1){const coarseValue=Math.round(number/granularity)*granularity;return this._numberFormatter.format(coarseValue);}
formatBytesToKB(size,granularity=0.1){const kbs=this._numberFormatter.format(Math.round(size/1024/granularity)*granularity);return`${kbs}${NBSP2}KB`;}
formatMilliseconds(ms,granularity=10){const coarseTime=Math.round(ms/granularity)*granularity;return`${this._numberFormatter.format(coarseTime)}${NBSP2}ms`;}
formatSeconds(ms,granularity=0.1){const coarseTime=Math.round(ms/1000/granularity)*granularity;return`${this._numberFormatter.format(coarseTime)}${NBSP2}s`;}
formatDateTime(date){const options={month:'short',day:'numeric',year:'numeric',hour:'numeric',minute:'numeric',timeZoneName:'short',};let formatter=new Intl.DateTimeFormat(this._numberDateLocale,options);const tz=formatter.resolvedOptions().timeZone;if(!tz||tz.toLowerCase()==='etc/unknown'){options.timeZone='UTC';formatter=new Intl.DateTimeFormat(this._numberDateLocale,options);}
return formatter.format(new Date(date));}
formatDuration(timeInMilliseconds){let timeInSeconds=timeInMilliseconds/1000;if(Math.round(timeInSeconds)===0){return'None';}
const parts=[];const unitLabels=({d:60*60*24,h:60*60,m:60,s:1,});Object.keys(unitLabels).forEach(label=>{const unit=unitLabels[label];const numberOfUnits=Math.floor(timeInSeconds/unit);if(numberOfUnits>0){timeInSeconds-=numberOfUnits*unit;parts.push(`${numberOfUnits}\xa0${label}`);}});return parts.join(' ');}}
if(typeof module!=='undefined'&&module.exports){module.exports=I18n;}else{self.I18n=I18n;}
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f();}else if(typeof define==="function"&&define.amd){define([],f);}else{var g;if(typeof window!=="undefined"){g=window;}else if(typeof global!=="undefined"){g=global;}else if(typeof self!=="undefined"){g=self;}else{g=this;}(g.Lighthouse||(g.Lighthouse={})).ReportGenerator=f();}})(function(){var define,module,exports;return(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t);}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({"./html/html-report-assets.js":[function(require,module,exports){'use strict';const cachedResources=Runtime.cachedResources;module.exports={get REPORT_CSS(){return cachedResources['third_party/lighthouse/report-assets/report.css'];},get REPORT_JAVASCRIPT(){return cachedResources['third_party/lighthouse/report-assets/report.js'];},get REPORT_TEMPLATE(){return cachedResources['third_party/lighthouse/report-assets/template.html'];},get REPORT_TEMPLATES(){return cachedResources['third_party/lighthouse/report-assets/templates.html'];},};},{}],1:[function(require,module,exports){'use strict';const htmlReportAssets=require('./html/html-report-assets.js');class ReportGenerator{static replaceStrings(source,replacements){if(replacements.length===0){return source;}
const firstReplacement=replacements[0];const nextReplacements=replacements.slice(1);return source.split(firstReplacement.search).map(part=>ReportGenerator.replaceStrings(part,nextReplacements)).join(firstReplacement.replacement);}
static generateReportHtml(lhr){const sanitizedJson=JSON.stringify(lhr).replace(/</g,'\\u003c').replace(/\u2028/g,'\\u2028').replace(/\u2029/g,'\\u2029');const sanitizedJavascript=htmlReportAssets.REPORT_JAVASCRIPT.replace(/<\//g,'\\u003c/');return ReportGenerator.replaceStrings(htmlReportAssets.REPORT_TEMPLATE,[{search:'%%LIGHTHOUSE_JSON%%',replacement:sanitizedJson},{search:'%%LIGHTHOUSE_JAVASCRIPT%%',replacement:sanitizedJavascript},{search:'/*%%LIGHTHOUSE_CSS%%*/',replacement:htmlReportAssets.REPORT_CSS},{search:'%%LIGHTHOUSE_TEMPLATES%%',replacement:htmlReportAssets.REPORT_TEMPLATES},]);}
static generateReportCSV(lhr){const CRLF='\r\n';const separator=',';const escape=value=>`"${value.replace(/"/g, '""')}"`;const header=['requestedUrl','finalUrl','category','name','title','type','score'];const table=Object.values(lhr.categories).map(category=>{return category.auditRefs.map(auditRef=>{const audit=lhr.audits[auditRef.id];const numericScore=audit.score===null?-1:audit.score;return[lhr.requestedUrl,lhr.finalUrl,category.title,audit.id,audit.title,audit.scoreDisplayMode,numericScore].map(value=>value.toString()).map(escape);});});return[header].concat(...table).map(row=>row.join(separator)).join(CRLF);}
static generateReport(lhr,outputModes){const outputAsArray=Array.isArray(outputModes);if(typeof outputModes==='string')outputModes=[outputModes];const output=outputModes.map(outputMode=>{if(outputMode==='html'){return ReportGenerator.generateReportHtml(lhr);}
if(outputMode==='csv'){return ReportGenerator.generateReportCSV(lhr);}
if(outputMode==='json'){return JSON.stringify(lhr,null,2);}
throw new Error('Invalid output mode: '+outputMode);});return outputAsArray?output:output[0];}}
module.exports=ReportGenerator;},{"./html/html-report-assets.js":"./html/html-report-assets.js"}]},{},[1])(1)});class LighthouseController extends ObjectWrapper.ObjectWrapper{constructor(protocolService){super();protocolService.registerStatusCallback(message=>this.dispatchEventToListeners(Events.AuditProgressChanged,{message}));for(const preset of Presets){preset.setting.addChangeListener(this.recomputePageAuditability.bind(this));}
SDKModel.TargetManager.instance().observeModels(ServiceWorkerManager.ServiceWorkerManager,this);SDKModel.TargetManager.instance().addEventListener(SDKModel.Events.InspectedURLChanged,this.recomputePageAuditability,this);}
modelAdded(serviceWorkerManager){if(this._manager){return;}
this._manager=serviceWorkerManager;this._serviceWorkerListeners=[this._manager.addEventListener(ServiceWorkerManager.Events.RegistrationUpdated,this.recomputePageAuditability,this),this._manager.addEventListener(ServiceWorkerManager.Events.RegistrationDeleted,this.recomputePageAuditability,this),];this.recomputePageAuditability();}
modelRemoved(serviceWorkerManager){if(this._manager!==serviceWorkerManager){return;}
EventTarget.EventTarget.removeEventListeners(this._serviceWorkerListeners);this._manager=null;this.recomputePageAuditability();}
_hasActiveServiceWorker(){if(!this._manager){return false;}
const mainTarget=this._manager.target();if(!mainTarget){return false;}
const inspectedURL=ParsedURL.ParsedURL.fromString(mainTarget.inspectedURL());const inspectedOrigin=inspectedURL&&inspectedURL.securityOrigin();for(const registration of this._manager.registrations().values()){if(registration.securityOrigin!==inspectedOrigin){continue;}
for(const version of registration.versions.values()){if(version.controlledClients.length>1){return true;}}}
return false;}
_hasAtLeastOneCategory(){return Presets.some(preset=>preset.setting.get());}
_unauditablePageMessage(){if(!this._manager){return null;}
const mainTarget=this._manager.target();const inspectedURL=mainTarget&&mainTarget.inspectedURL();if(inspectedURL&&!/^(http|chrome-extension)/.test(inspectedURL)){return UIString.UIString('Can only audit HTTP/HTTPS pages and Chrome extensions. Navigate to a different page to start an audit.');}
return null;}
async _evaluateInspectedURL(){const mainTarget=this._manager.target();const runtimeModel=mainTarget.model(RuntimeModel.RuntimeModel);const executionContext=runtimeModel&&runtimeModel.defaultExecutionContext();let inspectedURL=mainTarget.inspectedURL();if(!executionContext){return inspectedURL;}
try{const result=await executionContext.evaluate({expression:'window.location.href',objectGroup:'lighthouse',includeCommandLineAPI:false,silent:false,returnByValue:true,generatePreview:false},false,false);if(!result.exceptionDetails&&result.object){inspectedURL=result.object.value;result.object.release();}}catch(err){console.error(err);}
return inspectedURL;}
getFlags(){const flags={internalDisableDeviceScreenEmulation:true};for(const runtimeSetting of RuntimeSettings){runtimeSetting.setFlags(flags,runtimeSetting.setting.get());}
return flags;}
getCategoryIDs(){const categoryIDs=[];for(const preset of Presets){if(preset.setting.get()){categoryIDs.push(preset.configID);}}
return categoryIDs;}
async getInspectedURL(options){if(options&&options.force||!this._inspectedURL){this._inspectedURL=await this._evaluateInspectedURL();}
return this._inspectedURL;}
recomputePageAuditability(){const hasActiveServiceWorker=this._hasActiveServiceWorker();const hasAtLeastOneCategory=this._hasAtLeastOneCategory();const unauditablePageMessage=this._unauditablePageMessage();let helpText='';if(hasActiveServiceWorker){helpText=UIString.UIString('Multiple tabs are being controlled by the same service worker. Close your other tabs on the same origin to audit this page.');}else if(!hasAtLeastOneCategory){helpText=UIString.UIString('At least one category must be selected.');}else if(unauditablePageMessage){helpText=unauditablePageMessage;}
this.dispatchEventToListeners(Events.PageAuditabilityChanged,{helpText});}}
const Presets=[{setting:Settings.Settings.instance().createSetting('lighthouse.cat_perf',true),configID:'performance',title:ls`Performance`,description:ls`How long does this app take to show content and become usable`},{setting:Settings.Settings.instance().createSetting('lighthouse.cat_pwa',true),configID:'pwa',title:ls`Progressive Web App`,description:ls`Does this page meet the standard of a Progressive Web App`},{setting:Settings.Settings.instance().createSetting('lighthouse.cat_best_practices',true),configID:'best-practices',title:ls`Best practices`,description:ls`Does this page follow best practices for modern web development`},{setting:Settings.Settings.instance().createSetting('lighthouse.cat_a11y',true),configID:'accessibility',title:ls`Accessibility`,description:ls`Is this page usable by people with disabilities or impairments`},{setting:Settings.Settings.instance().createSetting('lighthouse.cat_seo',true),configID:'seo',title:ls`SEO`,description:ls`Is this page optimized for search engine results ranking`},{setting:Settings.Settings.instance().createSetting('lighthouse.cat_pubads',false),plugin:true,configID:'lighthouse-plugin-publisher-ads',title:ls`Publisher Ads`,description:ls`Is this page optimized for ad speed and quality`},];const RuntimeSettings=[{setting:Settings.Settings.instance().createSetting('lighthouse.device_type','mobile'),description:ls`Apply mobile emulation during auditing`,setFlags:(flags,value)=>{flags.emulatedFormFactor=value;},options:[{label:ls`Mobile`,value:'mobile'},{label:ls`Desktop`,value:'desktop'},],},{setting:Settings.Settings.instance().createSetting('lighthouse.throttling',true),title:ls`Simulated throttling`,learnMore:'https://github.com/GoogleChrome/lighthouse/blob/master/docs/throttling.md#devtools-lighthouse-panel-throttling',description:ls`Simulate a slower page load, based on data from an initial unthrottled load. If disabled, the page is actually slowed with applied throttling.`,setFlags:(flags,value)=>{flags.throttlingMethod=value?'simulate':'devtools';},},{setting:Settings.Settings.instance().createSetting('lighthouse.clear_storage',true),title:ls`Clear storage`,description:ls`Reset storage (localStorage, IndexedDB, etc) before auditing. (Good for performance & PWA testing)`,setFlags:(flags,value)=>{flags.disableStorageReset=!value;},},];const Events={PageAuditabilityChanged:Symbol('PageAuditabilityChanged'),AuditProgressChanged:Symbol('AuditProgressChanged'),RequestLighthouseStart:Symbol('RequestLighthouseStart'),RequestLighthouseCancel:Symbol('RequestLighthouseCancel'),};let Preset;let RuntimeSetting;var LighthouseController$1=Object.freeze({__proto__:null,LighthouseController:LighthouseController,Presets:Presets,RuntimeSettings:RuntimeSettings,Events:Events,Preset:Preset,RuntimeSetting:RuntimeSetting});class ProtocolService extends ObjectWrapper.ObjectWrapper{constructor(){super();this._rawConnection=null;this._backend=null;this._backendPromise=null;this._status=null;}
async attach(){await SDKModel.TargetManager.instance().suspendAllTargets();const childTargetManager=SDKModel.TargetManager.instance().mainTarget().model(ChildTargetManager.ChildTargetManager);this._rawConnection=await childTargetManager.createParallelConnection(this._dispatchProtocolMessage.bind(this));}
startLighthouse(auditURL,categoryIDs,flags){return this._send('start',{url:auditURL,categoryIDs,flags});}
async detach(){await this._send('stop');await this._backend.dispose();delete this._backend;delete this._backendPromise;await this._rawConnection.disconnect();await SDKModel.TargetManager.instance().resumeAllTargets();}
registerStatusCallback(callback){this._status=callback;}
_dispatchProtocolMessage(message){this._send('dispatchProtocolMessage',{message:JSON.stringify(message)});}
_initWorker(){this._backendPromise=Services.serviceManager.createAppService('lighthouse_worker','LighthouseService').then(backend=>{if(this._backend){return;}
this._backend=backend;this._backend.on('statusUpdate',result=>this._status(result.message));this._backend.on('sendProtocolMessage',result=>this._sendProtocolMessage(result.message));});}
_sendProtocolMessage(message){this._rawConnection.sendRawMessage(message);}
_send(method,params){if(!this._backendPromise){this._initWorker();}
return this._backendPromise.then(_=>this._backend.send(method,params));}}
var LighthouseProtocolService=Object.freeze({__proto__:null,ProtocolService:ProtocolService});const MaxLengthForLinks=40;class LighthouseReportRenderer extends ReportRenderer{static addViewTraceButton(el,artifacts){if(!artifacts||!artifacts.traces||!artifacts.traces.defaultPass){return;}
const container=el.querySelector('.lh-audit-group');const disclaimerEl=container.querySelector('.lh-metrics__disclaimer');if(!disclaimerEl){return;}
const defaultPassTrace=artifacts.traces.defaultPass;const timelineButton=UIUtils.createTextButton(UIString.UIString('View Trace'),onViewTraceClick,'view-trace');container.insertBefore(timelineButton,disclaimerEl.nextSibling);async function onViewTraceClick(){userMetrics.actionTaken(Host.UserMetrics.Action.LighthouseViewTrace);await self.UI.inspectorView.showPanel('timeline');TimelinePanel.TimelinePanel.instance().loadFromEvents(defaultPassTrace.traceEvents);}}
static async linkifyNodeDetails(el){const mainTarget=SDKModel.TargetManager.instance().mainTarget();const domModel=mainTarget.model(DOMModel.DOMModel);for(const origElement of el.getElementsByClassName('lh-node')){const detailsItem=origElement.dataset;if(!detailsItem.path){continue;}
const nodeId=await domModel.pushNodeByPathToFrontend(detailsItem.path);if(!nodeId){continue;}
const node=domModel.nodeForId(nodeId);if(!node){continue;}
const element=await Linkifier.Linkifier.linkify(node,{tooltip:detailsItem.snippet});origElement.title='';origElement.textContent='';origElement.appendChild(element);}}
static async linkifySourceLocationDetails(el){for(const origElement of el.getElementsByClassName('lh-source-location')){const detailsItem=origElement.dataset;if(!detailsItem.sourceUrl||!detailsItem.sourceLine||!detailsItem.sourceColumn){continue;}
const url=detailsItem.sourceUrl;const line=Number(detailsItem.sourceLine);const column=Number(detailsItem.sourceColumn);const element=await Linkifier$1.Linkifier.linkifyURL(url,{lineNumber:line,column,maxLength:MaxLengthForLinks});origElement.title='';origElement.textContent='';origElement.appendChild(element);}}
static handleDarkMode(el){if(self.UI.themeSupport.themeName()==='dark'){el.classList.add('dark');}}}
class LighthouseReportUIFeatures extends ReportUIFeatures{constructor(dom){super(dom);this._beforePrint=null;this._afterPrint=null;}
setBeforePrint(beforePrint){this._beforePrint=beforePrint;}
setAfterPrint(afterPrint){this._afterPrint=afterPrint;}
getReportHtml(){this.resetUIState();return Lighthouse.ReportGenerator.generateReportHtml(this.json);}
async _saveFile(blob){const domain=new ParsedURL.ParsedURL(this.json.finalUrl).domain();const sanitizedDomain=domain.replace(/[^a-z0-9.-]+/gi,'_');const timestamp=new Date(this.json.fetchTime).toISO8601Compact();const ext=blob.type.match('json')?'.json':'.html';const basename=`${sanitizedDomain}-${timestamp}${ext}`;const text=await blob.text();self.Workspace.fileManager.save(basename,text,true);}
async _print(){const document=this.getDocument();const clonedReport=document.querySelector('.lh-root').cloneNode(true);const printWindow=window.open('','_blank','channelmode=1,status=1,resizable=1');const style=printWindow.document.createElement('style');style.textContent=self.Runtime.cachedResources['third_party/lighthouse/report-assets/report.css'];printWindow.document.head.appendChild(style);printWindow.document.body.replaceWith(clonedReport);await LighthouseReportRenderer.linkifyNodeDetails(clonedReport);if(this._beforePrint){this._beforePrint();}
printWindow.focus();printWindow.print();printWindow.close();if(this._afterPrint){this._afterPrint();}}
getDocument(){return this._document;}
resetUIState(){this._resetUIState();}}
var LighthouseReportRenderer$1=Object.freeze({__proto__:null,LighthouseReportRenderer:LighthouseReportRenderer,LighthouseReportUIFeatures:LighthouseReportUIFeatures});class ReportSelector{constructor(renderNewLighthouseView){this._renderNewLighthouseView=renderNewLighthouseView;this._newLighthouseItem=createElement('option');this._comboBox=new Toolbar.ToolbarComboBox(this._handleChange.bind(this),ls`Reports`,'lighthouse-report');this._comboBox.setMaxWidth(180);this._comboBox.setMinWidth(140);this._itemByOptionElement=new Map();this._setEmptyState();}
_setEmptyState(){this._comboBox.selectElement().removeChildren();this._comboBox.setEnabled(false);this._newLighthouseItem=createElement('option');this._newLighthouseItem.label=UIString.UIString('(new report)');this._comboBox.selectElement().appendChild(this._newLighthouseItem);this._comboBox.select(this._newLighthouseItem);}
_handleChange(event){const item=this._selectedItem();if(item){item.select();}else{this._renderNewLighthouseView();}}
_selectedItem(){const option=this._comboBox.selectedOption();return this._itemByOptionElement.get(option);}
hasCurrentSelection(){return!!this._selectedItem();}
hasItems(){return this._itemByOptionElement.size>0;}
comboBox(){return this._comboBox;}
prepend(item){const optionEl=item.optionElement();const selectEl=this._comboBox.selectElement();this._itemByOptionElement.set(optionEl,item);selectEl.insertBefore(optionEl,selectEl.firstElementChild);this._comboBox.setEnabled(true);this._comboBox.select(optionEl);item.select();}
clearAll(){for(const elem of this._comboBox.options()){if(elem===this._newLighthouseItem){continue;}
this._itemByOptionElement.get(elem).delete();this._itemByOptionElement.delete(elem);}
this._setEmptyState();}
selectNewReport(){this._comboBox.select(this._newLighthouseItem);}}
class Item{constructor(lighthouseResult,renderReport,showLandingCallback){this._lighthouseResult=lighthouseResult;this._renderReport=renderReport;this._showLandingCallback=showLandingCallback;const url=new ParsedURL.ParsedURL(lighthouseResult.finalUrl);const timestamp=lighthouseResult.fetchTime;this._element=createElement('option');this._element.label=`${new Date(timestamp).toLocaleTimeString()} - ${url.domain()}`;}
select(){this._renderReport();}
optionElement(){return this._element;}
delete(){if(this._element){this._element.remove();}
this._showLandingCallback();}}
var LighthouseReportSelector=Object.freeze({__proto__:null,ReportSelector:ReportSelector,Item:Item});class RadioSetting{constructor(options,setting,description){this._setting=setting;this._options=options;this.element=createElement('div');this.element.title=description;ARIAUtils.setDescription(this.element,description);ARIAUtils.markAsRadioGroup(this.element);this._radioElements=[];for(const option of this._options){const fragment=Fragment.Fragment.build`
        <label $="label" class="lighthouse-radio">
          <input $="input" type="radio" value=${option.value} name=${setting.name}>
          <span class="lighthouse-radio-text">${option.label}</span>
        </label>
      `;this.element.appendChild(fragment.element());if(option.title){Tooltip.Tooltip.install(fragment.$('label'),option.title);}
const radioElement=fragment.$('input');radioElement.addEventListener('change',this._valueChanged.bind(this));this._radioElements.push(radioElement);}
this._ignoreChangeEvents=false;this._selectedIndex=-1;setting.addChangeListener(this._settingChanged,this);this._settingChanged();}
_updateUI(){this._ignoreChangeEvents=true;this._radioElements[this._selectedIndex].checked=true;this._ignoreChangeEvents=false;}
_settingChanged(){const value=this._setting.get();this._selectedIndex=this._options.findIndex(option=>option.value===value);this._updateUI();}
_valueChanged(event){if(this._ignoreChangeEvents){return;}
const selectedRadio=this._radioElements.find(radio=>radio.checked);this._setting.set(selectedRadio.value);}}
var RadioSetting$1=Object.freeze({__proto__:null,RadioSetting:RadioSetting});class StartView extends Widget.Widget{constructor(controller){super();this.registerRequiredCSS('lighthouse/lighthouseStartView.css');this._controller=controller;this._settingsToolbar=new Toolbar.Toolbar('');this._render();}
settingsToolbar(){return this._settingsToolbar;}
_populateRuntimeSettingAsRadio(settingName,label,parentElement){const runtimeSetting=RuntimeSettings.find(item=>item.setting.name===settingName);if(!runtimeSetting||!runtimeSetting.options){throw new Error(`${settingName} is not a setting with options`);}
const control=new RadioSetting(runtimeSetting.options,runtimeSetting.setting,runtimeSetting.description);parentElement.appendChild(control.element);ARIAUtils.setAccessibleName(control.element,label);}
_populateRuntimeSettingAsToolbarCheckbox(settingName,toolbar){const runtimeSetting=RuntimeSettings.find(item=>item.setting.name===settingName);if(!runtimeSetting||!runtimeSetting.title){throw new Error(`${settingName} is not a setting with a title`);}
runtimeSetting.setting.setTitle(runtimeSetting.title);const control=new Toolbar.ToolbarSettingCheckbox(runtimeSetting.setting,runtimeSetting.description);toolbar.appendToolbarItem(control);if(runtimeSetting.learnMore){const link=XLink.XLink.create(runtimeSetting.learnMore,ls`Learn more`,'lighthouse-learn-more');link.style.padding='5px';control.element.appendChild(link);}}
_populateFormControls(fragment){const deviceTypeFormElements=fragment.$('device-type-form-elements');this._populateRuntimeSettingAsRadio('lighthouse.device_type',ls`Device`,deviceTypeFormElements);const categoryFormElements=fragment.$('categories-form-elements');const pluginFormElements=fragment.$('plugins-form-elements');for(const preset of Presets){const formElements=preset.plugin?pluginFormElements:categoryFormElements;preset.setting.setTitle(preset.title);const checkbox=new Toolbar.ToolbarSettingCheckbox(preset.setting);const row=formElements.createChild('div','vbox lighthouse-launcher-row');row.title=preset.description;row.appendChild(checkbox.element);}
ARIAUtils.markAsGroup(categoryFormElements);ARIAUtils.setAccessibleName(categoryFormElements,ls`Categories`);ARIAUtils.markAsGroup(pluginFormElements);ARIAUtils.setAccessibleName(pluginFormElements,ls`Community Plugins (beta)`);}
_render(){this._populateRuntimeSettingAsToolbarCheckbox('lighthouse.clear_storage',this._settingsToolbar);this._populateRuntimeSettingAsToolbarCheckbox('lighthouse.throttling',this._settingsToolbar);this._startButton=UIUtils.createTextButton(ls`Generate report`,()=>this._controller.dispatchEventToListeners(Events.RequestLighthouseStart,UIUtils.elementIsFocusedByKeyboard(this._startButton)),'',true);this.setDefaultFocusedElement(this._startButton);const auditsDescription=ls`Identify and fix common problems that affect your site's performance, accessibility, and user experience.`;const fragment=Fragment.Fragment.build`
      <div class="vbox lighthouse-start-view">
        <header>
          <div class="lighthouse-logo"></div>
          <div class="lighthouse-start-button-container hbox">
            ${this._startButton}
            </div>
          <div $="help-text" class="lighthouse-help-text hidden"></div>
          <div class="lighthouse-start-view-text">
            <span>${auditsDescription}</span>
            ${XLink.XLink.create('https://developers.google.com/web/tools/lighthouse/', ls`Learn more`)}
          </div>
        </header>
        <form>
          <div class="lighthouse-form-categories">
            <div class="lighthouse-form-section">
              <div class="lighthouse-form-section-label">
                ${ls`Categories`}
              </div>
              <div class="lighthouse-form-elements" $="categories-form-elements"></div>
            </div>
            <div class="lighthouse-form-section">
              <div class="lighthouse-form-section-label">
                <div class="lighthouse-icon-label">${ls`Community Plugins(beta)`}</div>
              </div>
              <div class="lighthouse-form-elements" $="plugins-form-elements"></div>
            </div>
          </div>
          <div class="lighthouse-form-section">
            <div class="lighthouse-form-section-label">
              ${ls`Device`}
            </div>
            <div class="lighthouse-form-elements" $="device-type-form-elements"></div>
          </div>
        </form>
      </div>
    `;this._helpText=fragment.$('help-text');this._populateFormControls(fragment);this.contentElement.appendChild(fragment.element());this.contentElement.style.overflow='auto';}
onResize(){const useNarrowLayout=this.contentElement.offsetWidth<560;const startViewEl=this.contentElement.querySelector('.lighthouse-start-view');startViewEl.classList.toggle('hbox',!useNarrowLayout);startViewEl.classList.toggle('vbox',useNarrowLayout);}
focusStartButton(){this._startButton.focus();}
setStartButtonEnabled(isEnabled){if(this._helpText){this._helpText.classList.toggle('hidden',isEnabled);}
if(this._startButton){this._startButton.disabled=!isEnabled;}}
setUnauditableExplanation(text){if(this._helpText){this._helpText.textContent=text;}}}
var LighthouseStartView=Object.freeze({__proto__:null,StartView:StartView});class StatusView{constructor(controller){this._controller=controller;this._statusView=null;this._statusHeader=null;this._progressWrapper=null;this._progressBar=null;this._statusText=null;this._cancelButton=null;this._inspectedURL='';this._textChangedAt=0;this._fastFactsQueued=FastFacts.slice();this._currentPhase=null;this._scheduledTextChangeTimeout=null;this._scheduledFastFactTimeout=null;this._dialog=new Dialog.Dialog();this._dialog.setDimmed(true);this._dialog.setCloseOnEscape(false);this._dialog.setOutsideClickCallback(event=>event.consume(true));this._render();}
_render(){const dialogRoot=Utils.createShadowRootWithCoreStyles(this._dialog.contentElement,'lighthouse/lighthouseDialog.css');const lighthouseViewElement=dialogRoot.createChild('div','lighthouse-view vbox');const cancelButton=UIUtils.createTextButton(ls`Cancel`,this._cancel.bind(this));const fragment=Fragment.Fragment.build`
      <div class="lighthouse-view vbox">
        <h2 $="status-header">Auditing your web page…</h2>
        <div class="lighthouse-status vbox" $="status-view">
          <div class="lighthouse-progress-wrapper" $="progress-wrapper">
            <div class="lighthouse-progress-bar" $="progress-bar"></div>
          </div>
          <div class="lighthouse-status-text" $="status-text"></div>
        </div>
        ${cancelButton}
      </div>
    `;lighthouseViewElement.appendChild(fragment.element());this._statusView=fragment.$('status-view');this._statusHeader=fragment.$('status-header');this._progressWrapper=fragment.$('progress-wrapper');this._progressBar=fragment.$('progress-bar');this._statusText=fragment.$('status-text');ARIAUtils.markAsProgressBar(this._progressBar,0,StatusPhases.length-1);this._cancelButton=cancelButton;ARIAUtils.markAsStatus(this._statusText);this._dialog.setDefaultFocusedElement(cancelButton);this._dialog.setSizeBehavior(GlassPane.SizeBehavior.SetExactWidthMaxHeight);this._dialog.setMaxContentSize(new Geometry.Size(500,400));}
_reset(){this._resetProgressBarClasses();clearTimeout(this._scheduledFastFactTimeout);this._textChangedAt=0;this._fastFactsQueued=FastFacts.slice();this._currentPhase=null;this._scheduledTextChangeTimeout=null;this._scheduledFastFactTimeout=null;}
show(dialogRenderElement){this._reset();this.updateStatus(ls`Loading…`);const parsedURL=ParsedURL.ParsedURL.fromString(this._inspectedURL);const pageHost=parsedURL&&parsedURL.host;const statusHeader=pageHost?ls`Auditing ${pageHost}`:ls`Auditing your web page`;this._renderStatusHeader(statusHeader);this._dialog.show(dialogRenderElement);}
_renderStatusHeader(statusHeader){this._statusHeader.textContent=`${statusHeader}…`;}
hide(){if(this._dialog.isShowing()){this._dialog.hide();}}
setInspectedURL(url=''){this._inspectedURL=url;}
updateStatus(message){if(!message||!this._statusText){return;}
if(message.startsWith('Cancel')){this._commitTextChange(UIString.UIString('Cancelling…'));clearTimeout(this._scheduledFastFactTimeout);return;}
const nextPhase=this._getPhaseForMessage(message);const nextPhaseIndex=StatusPhases.indexOf(nextPhase);const currentPhaseIndex=StatusPhases.indexOf(this._currentPhase);if(!nextPhase&&!this._currentPhase){this._commitTextChange(UIString.UIString('Lighthouse is warming up…'));clearTimeout(this._scheduledFastFactTimeout);}else if(nextPhase&&(!this._currentPhase||currentPhaseIndex<nextPhaseIndex)){this._currentPhase=nextPhase;const text=this._getMessageForPhase(nextPhase);this._scheduleTextChange(text);this._scheduleFastFactCheck();this._resetProgressBarClasses();this._progressBar.classList.add(nextPhase.progressBarClass);ARIAUtils.setProgressBarValue(this._progressBar,nextPhaseIndex,text);}}
_cancel(){this._controller.dispatchEventToListeners(Events.RequestLighthouseCancel);}
_getMessageForPhase(phase){if(phase.message){return phase.message;}
const deviceType=RuntimeSettings.find(item=>item.setting.name==='lighthouse.device_type').setting.get();const throttling=RuntimeSettings.find(item=>item.setting.name==='lighthouse.throttling').setting.get();const match=LoadingMessages.find(item=>{return item.deviceType===deviceType&&item.throttling===throttling;});return match?match.message:ls`Lighthouse is loading your page`;}
_getPhaseForMessage(message){return StatusPhases.find(phase=>message.startsWith(phase.statusMessagePrefix));}
_resetProgressBarClasses(){if(!this._progressBar){return;}
this._progressBar.className='lighthouse-progress-bar';}
_scheduleFastFactCheck(){if(!this._currentPhase||this._scheduledFastFactTimeout){return;}
this._scheduledFastFactTimeout=setTimeout(()=>{this._updateFastFactIfNecessary();this._scheduledFastFactTimeout=null;this._scheduleFastFactCheck();},100);}
_updateFastFactIfNecessary(){const now=performance.now();if(now-this._textChangedAt<fastFactRotationInterval){return;}
if(!this._fastFactsQueued.length){return;}
const fastFactIndex=Math.floor(Math.random()*this._fastFactsQueued.length);this._scheduleTextChange(ls`\ud83d\udca1 ${this._fastFactsQueued[fastFactIndex]}`);this._fastFactsQueued.splice(fastFactIndex,1);}
_commitTextChange(text){if(!this._statusText){return;}
this._textChangedAt=performance.now();this._statusText.textContent=text;}
_scheduleTextChange(text){if(this._scheduledTextChangeTimeout){clearTimeout(this._scheduledTextChangeTimeout);}
const msSinceLastChange=performance.now()-this._textChangedAt;const msToTextChange=minimumTextVisibilityDuration-msSinceLastChange;this._scheduledTextChangeTimeout=setTimeout(()=>{this._commitTextChange(text);},Math.max(msToTextChange,0));}
renderBugReport(err){console.error(err);clearTimeout(this._scheduledFastFactTimeout);clearTimeout(this._scheduledTextChangeTimeout);this._resetProgressBarClasses();this._progressBar.classList.add('errored');this._commitTextChange('');this._statusText.createChild('p').createTextChild(UIString.UIString('Ah, sorry! We ran into an error.'));if(KnownBugPatterns.some(pattern=>pattern.test(err.message))){const message=UIString.UIString('Try to navigate to the URL in a fresh Chrome profile without any other tabs or extensions open and try again.');this._statusText.createChild('p').createTextChild(message);}else{this._renderBugReportBody(err,this._inspectedURL);}}
renderText(statusHeader,text){this._renderStatusHeader(statusHeader);this._commitTextChange(text);}
toggleCancelButton(show){this._cancelButton.style.visibility=show?'visible':'hidden';}
_renderBugReportBody(err,auditURL){const issueBody=`
${err.message}
\`\`\`
Channel: DevTools
Initial URL: ${auditURL}
Chrome Version: ${navigator.userAgent.match(/Chrome\/(\S+)/)[1]}
Stack Trace: ${err.stack}
\`\`\`
`;this._statusText.createChild('p').createTextChild(ls`If this issue is reproducible, please report it at the Lighthouse GitHub repo.`);this._statusText.createChild('code','monospace').createTextChild(issueBody.trim());}}
const fastFactRotationInterval=6000;const minimumTextVisibilityDuration=3000;const KnownBugPatterns=[/PARSING_PROBLEM/,/DOCUMENT_REQUEST/,/READ_FAILED/,/TRACING_ALREADY_STARTED/,/^You must provide a url to the runner/,/^You probably have multiple tabs open/,];const StatusPhases=[{id:'loading',progressBarClass:'loading',statusMessagePrefix:'Loading page',},{id:'gathering',progressBarClass:'gathering',message:ls`Lighthouse is gathering information about the page to compute your score.`,statusMessagePrefix:'Gathering',},{id:'auditing',progressBarClass:'auditing',message:ls`Almost there! Lighthouse is now generating your report.`,statusMessagePrefix:'Auditing',}];const LoadingMessages=[{deviceType:'mobile',throttling:'on',message:ls`Lighthouse is loading your page with throttling to measure performance on a mobile device on 3G.`,},{deviceType:'desktop',throttling:'on',message:ls`Lighthouse is loading your page with throttling to measure performance on a slow desktop on 3G.`,},{deviceType:'mobile',throttling:'off',message:ls`Lighthouse is loading your page with mobile emulation.`,},{deviceType:'desktop',throttling:'off',message:ls`Lighthouse is loading your page.`,},];const FastFacts=[ls`1MB takes a minimum of 5 seconds to download on a typical 3G connection [Source: WebPageTest and DevTools 3G definition].`,ls`Rebuilding Pinterest pages for performance increased conversion rates by 15% [Source: WPO Stats]`,ls`By reducing the response size of JSON needed for displaying comments, Instagram saw increased impressions [Source: WPO Stats]`,ls`Walmart saw a 1% increase in revenue for every 100ms improvement in page load [Source: WPO Stats]`,ls`If a site takes >1 second to become interactive, users lose attention, and their perception of completing the page task is broken [Source: Google Developers Blog]`,ls`75% of global mobile users in 2016 were on 2G or 3G [Source: GSMA Mobile]`,ls`The average user device costs less than 200 USD. [Source: International Data Corporation]`,ls`19 seconds is the average time a mobile web page takes to load on a 3G connection [Source: Google DoubleClick blog]`,ls`70% of mobile pages take nearly 7 seconds for the visual content above the fold to display on the screen. [Source: Think with Google]`,ls`As page load time increases from one second to seven seconds, the probability of a mobile site visitor bouncing increases 113%. [Source: Think with Google]`,ls`As the number of elements on a page increases from 400 to 6,000, the probability of conversion drops 95%. [Source: Think with Google]`,ls`70% of mobile pages weigh over 1MB, 36% over 2MB, and 12% over 4MB. [Source: Think with Google]`,ls`Lighthouse only simulates mobile performance; to measure performance on a real device, try WebPageTest.org [Source: Lighthouse team]`,];var LighthouseStatusView=Object.freeze({__proto__:null,StatusView:StatusView,fastFactRotationInterval:fastFactRotationInterval,minimumTextVisibilityDuration:minimumTextVisibilityDuration,StatusPhases:StatusPhases});class LighthousePanel extends Panel.Panel{constructor(){super('lighthouse');this.registerRequiredCSS('third_party/lighthouse/report-assets/report.css');this.registerRequiredCSS('lighthouse/lighthousePanel.css');this._protocolService=new ProtocolService();this._controller=new LighthouseController(this._protocolService);this._startView=new StartView(this._controller);this._statusView=new StatusView(this._controller);this._unauditableExplanation=null;this._cachedRenderedReports=new Map();this._dropTarget=new DropTarget.DropTarget(this.contentElement,[DropTarget.Type.File],UIString.UIString('Drop Lighthouse JSON here'),this._handleDrop.bind(this));this._controller.addEventListener(Events.PageAuditabilityChanged,this._refreshStartAuditUI.bind(this));this._controller.addEventListener(Events.AuditProgressChanged,this._refreshStatusUI.bind(this));this._controller.addEventListener(Events.RequestLighthouseStart,event=>{this._startLighthouse(event);});this._controller.addEventListener(Events.RequestLighthouseCancel,event=>{this._cancelLighthouse();});this._renderToolbar();this._auditResultsElement=this.contentElement.createChild('div','lighthouse-results-container');this._renderStartView();this._controller.recomputePageAuditability();}
_refreshStartAuditUI(evt){if(this._isLHAttached){return;}
this._unauditableExplanation=evt.data.helpText;this._startView.setUnauditableExplanation(evt.data.helpText);this._startView.setStartButtonEnabled(!evt.data.helpText);}
_refreshStatusUI(evt){this._statusView.updateStatus(evt.data.message);}
_refreshToolbarUI(){this._clearButton.setEnabled(this._reportSelector.hasItems());}
_clearAll(){this._reportSelector.clearAll();this._renderStartView();this._refreshToolbarUI();}
_renderToolbar(){const lighthouseToolbarContainer=this.element.createChild('div','lighthouse-toolbar-container');const toolbar=new Toolbar.Toolbar('',lighthouseToolbarContainer);this._newButton=new Toolbar.ToolbarButton(UIString.UIString('Perform an audit…'),'largeicon-add');toolbar.appendToolbarItem(this._newButton);this._newButton.addEventListener(Toolbar.ToolbarButton.Events.Click,this._renderStartView.bind(this));toolbar.appendSeparator();this._reportSelector=new ReportSelector(()=>this._renderStartView());toolbar.appendToolbarItem(this._reportSelector.comboBox());this._clearButton=new Toolbar.ToolbarButton(UIString.UIString('Clear all'),'largeicon-clear');toolbar.appendToolbarItem(this._clearButton);this._clearButton.addEventListener(Toolbar.ToolbarButton.Events.Click,this._clearAll.bind(this));this._settingsPane=new Widget.HBox();this._settingsPane.show(this.contentElement);this._settingsPane.element.classList.add('lighthouse-settings-pane');this._settingsPane.element.appendChild(this._startView.settingsToolbar().element);this._showSettingsPaneSetting=Settings.Settings.instance().createSetting('lighthouseShowSettingsToolbar',false);this._rightToolbar=new Toolbar.Toolbar('',lighthouseToolbarContainer);this._rightToolbar.appendSeparator();this._rightToolbar.appendToolbarItem(new Toolbar.ToolbarSettingToggle(this._showSettingsPaneSetting,'largeicon-settings-gear',ls`Lighthouse settings`));this._showSettingsPaneSetting.addChangeListener(this._updateSettingsPaneVisibility.bind(this));this._updateSettingsPaneVisibility();this._refreshToolbarUI();}
_updateSettingsPaneVisibility(){this._settingsPane.element.classList.toggle('hidden',!this._showSettingsPaneSetting.get());}
_toggleSettingsDisplay(show){this._rightToolbar.element.classList.toggle('hidden',!show);this._settingsPane.element.classList.toggle('hidden',!show);this._updateSettingsPaneVisibility();}
_renderStartView(){this._auditResultsElement.removeChildren();this._statusView.hide();this._reportSelector.selectNewReport();this.contentElement.classList.toggle('in-progress',false);this._startView.show(this.contentElement);this._toggleSettingsDisplay(true);this._startView.setUnauditableExplanation(this._unauditableExplanation);this._startView.setStartButtonEnabled(!this._unauditableExplanation);if(!this._unauditableExplanation){this._startView.focusStartButton();}
this._newButton.setEnabled(false);this._refreshToolbarUI();this.setDefaultFocusedChild(this._startView);}
_renderStatusView(inspectedURL){this.contentElement.classList.toggle('in-progress',true);this._statusView.setInspectedURL(inspectedURL);this._statusView.show(this.contentElement);}
_beforePrint(){this._statusView.show(this.contentElement);this._statusView.toggleCancelButton(false);this._statusView.renderText(ls`Printing`,ls`The print popup window is open. Please close it to continue.`);}
_afterPrint(){this._statusView.hide();this._statusView.toggleCancelButton(true);}
_renderReport(lighthouseResult,artifacts){this._toggleSettingsDisplay(false);this.contentElement.classList.toggle('in-progress',false);this._startView.hideWidget();this._statusView.hide();this._auditResultsElement.removeChildren();this._newButton.setEnabled(true);this._refreshToolbarUI();const cachedRenderedReport=this._cachedRenderedReports.get(lighthouseResult);if(cachedRenderedReport){this._auditResultsElement.appendChild(cachedRenderedReport);return;}
const reportContainer=this._auditResultsElement.createChild('div','lh-vars lh-root lh-devtools');const dom=new DOM((this._auditResultsElement.ownerDocument));const renderer=new LighthouseReportRenderer(dom);const templatesHTML=self.Runtime.cachedResources['third_party/lighthouse/report-assets/templates.html'];const templatesDOM=new DOMParser().parseFromString(templatesHTML,'text/html');if(!templatesDOM){return;}
renderer.setTemplateContext(templatesDOM);const el=renderer.renderReport(lighthouseResult,reportContainer);LighthouseReportRenderer.addViewTraceButton(el,artifacts);this._waitForMainTargetLoad().then(()=>{LighthouseReportRenderer.linkifyNodeDetails(el);LighthouseReportRenderer.linkifySourceLocationDetails(el);});LighthouseReportRenderer.handleDarkMode(el);const features=new LighthouseReportUIFeatures(dom);features.setBeforePrint(this._beforePrint.bind(this));features.setAfterPrint(this._afterPrint.bind(this));features.setTemplateContext(templatesDOM);features.initFeatures(lighthouseResult);this._cachedRenderedReports.set(lighthouseResult,reportContainer);}
_waitForMainTargetLoad(){const mainTarget=SDKModel.TargetManager.instance().mainTarget();const resourceTreeModel=mainTarget.model(ResourceTreeModel.ResourceTreeModel);return resourceTreeModel.once(ResourceTreeModel.Events.Load);}
_buildReportUI(lighthouseResult,artifacts){if(lighthouseResult===null){return;}
const optionElement=new Item(lighthouseResult,()=>this._renderReport(lighthouseResult,artifacts),this._renderStartView.bind(this));this._reportSelector.prepend(optionElement);this._refreshToolbarUI();this._renderReport(lighthouseResult);}
_handleDrop(dataTransfer){const items=dataTransfer.items;if(!items.length){return;}
const item=items[0];if(item.kind==='file'){const entry=items[0].webkitGetAsEntry();if(!entry.isFile){return;}
entry.file(file=>{const reader=new FileReader();reader.onload=()=>this._loadedFromFile((reader.result));reader.readAsText(file);});}}
_loadedFromFile(report){const data=JSON.parse(report);if(!data['lighthouseVersion']){return;}
this._buildReportUI((data));}
async _startLighthouse(event){userMetrics.actionTaken(Host.UserMetrics.Action.LighthouseStarted);try{const inspectedURL=await this._controller.getInspectedURL({force:true});const categoryIDs=this._controller.getCategoryIDs();const flags=this._controller.getFlags();await this._setupEmulationAndProtocolConnection();this._renderStatusView(inspectedURL);const lighthouseResponse=await this._protocolService.startLighthouse(inspectedURL,categoryIDs,flags);if(lighthouseResponse&&lighthouseResponse.fatal){const error=new Error(lighthouseResponse.message);error.stack=lighthouseResponse.stack;throw error;}
if(!lighthouseResponse){throw new Error('Auditing failed to produce a result');}
userMetrics.actionTaken(Host.UserMetrics.Action.LighthouseFinished);await this._resetEmulationAndProtocolConnection();this._buildReportUI(lighthouseResponse.lhr,lighthouseResponse.artifacts);this._newButton.element.focus();const keyboardInitiated=(event.data);if(keyboardInitiated){UIUtils.markAsFocusedByKeyboard(this._newButton.element);}}catch(err){await this._resetEmulationAndProtocolConnection();if(err instanceof Error){this._statusView.renderBugReport(err);}}}
async _cancelLighthouse(){this._statusView.updateStatus(ls`Cancelling`);await this._resetEmulationAndProtocolConnection();this._renderStartView();}
async _setupEmulationAndProtocolConnection(){const flags=this._controller.getFlags();const emulationModel=self.singleton(DeviceModeModel.DeviceModeModel);this._stateBefore={emulation:{enabled:emulationModel.enabledSetting().get(),outlineEnabled:emulationModel.deviceOutlineSetting().get(),toolbarControlsEnabled:emulationModel.toolbarControlsEnabledSetting().get()},network:{conditions:NetworkManager.MultitargetNetworkManager.instance().networkConditions()}};emulationModel.toolbarControlsEnabledSetting().set(false);if(flags.emulatedFormFactor==='desktop'){emulationModel.enabledSetting().set(false);emulationModel.emulate(DeviceModeModel.Type.None,null,null);}else if(flags.emulatedFormFactor==='mobile'){emulationModel.enabledSetting().set(true);emulationModel.deviceOutlineSetting().set(true);for(const device of EmulatedDevices.EmulatedDevicesList.instance().standard()){if(device.title==='Moto G4'){emulationModel.emulate(DeviceModeModel.Type.Device,device,device.modes[0],1);}}}
await this._protocolService.attach();this._isLHAttached=true;}
async _resetEmulationAndProtocolConnection(){if(!this._isLHAttached){return;}
this._isLHAttached=false;await this._protocolService.detach();if(this._stateBefore){const emulationModel=self.singleton(DeviceModeModel.DeviceModeModel);emulationModel.enabledSetting().set(this._stateBefore.emulation.enabled);emulationModel.deviceOutlineSetting().set(this._stateBefore.emulation.outlineEnabled);emulationModel.toolbarControlsEnabledSetting().set(this._stateBefore.emulation.toolbarControlsEnabled);NetworkManager.MultitargetNetworkManager.instance().setNetworkConditions(this._stateBefore.network.conditions);delete this._stateBefore;}
InspectedPagePlaceholder.instance().update(true);const resourceTreeModel=SDKModel.TargetManager.instance().mainTarget().model(ResourceTreeModel.ResourceTreeModel);const inspectedURL=await this._controller.getInspectedURL();await resourceTreeModel.navigate(inspectedURL);}}
var LighthousePanel$1=Object.freeze({__proto__:null,LighthousePanel:LighthousePanel});export{LighthouseController$1 as LighthouseController,LighthousePanel$1 as LighthousePanel,LighthouseProtocolService,LighthouseReportRenderer$1 as LighthouseReportRenderer,LighthouseReportSelector,LighthouseStartView,LighthouseStatusView,RadioSetting$1 as RadioSetting};