coach-core
Advanced tools
Comparing version 7.1.1 to 7.1.2
@@ -2083,3 +2083,3 @@ (function() { | ||
'url': document.URL, | ||
'version': "7.1.1" | ||
'version': "7.1.2" | ||
}; | ||
@@ -2086,0 +2086,0 @@ })(util); |
@@ -1,1 +0,1 @@ | ||
(function(){if(typeof window!=="undefined"){"use strict";const e={getAbsoluteURL:function(e){const t=window.document.createElement("a");t.href=e;return t.href},getHostname:function(e){const t=window.document.createElement("a");t.href=e;return t.hostname},exists:function(e,t){return t.some((function(t){return t===e}))},caseInsensitiveAttributeValueFilter:function(e,t){return function(n){const o=n.getAttribute(e)||"";if(o.toLowerCase()===t.toLowerCase()){return n}return undefined}},isHTTP2:function(){const t=e.getConnectionType().toLowerCase();return t==="h2"||t.startsWith("spdy")},isHTTP3:function(){const t=e.getConnectionType().toLowerCase();return t.startsWith("h3")},getConnectionType:function(){if(window.performance.getEntriesByType("navigation")&&window.performance.getEntriesByType("navigation")[0]&&window.performance.getEntriesByType("navigation")[0].nextHopProtocol){return window.performance.getEntriesByType("navigation")[0].nextHopProtocol}else if(window.performance&&window.performance.getEntriesByType&&window.performance.getEntriesByType("resource")){const t=window.performance.getEntriesByType("resource");if(t.length>1&&t[0].nextHopProtocol){const n=document.domain;for(let o=0,r=t.length;o<r;o++){if(n===e.getHostname(t[o].name)){return t[o].nextHopProtocol}}}}return"unknown"},getSynchJSFiles:function(t){const n=Array.prototype.slice.call(t.getElementsByTagName("script"));return n.filter((function(e){return!e.async&&e.src&&!e.defer})).map((function(t){return e.getAbsoluteURL(t.src)}))},getAsynchJSFiles:function(t){const n=Array.prototype.slice.call(t.getElementsByTagName("script"));return n.filter((function(e){return e.async&&e.src})).map((function(t){return e.getAbsoluteURL(t.src)}))},getResourceHintsHrefs:function(e){const t=Array.prototype.slice.call(window.document.head.getElementsByTagName("link"));return t.filter((function(t){return t.rel===e})).map((function(e){return e.href}))},getCSSFiles:function(t){const n=Array.prototype.slice.call(t.getElementsByTagName("link"));return n.filter((function(e){return e.rel==="stylesheet"&&!e.href.startsWith("data:")})).map((function(t){return e.getAbsoluteURL(t.href)}))},plural:function(e,t){if(e>1){t+="s"}return`${e} ${t}`},getTransferSize:function(e){const t=window.performance.getEntriesByName(e,"resource");if(t.length===1&&typeof t[0].transferSize==="number"){return t[0].transferSize}else{return 0}},ms(e){if(e<1e3){return e+" ms"}else{return Number(e/1e3).toFixed(3)+" s"}}};return(function(e){var t={},n={};var o={},r={};try{o["amp"]=(function(){"use strict";const e=[];const t=document.getElementsByTagName("html")[0];let n=100;if(t&&t.getAttribute("amp-version")||window.AMP){n=0}return{id:"amp",title:"Avoid using AMP",description:"AMP was one of Google attempts to strengthen its monopoly in the Interente advertising market. You can read more about it here: https://storage.courtlistener.com/recap/gov.uscourts.nysd.564903/gov.uscourts.nysd.564903.152.0_1.pdf Using AMP you also share private user information with Google that your user hasn't agreed on sharing.",advice:n===0?"The page is using AMP, that makes you share private user information with Google.":"",score:n,weight:10,offending:e,tags:["bestpractice"]}})()}catch(e){r["amp"]=e.message}try{o["charset"]=(function(){"use strict";let e=100;let t="";const n=document.characterSet;if(n===null){t="The page is missing a character set. If you use Chrome/Firefox we know you are missing it, if you use another browser, it could be an implementation problem.";e=0}else if(n!=="UTF-8"){t="You are not using charset UTF-8?";e=50}return{id:"charset",title:"Declare a charset in your document",description:"The Unicode Standard (UTF-8) covers (almost) all the characters, punctuations, and symbols in the world. Please use that.",advice:t,score:e,weight:2,offending:[],tags:["bestpractice"]}})()}catch(e){r["charset"]=e.message}try{o["cumulativeLayoutShift"]=(function(){"use strict";const e=[];let t="There is no Layout Shift on the page.";let n=0;let o=0;const r=PerformanceObserver.supportedEntryTypes;if(!r||r.indexOf("layout-shift")===-1){t="Layout Shift is not supported in this browser"}else{let i=0;let s=Number.NEGATIVE_INFINITY;let a=Number.NEGATIVE_INFINITY;const c=new PerformanceObserver((()=>{}));c.observe({type:"layout-shift",buffered:true});const u=c.takeRecords();for(let l of u){if(l.hadRecentInput){continue}if(l.startTime-s>5e3||l.startTime-a>1e3){s=l.startTime;i=0}a=l.startTime;i+=l.value;o=Math.max(o,i)}if(o<=.1){n=100}else if(o>.25){n=0;t=`You have a poor cumulative layout shift score (${o.toFixed(4)}). It is in the Google Web Vitals poor range, with a shift higher than 0.25. You should manually check the filmstrip or video and check if it will affect the user.`}else{n=50;t=`You have a cumulative layout shift score (${o.toFixed(4)}) that needs improvements. It is in the Google Web Vitals needs improvement range, shift higher than 0.1. You should manually check the filmstrip or video and check if it will affect the user.`}}return{id:"cumulativeLayoutShift",title:"Cumulative Layout Shift",description:"Cumulative Layout Shift measures the sum total of all individual layout shift scores for unexpected layout shift that occur. The metric is measuring visual stability by quantify how often users experience unexpected layout shifts. It is one of Google Web Vitals.",advice:t,score:n,weight:8,offending:e,tags:["bestpractice"]}})()}catch(e){r["cumulativeLayoutShift"]=e.message}try{o["doctype"]=(function(){"use strict";let e=100;let t="";const n=document.doctype;if(n===null){t="The page is missing a doctype. Please use <!DOCTYPE html>.";e=0}else if(!(n.name.toLowerCase()==="html"&&(n.systemId===""||n.systemId.toLowerCase()==="about:legacy-compat"))){t="Just do yourself a favor and use the HTML5 doctype declaration: <!DOCTYPE html>";e=25}return{id:"doctype",title:"Declare a doctype in your document",description:"The <!DOCTYPE> declaration is not an HTML tag; it is an instruction to the web browser about what version of HTML the page is written in.",advice:t,score:e,weight:2,offending:[],tags:["bestpractice"]}})()}catch(e){r["doctype"]=e.message}try{o["language"]=(function(){"use strict";const e=document.getElementsByTagName("html");const t=e[0].getAttribute("lang");let n=100;let o="";if(e.length>0){if(t===null){n=0;o='The page is missing a language definition in the HTML tag. Define it with <html lang="YOUR_LANGUAGE_CODE">'}}else{n=0;o="What! The page is missing the HTML tag!"}return{id:"language",title:"Declare the language code for your document",description:"According to the W3C recommendation you should declare the primary language for each Web page with the lang attribute inside the <html> tag https://www.w3.org/International/questions/qa-html-language-declarations#basics.",advice:o,score:n,weight:3,offending:[],tags:["bestpractice"]}})()}catch(e){r["language"]=e.message}try{o["metaDescription"]=(function(e){"use strict";const t=155;let n=100;let o="";let r=Array.prototype.slice.call(document.querySelectorAll("meta[name][content]"));r=r.filter(e.caseInsensitiveAttributeValueFilter("name","description"));const i=r.length>0?r[0].getAttribute("content"):"";if(i.length===0){o="The page is missing a meta description.";n=0}else if(i.length>t){o="The meta description is too long. It has "+i.length+" characters, the recommended max is "+t;n=50}return{id:"metaDescription",title:"Meta description",description:"Use a page description to make the page more relevant to search engines.",advice:o,score:n,weight:5,offending:[],tags:["bestpractice"]}})(e)}catch(e){r["metaDescription"]=e.message}try{o["optimizely"]=(function(e){"use strict";const t=e.getSynchJSFiles(document.head);const n=[];let o=100;let r="";t.forEach((function(t){if(e.getHostname(t)==="cdn.optimizely.com"){n.push(t);o=0;r="The page is using Optimizely. Use it with care because it hurts your performance. Only turn it on (= load the JavaScript) when you run your A/B tests. Then when you are finished make sure to turn it off."}}));return{id:"optimizely",title:"Only use Optimizely when you need it",description:"Use Optimizely with care because it hurts your performance since JavaScript is loaded synchronously inside of the head tag, making the first paint happen later. Only turn on Optimzely (= load the javascript) when you run your A/B tests.",advice:r,score:o,weight:2,offending:n,tags:["bestpractice"]}})(e)}catch(e){r["optimizely"]=e.message}try{o["pageTitle"]=(function(){"use strict";const e=60;const t=document.title;let n=100;let o="";if(t.length===0){o="The page is missing a title.";n=0}else if(t.length>e){o="The title is too long by "+(t.length-e)+" characters. The recommended max is "+e;n=50}return{id:"pageTitle",title:"Page title",description:"Use a title to make the page more relevant to search engines.",advice:o,score:n,weight:5,offending:[],tags:["bestpractice"]}})()}catch(e){r["pageTitle"]=e.message}try{o["spdy"]=(function(){"use strict";const t=e.getConnectionType();let n=100;let o="";if(t.indexOf("spdy")!==-1){n=0;o="The page is using SPDY. Chrome dropped support for SPDY in Chrome 51. Change to HTTP/2 asap."}return{id:"spdy",title:"EOL for SPDY in Chrome",description:"Chrome dropped supports for SPDY in Chrome 51, upgrade to HTTP/2 as soon as possible. The page has more users (browsers) supporting HTTP/2 than supports SPDY.",advice:o,score:n,weight:1,offending:[],tags:["bestpractice"]}})()}catch(e){r["spdy"]=e.message}try{o["url"]=(function(){"use strict";const e=document.URL;let t=100;let n="";if(e.indexOf("?")>-1&&e.indexOf("jsessionid")>e.indexOf("?")){t=0;n="The page has the session id for the user as a parameter, please change so the session handling is done only with cookies. "}var o=(e.match(/&/g)||[]).length;if(o>1){t-=50;n+="The page is using more than two request parameters. You should really rethink and try to minimize the number of parameters. "}if(e.length>100){t-=10;n+="The URL is "+e.length+" characters long. Try to make it less than 100 characters. "}if(e.indexOf(" ")>-1||e.indexOf("%20")>-1){t-=10;n+="Could the developer or the CMS be on Windows? Avoid using spaces in the URLs, use hyphens or underscores. "}return{id:"url",title:"Have a good URL format",description:"A clean URL is good for the user and for SEO. Make them human readable, avoid too long URLs, spaces in the URL, too many request parameters, and never ever have the session id in your URL.",advice:n,score:t<0?0:t,weight:2,offending:[],tags:["bestpractice"]}})()}catch(e){r["url"]=e.message}t["bestpractice"]={adviceList:o};if(Object.keys(r).length>0){n["bestpractice"]=r}var i={},s={};try{i["amp"]=(function(){"use strict";const e=document.getElementsByTagName("html")[0];if(e&&e.getAttribute("amp-version")||window.AMP){return e.getAttribute("amp-version")||true}else{return false}})()}catch(e){s["amp"]=e.message}try{i["browser"]=(function(){"use strict";const{userAgent:userAgent}=navigator;if(userAgent.includes("Firefox/")){return`Firefox ${userAgent.split("Firefox/")[1]}`}else if(userAgent.includes("Edg/")){return`Edge ${userAgent.split("Edg/")[1]}`}else if(userAgent.includes("Chrome/")){return`Chrome ${userAgent.match(/(Chrome)\/(\S+)/)[2]}`}else if(userAgent.includes("Safari/")){return`Safari ${userAgent.match(/(Version)\/(\S+)/)[2]}`}else return"Unknown"})()}catch(e){s["browser"]=e.message}try{i["connectionType"]=(function(e){"use strict";return e.getConnectionType()})(e)}catch(e){s["connectionType"]=e.message}try{i["documentHeight"]=(function(){"use strict";return Math.max(document.body.scrollHeight,document.body.offsetHeight,document.documentElement.clientHeight,document.documentElement.scrollHeight,document.documentElement.offsetHeight)})()}catch(e){s["documentHeight"]=e.message}try{i["documentTitle"]=(function(){"use strict";return document.title})()}catch(e){s["documentTitle"]=e.message}try{i["documentWidth"]=(function(){"use strict";return Math.max(document.body.scrollWidth,document.body.offsetWidth,document.documentElement.clientWidth,document.documentElement.scrollWidth,document.documentElement.offsetWidth)})()}catch(e){s["documentWidth"]=e.message}try{i["domDepth"]=(function(){"use strict";function e(e){const n=e.getElementsByTagName("*");let o=n.length;let r=0;let i=0;while(o--){let s=t(n[o]);if(s>i){i=s}r+=s}const a=r/n.length;return{avg:a,max:i}}function t(e){let t=0;if(e.parentNode){while(e=e.parentNode){t++}}return t}const n=e(document);return{avg:Math.round(n.avg),max:n.max}})()}catch(e){s["domDepth"]=e.message}try{i["domElements"]=(function(){"use strict";return document.getElementsByTagName("*").length})()}catch(e){s["domElements"]=e.message}try{i["generator"]=(function(){"use strict";const e=document.querySelector('meta[name="generator"]');if(e){return e.getAttribute("content")}})()}catch(e){s["generator"]=e.message}try{i["head"]=(function(e){"use strict";return{jssync:e.getSynchJSFiles(document.head),jsasync:e.getAsynchJSFiles(document.head),css:e.getCSSFiles(document.head)}})(e)}catch(e){s["head"]=e.message}try{i["iframes"]=(function(){"use strict";return document.getElementsByTagName("iframe").length})()}catch(e){s["iframes"]=e.message}try{i["localStorageSize"]=(function(){"use strict";function e(e){if(e){const t=e.length||Object.keys(e).length;let n=0;for(let o=0;o<t;o++){const r=e.key(o);const i=e.getItem(r);n+=r.length+i.length}return n}else{return 0}}return e(window.localStorage)})()}catch(e){s["localStorageSize"]=e.message}try{i["metaDescription"]=(function(){"use strict";const e=document.querySelector('meta[name="description"]');const t=document.querySelector('meta[property="og:description"]');if(e){return e.getAttribute("content")}else if(t){return t.getAttribute("content")}else{return""}})()}catch(e){s["metaDescription"]=e.message}try{i["networkConnectionType"]=(function(){"use strict";if(window.navigator.connection){return window.navigator.connection.effectiveType}else{return"unknown"}})()}catch(e){s["networkConnectionType"]=e.message}try{i["resourceHints"]=(function(e){"use strict";return{"dns-prefetch":e.getResourceHintsHrefs("dns-prefetch"),preconnect:e.getResourceHintsHrefs("preconnect"),prefetch:e.getResourceHintsHrefs("prefetch"),prerender:e.getResourceHintsHrefs("prerender")}})(e)}catch(e){s["resourceHints"]=e.message}try{i["responsive"]=(function(){"use strict";let e=true;const t=document.body.scrollWidth;const n=window.innerWidth;const o=document.body.children;if(t>n){e=false}for(var r in o){if(o[r].scrollWidth>n){e=false}}return e})()}catch(e){s["responsive"]=e.message}try{i["scripts"]=(function(){"use strict";return document.getElementsByTagName("script").length})()}catch(e){s["scripts"]=e.message}try{i["serializedDomSize"]=(function(){"use strict";return document.body.innerHTML.length})()}catch(e){s["serializedDomSize"]=e.message}try{i["serviceWorker"]=(function(){"use strict";if("serviceWorker"in navigator){if(navigator.serviceWorker.controller){if(navigator.serviceWorker.controller.state==="activated"){return navigator.serviceWorker.controller.scriptURL}else return false}else{return false}}else{return false}})()}catch(e){s["serviceWorker"]=e.message}try{i["sessionStorageSize"]=(function(){"use strict";function e(e){const t=e.length||Object.keys(e).length;let n=0;for(let o=0;o<t;o++){const r=e.key(o);const i=e.getItem(r);n+=r.length+i.length}return n}return e(window.sessionStorage)})()}catch(e){s["sessionStorageSize"]=e.message}try{i["userTiming"]=(function(){"use strict";let e=0;let t=0;if(window.performance&&window.performance.getEntriesByType){t=window.performance.getEntriesByType("measure").length;e=window.performance.getEntriesByType("mark").length}return{marks:e,measures:t}})()}catch(e){s["userTiming"]=e.message}try{i["windowSize"]=(function(){"use strict";const e=window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth;const t=window.innerHeight||document.documentElement.clientHeight||document.body.clientHeight;return e+"x"+t})()}catch(e){s["windowSize"]=e.message}t["info"]=i;if(Object.keys(s).length>0){n["info"]=s}var a={},c={};try{a["avoidRenderBlocking"]=(function(e){"use strict";const t=[];const n=e.getCSSFiles(document.head);const o=e.getSynchJSFiles(document.head);const r=document.domain;const i=[];const s=e.getResourceHintsHrefs("preconnect");const a=s.map((function(t){return e.getHostname(t)}));let c=0;let u=0;let l="";let d=0;function h(n){const o=e.getHostname(n);if(o!==r){t.push(n);if(!e.exists(o,i)){d+=e.exists(o,a)?5:10;i.push(o)}d+=5}else{t.push(n);d+=5}}if(e.isHTTP2()){if(n.length>0){l="";n.forEach((function(n){if(e.getTransferSize(n)>14500){t.push(n);d+=5;c++;l+="The style "+n+" is larger than the magic number TCP window size 14.5 kB. Make the file smaller and the page will render faster. "}}))}if(o.length>0){d+=o.length*10;o.forEach((function(e){t.push(e);u++}));l+="Avoid loading synchronously JavaScript inside of head, you shouldn't need JavaScript to render your page! "}}else if(e.isHTTP3()){}else{n.forEach((function(e){h(e)}));c=n.length;o.forEach((function(e){h(e)}));u=o.length}if(t.length>0){l+=`The page has ${e.plural(c,"render blocking CSS request")} and ${e.plural(u,"blocking JavaScript request")} inside of head.`}return{id:"avoidRenderBlocking",title:"Avoid slowing down the critical rendering path",description:"The critical rendering path is what the browser needs to do to start rendering the page. Every file requested inside of the head element will postpone the rendering of the page, because the browser need to do the request. Avoid loading JavaScript synchronously inside of the head (you should not need JavaScript to render the page), request files from the same domain as the main document (to avoid DNS lookups) and inline CSS for really fast rendering and a short rendering path.",advice:l,score:Math.max(0,100-d),weight:10,offending:t,tags:["performance"]}})(e)}catch(e){c["avoidRenderBlocking"]=e.message}try{a["avoidScalingImages"]=(function(e){"use strict";const t=100;const n=[];const o=Array.prototype.slice.call(document.getElementsByTagName("img"));let r=0;let i="";for(let s=0,a=o.length;s<a;s++){const c=o[s];if(c.clientWidth+t<c.naturalWidth&&c.clientWidth>0){n.push(e.getAbsoluteURL(c.currentSrc));r+=10}}if(r>0){i=`The page has ${e.plural(r/10,"image")} that are scaled more than ${t} pixels. It would be better if those images are sent so the browser don't need to scale them.`}return{id:"avoidScalingImages",title:"Don't scale images in the browser",description:"It's easy to scale images in the browser and make sure they look good in different devices, however that is bad for performance! Scaling images in the browser takes extra CPU time and will hurt performance on mobile. And the user will download extra kilobytes (sometimes megabytes) of data that could be avoided. Don't do that, make sure you create multiple version of the same image server-side and serve the appropriate one.",advice:i,score:Math.max(0,100-r),weight:5,offending:n,tags:["performance","image"]}})(e)}catch(e){c["avoidScalingImages"]=e.message}try{a["cssPrint"]=(function(e){"use strict";const t=[];const n=document.getElementsByTagName("link");for(let o=0,r=n.length;o<r;o++){if(n[o].media==="print"){t.push(e.getAbsoluteURL(n[o].href))}}const i=t.length*10;return{id:"cssPrint",title:"Do not load specific print stylesheets.",description:"Loading a specific stylesheet for printing slows down the page, even though it is not used. You can include the print styles inside your other CSS file(s) just by using an @media query targeting type print.",advice:t.length>0?`The page has ${e.plural(t.length,"print stylesheet")}. You should include that stylesheet using @media type print instead.`:"",score:Math.max(0,100-i),weight:1,offending:t,tags:["performance","css"]}})(e)}catch(e){c["cssPrint"]=e.message}try{a["firstContentfulPaint"]=(function(e){"use strict";let t=100;let n="";const o=1800;const r=3e3;const i=performance.getEntriesByName("first-contentful-paint")[0].startTime;if(i<=o){`First contentful paint is good ${e.ms(i)}.`}else if(i<=r){t=50;n=`First contentful paint can be improved (${e.ms(i)}). It is in the Google Web Vitals needs improvement range, slower than 1.8 seconds.`}else{t=0;n=`First contentful paint is poor (${e.ms(i)}). It is in the Google Web Vitals poor range, slower than 3 seconds.`;let s=window.performance.getEntriesByType("navigation")[0];if(s){if(Number(s.responseStart.toFixed(0))>1e3){n+=`The page has a high time to first byte (TTFB) ${e.ms(s.responseStart)} that you should look into to improve first contentful paint.`}}}return{id:"firstContentfulPaint",title:"Have a fast first contentful paint",description:'The First Contentful Paint (FCP) metric measures the time from when the page starts loading to when any part of the page content is rendered on the screen. For this metric, "content" refers to text, images (including background images), <svg> elements, or non-white <canvas> elements.',advice:n,score:Math.max(0,t),weight:7,offending:[],tags:["performance"]}})(e)}catch(e){c["firstContentfulPaint"]=e.message}try{a["googleTagManager"]=(function(){"use strict";var e=100;if(window.google_tag_manager){e=0}return{id:"googleTagManager",title:"Avoid using Google Tag Manager.",description:"Google Tag Manager makes it possible for non tech users to add scripts to your page that will downgrade performance.",advice:e===0?"The page is using Google Tag Manager, this is a performance risk since non-tech users can add JavaScript to your page.":"",score:e,weight:5,offending:[],tags:["performance","js"]}})()}catch(e){c["googleTagManager"]=e.message}try{a["inlineCss"]=(function(e){"use strict";const t=[];const n=e.getCSSFiles(document.head);const o=Array.prototype.slice.call(window.document.head.getElementsByTagName("style"));let r="";let i=0;if(e.isHTTP2()&&n.length>0&&o.length>0){i+=5;r="The page has both inline CSS and CSS requests even though it uses a HTTP/2-ish connection. If you have many users on slow connections, it can be better to only inline the CSS. Run your own tests and check the waterfall graph to see what happens."}else if(e.isHTTP2()&&o.length>0&&n.length===0){r+="The page has inline CSS and uses HTTP/2. Do you have a lot of users with slow connections on the site? It is good to inline CSS when using HTTP/2."}else if(e.isHTTP2()&&n.length>0){r+="It is always faster for the user if you inline CSS instead of making a CSS request."}if(e.isHTTP3()){r="The page uses HTTP3. HTTP3 is new and it is hard to say if inlined is good or not. The coach will improve the advice when there is a new best practice."}else if(!e.isHTTP2()){if(n.length>0&&o.length===0){i+=10*n.length;r="The page loads "+e.plural(n.length,"CSS request")+" inside of head, try to inline the CSS for the first render and lazy load the rest.";t.push.apply(t,n)}if(o.length>0&&n.length>0){i+=10;r+="The page has both inline styles as well as it is requesting "+e.plural(n.length,"CSS file")+" inside of the head. Let's only inline CSS for really fast render.";t.push.apply(t,n)}}return{id:"inlineCss",title:"Inline CSS for faster first render",description:"In the early days of the Internet, inlining CSS was one of the ugliest things you can do. That has changed if you want your page to start rendering fast for your user. Always inline the critical CSS when you use HTTP/1 and HTTP/2 (avoid doing CSS requests that block rendering) and lazy load and cache the rest of the CSS. It is a little more complicated when using HTTP/2. Does your server support HTTP push? Then maybe that can help. Do you have a lot of users on a slow connection and are serving large chunks of HTML? Then it could be better to use the inline technique, becasue some servers always prioritize HTML content over CSS so the user needs to download the HTML first, before the CSS is downloaded.",advice:r,score:Math.max(0,100-i),weight:7,offending:t,tags:["performance","css"]}})(e)}catch(e){c["inlineCss"]=e.message}try{a["jquery"]=(function(e){"use strict";const t=[];if(typeof window.jQuery==="function"){let n=window.$;t.push(window.jQuery.fn.jquery);let o=window.jQuery;while(o.fn&&o.fn.jquery){o=window.jQuery.noConflict(true);if(!window.jQuery||!window.jQuery.fn||!window.jQuery.fn.jquery){break}if(o.fn.jquery===window.jQuery.fn.jquery){break}t.push(window.jQuery.fn.jquery)}window.jQuery=window.$=n}return{id:"jquery",title:"Avoid using more than one jQuery version per page",description:"There are sites out there that use multiple versions of jQuery on the same page. You shouldn't do that because the user will then unnecessarily download extra data. Cleanup the code and make sure you only use one version.",advice:t.length>1?"The page uses "+e.plural(t.length,"version")+" of jQuery! You only need one version, please remove the unnecessary version(s).":"",score:t.length>1?0:100,weight:4,offending:t,tags:["jQuery","performance"]}})(e)}catch(e){c["jquery"]=e.message}try{a["largestContentfulPaint"]=(function(e){"use strict";let t=100;let n="";const o=[];const r=PerformanceObserver.supportedEntryTypes;if(!r||r.indexOf("largest-contentful-paint")===-1){n="Largest contentful paint is not supported in this browser"}else{const i=new PerformanceObserver((()=>{}));i.observe({type:"largest-contentful-paint",buffered:true});const s=i.takeRecords();if(s.length>0){const a=s[s.length-1];const c=2500;const u=4e3;const l={url:a.url,renderTime:Number(Math.max(a.renderTime,a.loadTime).toFixed(0)),tagName:a.element?a.element.tagName:"",tag:a.element?a.element.cloneNode(false).outerHTML:""};if(l.renderTime<=c){`Largest contentful paint is good ${e.ms(l.renderTime)}.`}else if(l.renderTime<=u){t=80;n=`Largest contentful paint can be improved ${e.ms(l.renderTime)}. It is in the Google Web Vitals needs improvement range, slower than 2.5 seconds.`;o.push(l.url||l.tag)}else if(l.renderTime>u){t=0;n=`Largest contentful paint is poor ${e.ms(l.renderTime)}. It is in the Google Web Vitals poor range, slower than 4.5 seconds.`;o.push(l.url||l.tag)}if(l.tagName==="IMG"){if(a.element.importance!="high"){t-=5;n+=' You can add importance="high" to the image to increase the load priority that is rolling out soon in Chrome.'}if(a.element.loading==="lazy"){t-=20;n+=" The image is lazy loaded using the lazy attribute, you should avoid that on the LCP image."}}}}return{id:"largestContentfulPaint",title:"Have a fast largest contentful paint",description:"Largest contentful paint is one of Google Web Vitals and reports the render time of the largest image or text block visible within the viewport, relative to when the page first started loading. To be fast according to Google, it needs to render before 2.5 seconds and results over 4 seconds is poor performance.",advice:n,score:Math.max(0,t),weight:7,offending:o,tags:["performance"]}})(e)}catch(e){c["largestContentfulPaint"]=e.message}try{a["longTasks"]=(function(e){"use strict";const t=[];let n=0;let o=0;let r=0;let i=0;let s=0;let a="The page do not have any CPU Long Tasks.";const c=PerformanceObserver.supportedEntryTypes;if(!c||c.indexOf("longtask")===-1){a="The Long Task API is not supported in this browser."}else{const u=new PerformanceObserver((()=>{}));u.observe({type:"longtask",buffered:true});const l=performance.getEntriesByName("first-contentful-paint")[0].startTime;for(let d of u.takeRecords()){n+=20;o+=d.duration;if(l&&d.startTime<l){i++;s+=d.duration}else if(l&&d.startTime>l){r+=d.duration-50}t.push(d.name)}}return{id:"longTasks",title:"Avoid CPU Long Tasks",description:'Long CPU tasks locks the thread. To the user this is commonly visible as a "locked up" page where the browser is unable to respond to user input; this is a major source of bad user experience on the web today. However the CPU Long Task is depending on the computer/phones actual CPU speed, so you should measure this on the same type of the device that your user is using. To debug you should use the Chrome timeline log and drag/drop it into devtools or use Firefox Geckoprofiler.',advice:t.length>0?`The page has ${e.plural(t.length,"CPU long task")} with the total of ${e.ms(o.toFixed(0))}. The total blocking time is ${e.ms(r)} ${i>0?` and ${e.plural(i,"long task")} before first contentful paint with total time of ${e.ms(s)}.`:"."} However the CPU Long Task is depending on the computer/phones actual CPU speed, so you should measure this on the same type of the device that your user is using. Use Geckoprofiler for Firefox or Chromes tracelog to debug your long tasks.`:a,score:Math.max(0,100-n),weight:8,offending:t,tags:["performance","js"]}})(e)}catch(e){c["longTasks"]=e.message}try{a["spof"]=(function(e){"use strict";const t=[];const n=[];const o=document.domain;const r=e.getCSSFiles(document.head);let i=0;r.forEach((function(r){const s=e.getHostname(r);if(s!==o){t.push(r);if(n.indexOf(s)===-1){n.push(s);i+=10}}}));const s=e.getSynchJSFiles(document.head);s.forEach((function(r){const s=e.getHostname(r);if(s!==o){t.push(r);if(n.indexOf(s)===-1){n.push(s);i+=10}}}));return{id:"spof",title:"Avoid Frontend single point of failures",description:"A page can be stopped from loading in the browser if a single JavaScript, CSS, and in some cases a font, couldn't be fetched or is loading really slowly (the white screen of death). That is a scenario you really want to avoid. Never load 3rd-party components synchronously inside of the head tag.",advice:t.length>0?"The page has "+e.plural(t.length,"request")+" inside of the head that can cause a SPOF (single point of failure). Load them asynchronously or move them outside of the document head.":"",score:Math.max(0,100-i),weight:7,offending:t,tags:["performance","css","js"]}})(e)}catch(e){c["spof"]=e.message}t["performance"]={adviceList:a};if(Object.keys(c).length>0){n["performance"]=c}var u={},l={};try{u["facebook"]=(function(){"use strict";const e=[];let t=100;if(window.FB){t=0}return{id:"facebook",title:"Avoid including Facebook",description:"You share share private user information with Facebook that your user hasn't agreed on sharing.",advice:t===0?"The page gets content from Facebook. That means you share your users private information with Facebook.":"",score:t,weight:8,offending:e,tags:["privacy"]}})()}catch(e){l["facebook"]=e.message}try{u["fingerprint"]=(function(){"use strict";const e=[];let t=100;if(window.FingerprintJS||window.Fingerprint2){t=0}return{id:"fingerprint",title:"Do not fingerprint your user.",description:'Fingerprinting consists of collecting different kinds of information about the user with the goal of building a unique "fingerprint" for them. Different types of fingerprinting are used on the web by trackers. Browser fingerprinting use characteristics specific to the browser of the user, relying on the fact that the chance of another user having the exact same browser set-up is fairly small if there are a large enough number of variables to track',advice:t===0?"The page uses https://fingerprintjs.com to fingerprint the user.":"",score:t,weight:8,offending:e,tags:["privacy"]}})()}catch(e){l["fingerprint"]=e.message}try{u["ga"]=(function(){"use strict";const e=[];let t=100;if(window.ga&&window.ga.create){t=0}return{id:"ga",title:"Avoid using Google Analytics",description:"Google Analytics share private user information with Google that your user hasn't agreed on sharing.",advice:t===0?"The page is using Google Analytics meaning you share your users private information with Google. You should use analytics that care about user privacy, something like https://matomo.org.":"",score:t,weight:8,offending:e,tags:["privacy"]}})()}catch(e){l["ga"]=e.message}try{u["https"]=(function(){"use strict";const e=document.URL;let t=100;let n="";if(e.indexOf("https://")===-1){t=0;n="What!! The page is not using HTTPS. Every unencrypted HTTP request reveals information about user’s behavior, read more about it at https://https.cio.gov/everything/. You can get a totally free SSL/TLS certificate from https://letsencrypt.org/."}return{id:"https",title:"Serve your content securely",description:"A page should always use HTTPS (https://https.cio.gov/everything/). You also need that for HTTP/2. You can get your free SSL/TLC certificate from https://letsencrypt.org/.",advice:n,score:t,weight:10,offending:[],tags:["privacy"]}})()}catch(e){l["https"]=e.message}try{u["surveillance"]=(function(){"use strict";const e=document.domain;const t=[];const n=[".google.","facebook.com","youtube.","yahoo.com"];let o=100;for(var r=0;r<n.length;r++){if(e.indexOf(n[r])>-1){o=0;t.push(e)}}return{id:"surveillance",title:"Avoid using surveillance web sites",description:"Do not use web sites that harvest private user information and sell it to other companies. See https://en.wikipedia.org/wiki/Surveillance_capitalism",advice:o===0?e+" harvest user information and sell it to other companies without the users agreement. That is not OK.":"",score:o,weight:10,offending:t,tags:["privacy"]}})()}catch(e){l["surveillance"]=e.message}try{u["youtube"]=(function(){"use strict";const e=[];let t=100;if(window.YT){t=0}return{id:"youtube",title:"Avoid including Youtube videos",description:"If you include Youtube videos on your page, you are sharing private user information with Google.",advice:t===0?"The page is including code from Youtube. You share user private information with Google. Instead you can host a video screenshot and let the user choose to go to Youtube or not, by clicking on the screenshot. You can look at http://labnol.org/?p=27941 and make sure you host your screenshot yourself. Or choose another video service.":"",score:t,weight:6,offending:e,tags:["privacy"]}})()}catch(e){l["youtube"]=e.message}t["privacy"]={adviceList:u};if(Object.keys(l).length>0){n["privacy"]=l}var d={},h={};try{d["elementTimings"]=(function(){"use strict";const e=PerformanceObserver.supportedEntryTypes;if(!e||e.indexOf("element")===-1){return}const t=new PerformanceObserver((()=>{}));t.observe({type:"element",buffered:true});const n=t.takeRecords();const o={};for(let r of n){o[r.identifier]={duration:r.duration,url:r.url,loadTime:Number(r.loadTime.toFixed(0)),renderTime:Number(r.renderTime.toFixed(0)),startTime:Number(r.startTime.toFixed(0)),naturalHeight:r.naturalHeight,naturalWidth:r.naturalWidth,tagName:r.element?r.element.tagName:""}}return o})()}catch(e){h["elementTimings"]=e.message}try{d["fullyLoaded"]=(function(){"use strict";if(window.performance&&window.performance.getEntriesByType){const e=window.performance.getEntriesByType("resource");let t=0;for(let n=1,o=e.length;n<o;n++){if(e[n].responseEnd>t){t=e[n].responseEnd}}return t}else{return-1}})()}catch(e){h["fullyLoaded"]=e.message}try{d["largestContentfulPaint"]=(function(){"use strict";const e=PerformanceObserver.supportedEntryTypes;if(!e||e.indexOf("largest-contentful-paint")===-1){return}const t=new PerformanceObserver((()=>{}));t.observe({type:"largest-contentful-paint",buffered:true});const n=t.takeRecords();if(n.length>0){const o=n[n.length-1];return{duration:o.duration,id:o.id,url:o.url,loadTime:Number(o.loadTime.toFixed(0)),renderTime:Number(Math.max(o.renderTime,o.loadTime).toFixed(0)),size:o.size,startTime:Number(o.startTime.toFixed(0)),tagName:o.element?o.element.tagName:""}}else return})()}catch(e){h["largestContentfulPaint"]=e.message}try{d["navigationTimings"]=(function(){"use strict";const e=window.performance.timing;const t={navigationStart:0,unloadEventStart:e.unloadEventStart>0?e.unloadEventStart-e.navigationStart:undefined,unloadEventEnd:e.unloadEventEnd>0?e.unloadEventEnd-e.navigationStart:undefined,redirectStart:e.redirectStart>0?e.redirectStart-e.navigationStart:undefined,redirectEnd:e.redirectEnd>0?e.redirectEnd-e.navigationStart:undefined,fetchStart:e.fetchStart-e.navigationStart,domainLookupStart:e.domainLookupStart-e.navigationStart,domainLookupEnd:e.domainLookupEnd-e.navigationStart,connectStart:e.connectStart-e.navigationStart,connectEnd:e.connectEnd-e.navigationStart,secureConnectionStart:e.secureConnectionStart?e.secureConnectionStart-e.navigationStart:undefined,requestStart:e.requestStart-e.navigationStart,responseStart:e.responseStart-e.navigationStart,responseEnd:e.responseEnd-e.navigationStart,domLoading:e.domLoading-e.navigationStart,domInteractive:e.domInteractive-e.navigationStart,domContentLoadedEventStart:e.domContentLoadedEventStart-e.navigationStart,domContentLoadedEventEnd:e.domContentLoadedEventEnd-e.navigationStart,domComplete:e.domComplete-e.navigationStart,loadEventStart:e.loadEventStart-e.navigationStart,loadEventEnd:e.loadEventEnd-e.navigationStart};Object.keys(t).forEach((function(e){if(t[e]===undefined){delete t[e]}}));return t})()}catch(e){h["navigationTimings"]=e.message}try{d["paintTimings"]=(function(){"use strict";const e=window.performance.getEntriesByType("paint");const t={};if(e.length>0){for(var n=0;n<e.length;n++){t[e[n].name]=Number(e[n].startTime.toFixed(0))}return t}else return})()}catch(e){h["paintTimings"]=e.message}try{d["userTimings"]=(function(){"use strict";const e=[];const t=[];if(window.performance&&window.performance.getEntriesByType){const n=Array.prototype.slice.call(window.performance.getEntriesByType("mark"));n.forEach((function(e){t.push({name:e.name,startTime:e.startTime})}));const o=Array.prototype.slice.call(window.performance.getEntriesByType("measure"));o.forEach((function(t){e.push({name:t.name,duration:t.duration,startTime:t.startTime})}))}return{marks:t,measures:e}})()}catch(e){h["userTimings"]=e.message}t["timings"]=d;if(Object.keys(h).length>0){n["timings"]=h}"use strict";(function(e){var t=0,n=0;Object.keys(e).forEach((function(o){var r=0,i=0,s=e[o].adviceList;if(s){Object.keys(s).forEach((function(e){var o=s[e];t+=o.score*o.weight;r+=o.score*o.weight;n+=o.weight;i+=o.weight}))}if(i>0){e[o].score=Math.round(r/i)}}));e.score=Math.round(t/n)})(t);return{advice:t,errors:n,url:document.URL,version:"7.1.1"}})(e)}else{console.error("Missing window or window document")}})(); | ||
(function(){if(typeof window!=="undefined"){"use strict";const e={getAbsoluteURL:function(e){const t=window.document.createElement("a");t.href=e;return t.href},getHostname:function(e){const t=window.document.createElement("a");t.href=e;return t.hostname},exists:function(e,t){return t.some((function(t){return t===e}))},caseInsensitiveAttributeValueFilter:function(e,t){return function(n){const o=n.getAttribute(e)||"";if(o.toLowerCase()===t.toLowerCase()){return n}return undefined}},isHTTP2:function(){const t=e.getConnectionType().toLowerCase();return t==="h2"||t.startsWith("spdy")},isHTTP3:function(){const t=e.getConnectionType().toLowerCase();return t.startsWith("h3")},getConnectionType:function(){if(window.performance.getEntriesByType("navigation")&&window.performance.getEntriesByType("navigation")[0]&&window.performance.getEntriesByType("navigation")[0].nextHopProtocol){return window.performance.getEntriesByType("navigation")[0].nextHopProtocol}else if(window.performance&&window.performance.getEntriesByType&&window.performance.getEntriesByType("resource")){const t=window.performance.getEntriesByType("resource");if(t.length>1&&t[0].nextHopProtocol){const n=document.domain;for(let o=0,r=t.length;o<r;o++){if(n===e.getHostname(t[o].name)){return t[o].nextHopProtocol}}}}return"unknown"},getSynchJSFiles:function(t){const n=Array.prototype.slice.call(t.getElementsByTagName("script"));return n.filter((function(e){return!e.async&&e.src&&!e.defer})).map((function(t){return e.getAbsoluteURL(t.src)}))},getAsynchJSFiles:function(t){const n=Array.prototype.slice.call(t.getElementsByTagName("script"));return n.filter((function(e){return e.async&&e.src})).map((function(t){return e.getAbsoluteURL(t.src)}))},getResourceHintsHrefs:function(e){const t=Array.prototype.slice.call(window.document.head.getElementsByTagName("link"));return t.filter((function(t){return t.rel===e})).map((function(e){return e.href}))},getCSSFiles:function(t){const n=Array.prototype.slice.call(t.getElementsByTagName("link"));return n.filter((function(e){return e.rel==="stylesheet"&&!e.href.startsWith("data:")})).map((function(t){return e.getAbsoluteURL(t.href)}))},plural:function(e,t){if(e>1){t+="s"}return`${e} ${t}`},getTransferSize:function(e){const t=window.performance.getEntriesByName(e,"resource");if(t.length===1&&typeof t[0].transferSize==="number"){return t[0].transferSize}else{return 0}},ms(e){if(e<1e3){return e+" ms"}else{return Number(e/1e3).toFixed(3)+" s"}}};return(function(e){var t={},n={};var o={},r={};try{o["amp"]=(function(){"use strict";const e=[];const t=document.getElementsByTagName("html")[0];let n=100;if(t&&t.getAttribute("amp-version")||window.AMP){n=0}return{id:"amp",title:"Avoid using AMP",description:"AMP was one of Google attempts to strengthen its monopoly in the Interente advertising market. You can read more about it here: https://storage.courtlistener.com/recap/gov.uscourts.nysd.564903/gov.uscourts.nysd.564903.152.0_1.pdf Using AMP you also share private user information with Google that your user hasn't agreed on sharing.",advice:n===0?"The page is using AMP, that makes you share private user information with Google.":"",score:n,weight:10,offending:e,tags:["bestpractice"]}})()}catch(e){r["amp"]=e.message}try{o["charset"]=(function(){"use strict";let e=100;let t="";const n=document.characterSet;if(n===null){t="The page is missing a character set. If you use Chrome/Firefox we know you are missing it, if you use another browser, it could be an implementation problem.";e=0}else if(n!=="UTF-8"){t="You are not using charset UTF-8?";e=50}return{id:"charset",title:"Declare a charset in your document",description:"The Unicode Standard (UTF-8) covers (almost) all the characters, punctuations, and symbols in the world. Please use that.",advice:t,score:e,weight:2,offending:[],tags:["bestpractice"]}})()}catch(e){r["charset"]=e.message}try{o["cumulativeLayoutShift"]=(function(){"use strict";const e=[];let t="There is no Layout Shift on the page.";let n=0;let o=0;const r=PerformanceObserver.supportedEntryTypes;if(!r||r.indexOf("layout-shift")===-1){t="Layout Shift is not supported in this browser"}else{let i=0;let s=Number.NEGATIVE_INFINITY;let a=Number.NEGATIVE_INFINITY;const c=new PerformanceObserver((()=>{}));c.observe({type:"layout-shift",buffered:true});const u=c.takeRecords();for(let l of u){if(l.hadRecentInput){continue}if(l.startTime-s>5e3||l.startTime-a>1e3){s=l.startTime;i=0}a=l.startTime;i+=l.value;o=Math.max(o,i)}if(o<=.1){n=100}else if(o>.25){n=0;t=`You have a poor cumulative layout shift score (${o.toFixed(4)}). It is in the Google Web Vitals poor range, with a shift higher than 0.25. You should manually check the filmstrip or video and check if it will affect the user.`}else{n=50;t=`You have a cumulative layout shift score (${o.toFixed(4)}) that needs improvements. It is in the Google Web Vitals needs improvement range, shift higher than 0.1. You should manually check the filmstrip or video and check if it will affect the user.`}}return{id:"cumulativeLayoutShift",title:"Cumulative Layout Shift",description:"Cumulative Layout Shift measures the sum total of all individual layout shift scores for unexpected layout shift that occur. The metric is measuring visual stability by quantify how often users experience unexpected layout shifts. It is one of Google Web Vitals.",advice:t,score:n,weight:8,offending:e,tags:["bestpractice"]}})()}catch(e){r["cumulativeLayoutShift"]=e.message}try{o["doctype"]=(function(){"use strict";let e=100;let t="";const n=document.doctype;if(n===null){t="The page is missing a doctype. Please use <!DOCTYPE html>.";e=0}else if(!(n.name.toLowerCase()==="html"&&(n.systemId===""||n.systemId.toLowerCase()==="about:legacy-compat"))){t="Just do yourself a favor and use the HTML5 doctype declaration: <!DOCTYPE html>";e=25}return{id:"doctype",title:"Declare a doctype in your document",description:"The <!DOCTYPE> declaration is not an HTML tag; it is an instruction to the web browser about what version of HTML the page is written in.",advice:t,score:e,weight:2,offending:[],tags:["bestpractice"]}})()}catch(e){r["doctype"]=e.message}try{o["language"]=(function(){"use strict";const e=document.getElementsByTagName("html");const t=e[0].getAttribute("lang");let n=100;let o="";if(e.length>0){if(t===null){n=0;o='The page is missing a language definition in the HTML tag. Define it with <html lang="YOUR_LANGUAGE_CODE">'}}else{n=0;o="What! The page is missing the HTML tag!"}return{id:"language",title:"Declare the language code for your document",description:"According to the W3C recommendation you should declare the primary language for each Web page with the lang attribute inside the <html> tag https://www.w3.org/International/questions/qa-html-language-declarations#basics.",advice:o,score:n,weight:3,offending:[],tags:["bestpractice"]}})()}catch(e){r["language"]=e.message}try{o["metaDescription"]=(function(e){"use strict";const t=155;let n=100;let o="";let r=Array.prototype.slice.call(document.querySelectorAll("meta[name][content]"));r=r.filter(e.caseInsensitiveAttributeValueFilter("name","description"));const i=r.length>0?r[0].getAttribute("content"):"";if(i.length===0){o="The page is missing a meta description.";n=0}else if(i.length>t){o="The meta description is too long. It has "+i.length+" characters, the recommended max is "+t;n=50}return{id:"metaDescription",title:"Meta description",description:"Use a page description to make the page more relevant to search engines.",advice:o,score:n,weight:5,offending:[],tags:["bestpractice"]}})(e)}catch(e){r["metaDescription"]=e.message}try{o["optimizely"]=(function(e){"use strict";const t=e.getSynchJSFiles(document.head);const n=[];let o=100;let r="";t.forEach((function(t){if(e.getHostname(t)==="cdn.optimizely.com"){n.push(t);o=0;r="The page is using Optimizely. Use it with care because it hurts your performance. Only turn it on (= load the JavaScript) when you run your A/B tests. Then when you are finished make sure to turn it off."}}));return{id:"optimizely",title:"Only use Optimizely when you need it",description:"Use Optimizely with care because it hurts your performance since JavaScript is loaded synchronously inside of the head tag, making the first paint happen later. Only turn on Optimzely (= load the javascript) when you run your A/B tests.",advice:r,score:o,weight:2,offending:n,tags:["bestpractice"]}})(e)}catch(e){r["optimizely"]=e.message}try{o["pageTitle"]=(function(){"use strict";const e=60;const t=document.title;let n=100;let o="";if(t.length===0){o="The page is missing a title.";n=0}else if(t.length>e){o="The title is too long by "+(t.length-e)+" characters. The recommended max is "+e;n=50}return{id:"pageTitle",title:"Page title",description:"Use a title to make the page more relevant to search engines.",advice:o,score:n,weight:5,offending:[],tags:["bestpractice"]}})()}catch(e){r["pageTitle"]=e.message}try{o["spdy"]=(function(){"use strict";const t=e.getConnectionType();let n=100;let o="";if(t.indexOf("spdy")!==-1){n=0;o="The page is using SPDY. Chrome dropped support for SPDY in Chrome 51. Change to HTTP/2 asap."}return{id:"spdy",title:"EOL for SPDY in Chrome",description:"Chrome dropped supports for SPDY in Chrome 51, upgrade to HTTP/2 as soon as possible. The page has more users (browsers) supporting HTTP/2 than supports SPDY.",advice:o,score:n,weight:1,offending:[],tags:["bestpractice"]}})()}catch(e){r["spdy"]=e.message}try{o["url"]=(function(){"use strict";const e=document.URL;let t=100;let n="";if(e.indexOf("?")>-1&&e.indexOf("jsessionid")>e.indexOf("?")){t=0;n="The page has the session id for the user as a parameter, please change so the session handling is done only with cookies. "}var o=(e.match(/&/g)||[]).length;if(o>1){t-=50;n+="The page is using more than two request parameters. You should really rethink and try to minimize the number of parameters. "}if(e.length>100){t-=10;n+="The URL is "+e.length+" characters long. Try to make it less than 100 characters. "}if(e.indexOf(" ")>-1||e.indexOf("%20")>-1){t-=10;n+="Could the developer or the CMS be on Windows? Avoid using spaces in the URLs, use hyphens or underscores. "}return{id:"url",title:"Have a good URL format",description:"A clean URL is good for the user and for SEO. Make them human readable, avoid too long URLs, spaces in the URL, too many request parameters, and never ever have the session id in your URL.",advice:n,score:t<0?0:t,weight:2,offending:[],tags:["bestpractice"]}})()}catch(e){r["url"]=e.message}t["bestpractice"]={adviceList:o};if(Object.keys(r).length>0){n["bestpractice"]=r}var i={},s={};try{i["amp"]=(function(){"use strict";const e=document.getElementsByTagName("html")[0];if(e&&e.getAttribute("amp-version")||window.AMP){return e.getAttribute("amp-version")||true}else{return false}})()}catch(e){s["amp"]=e.message}try{i["browser"]=(function(){"use strict";const{userAgent:userAgent}=navigator;if(userAgent.includes("Firefox/")){return`Firefox ${userAgent.split("Firefox/")[1]}`}else if(userAgent.includes("Edg/")){return`Edge ${userAgent.split("Edg/")[1]}`}else if(userAgent.includes("Chrome/")){return`Chrome ${userAgent.match(/(Chrome)\/(\S+)/)[2]}`}else if(userAgent.includes("Safari/")){return`Safari ${userAgent.match(/(Version)\/(\S+)/)[2]}`}else return"Unknown"})()}catch(e){s["browser"]=e.message}try{i["connectionType"]=(function(e){"use strict";return e.getConnectionType()})(e)}catch(e){s["connectionType"]=e.message}try{i["documentHeight"]=(function(){"use strict";return Math.max(document.body.scrollHeight,document.body.offsetHeight,document.documentElement.clientHeight,document.documentElement.scrollHeight,document.documentElement.offsetHeight)})()}catch(e){s["documentHeight"]=e.message}try{i["documentTitle"]=(function(){"use strict";return document.title})()}catch(e){s["documentTitle"]=e.message}try{i["documentWidth"]=(function(){"use strict";return Math.max(document.body.scrollWidth,document.body.offsetWidth,document.documentElement.clientWidth,document.documentElement.scrollWidth,document.documentElement.offsetWidth)})()}catch(e){s["documentWidth"]=e.message}try{i["domDepth"]=(function(){"use strict";function e(e){const n=e.getElementsByTagName("*");let o=n.length;let r=0;let i=0;while(o--){let s=t(n[o]);if(s>i){i=s}r+=s}const a=r/n.length;return{avg:a,max:i}}function t(e){let t=0;if(e.parentNode){while(e=e.parentNode){t++}}return t}const n=e(document);return{avg:Math.round(n.avg),max:n.max}})()}catch(e){s["domDepth"]=e.message}try{i["domElements"]=(function(){"use strict";return document.getElementsByTagName("*").length})()}catch(e){s["domElements"]=e.message}try{i["generator"]=(function(){"use strict";const e=document.querySelector('meta[name="generator"]');if(e){return e.getAttribute("content")}})()}catch(e){s["generator"]=e.message}try{i["head"]=(function(e){"use strict";return{jssync:e.getSynchJSFiles(document.head),jsasync:e.getAsynchJSFiles(document.head),css:e.getCSSFiles(document.head)}})(e)}catch(e){s["head"]=e.message}try{i["iframes"]=(function(){"use strict";return document.getElementsByTagName("iframe").length})()}catch(e){s["iframes"]=e.message}try{i["localStorageSize"]=(function(){"use strict";function e(e){if(e){const t=e.length||Object.keys(e).length;let n=0;for(let o=0;o<t;o++){const r=e.key(o);const i=e.getItem(r);n+=r.length+i.length}return n}else{return 0}}return e(window.localStorage)})()}catch(e){s["localStorageSize"]=e.message}try{i["metaDescription"]=(function(){"use strict";const e=document.querySelector('meta[name="description"]');const t=document.querySelector('meta[property="og:description"]');if(e){return e.getAttribute("content")}else if(t){return t.getAttribute("content")}else{return""}})()}catch(e){s["metaDescription"]=e.message}try{i["networkConnectionType"]=(function(){"use strict";if(window.navigator.connection){return window.navigator.connection.effectiveType}else{return"unknown"}})()}catch(e){s["networkConnectionType"]=e.message}try{i["resourceHints"]=(function(e){"use strict";return{"dns-prefetch":e.getResourceHintsHrefs("dns-prefetch"),preconnect:e.getResourceHintsHrefs("preconnect"),prefetch:e.getResourceHintsHrefs("prefetch"),prerender:e.getResourceHintsHrefs("prerender")}})(e)}catch(e){s["resourceHints"]=e.message}try{i["responsive"]=(function(){"use strict";let e=true;const t=document.body.scrollWidth;const n=window.innerWidth;const o=document.body.children;if(t>n){e=false}for(var r in o){if(o[r].scrollWidth>n){e=false}}return e})()}catch(e){s["responsive"]=e.message}try{i["scripts"]=(function(){"use strict";return document.getElementsByTagName("script").length})()}catch(e){s["scripts"]=e.message}try{i["serializedDomSize"]=(function(){"use strict";return document.body.innerHTML.length})()}catch(e){s["serializedDomSize"]=e.message}try{i["serviceWorker"]=(function(){"use strict";if("serviceWorker"in navigator){if(navigator.serviceWorker.controller){if(navigator.serviceWorker.controller.state==="activated"){return navigator.serviceWorker.controller.scriptURL}else return false}else{return false}}else{return false}})()}catch(e){s["serviceWorker"]=e.message}try{i["sessionStorageSize"]=(function(){"use strict";function e(e){const t=e.length||Object.keys(e).length;let n=0;for(let o=0;o<t;o++){const r=e.key(o);const i=e.getItem(r);n+=r.length+i.length}return n}return e(window.sessionStorage)})()}catch(e){s["sessionStorageSize"]=e.message}try{i["userTiming"]=(function(){"use strict";let e=0;let t=0;if(window.performance&&window.performance.getEntriesByType){t=window.performance.getEntriesByType("measure").length;e=window.performance.getEntriesByType("mark").length}return{marks:e,measures:t}})()}catch(e){s["userTiming"]=e.message}try{i["windowSize"]=(function(){"use strict";const e=window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth;const t=window.innerHeight||document.documentElement.clientHeight||document.body.clientHeight;return e+"x"+t})()}catch(e){s["windowSize"]=e.message}t["info"]=i;if(Object.keys(s).length>0){n["info"]=s}var a={},c={};try{a["avoidRenderBlocking"]=(function(e){"use strict";const t=[];const n=e.getCSSFiles(document.head);const o=e.getSynchJSFiles(document.head);const r=document.domain;const i=[];const s=e.getResourceHintsHrefs("preconnect");const a=s.map((function(t){return e.getHostname(t)}));let c=0;let u=0;let l="";let d=0;function h(n){const o=e.getHostname(n);if(o!==r){t.push(n);if(!e.exists(o,i)){d+=e.exists(o,a)?5:10;i.push(o)}d+=5}else{t.push(n);d+=5}}if(e.isHTTP2()){if(n.length>0){l="";n.forEach((function(n){if(e.getTransferSize(n)>14500){t.push(n);d+=5;c++;l+="The style "+n+" is larger than the magic number TCP window size 14.5 kB. Make the file smaller and the page will render faster. "}}))}if(o.length>0){d+=o.length*10;o.forEach((function(e){t.push(e);u++}));l+="Avoid loading synchronously JavaScript inside of head, you shouldn't need JavaScript to render your page! "}}else if(e.isHTTP3()){}else{n.forEach((function(e){h(e)}));c=n.length;o.forEach((function(e){h(e)}));u=o.length}if(t.length>0){l+=`The page has ${e.plural(c,"render blocking CSS request")} and ${e.plural(u,"blocking JavaScript request")} inside of head.`}return{id:"avoidRenderBlocking",title:"Avoid slowing down the critical rendering path",description:"The critical rendering path is what the browser needs to do to start rendering the page. Every file requested inside of the head element will postpone the rendering of the page, because the browser need to do the request. Avoid loading JavaScript synchronously inside of the head (you should not need JavaScript to render the page), request files from the same domain as the main document (to avoid DNS lookups) and inline CSS for really fast rendering and a short rendering path.",advice:l,score:Math.max(0,100-d),weight:10,offending:t,tags:["performance"]}})(e)}catch(e){c["avoidRenderBlocking"]=e.message}try{a["avoidScalingImages"]=(function(e){"use strict";const t=100;const n=[];const o=Array.prototype.slice.call(document.getElementsByTagName("img"));let r=0;let i="";for(let s=0,a=o.length;s<a;s++){const c=o[s];if(c.clientWidth+t<c.naturalWidth&&c.clientWidth>0){n.push(e.getAbsoluteURL(c.currentSrc));r+=10}}if(r>0){i=`The page has ${e.plural(r/10,"image")} that are scaled more than ${t} pixels. It would be better if those images are sent so the browser don't need to scale them.`}return{id:"avoidScalingImages",title:"Don't scale images in the browser",description:"It's easy to scale images in the browser and make sure they look good in different devices, however that is bad for performance! Scaling images in the browser takes extra CPU time and will hurt performance on mobile. And the user will download extra kilobytes (sometimes megabytes) of data that could be avoided. Don't do that, make sure you create multiple version of the same image server-side and serve the appropriate one.",advice:i,score:Math.max(0,100-r),weight:5,offending:n,tags:["performance","image"]}})(e)}catch(e){c["avoidScalingImages"]=e.message}try{a["cssPrint"]=(function(e){"use strict";const t=[];const n=document.getElementsByTagName("link");for(let o=0,r=n.length;o<r;o++){if(n[o].media==="print"){t.push(e.getAbsoluteURL(n[o].href))}}const i=t.length*10;return{id:"cssPrint",title:"Do not load specific print stylesheets.",description:"Loading a specific stylesheet for printing slows down the page, even though it is not used. You can include the print styles inside your other CSS file(s) just by using an @media query targeting type print.",advice:t.length>0?`The page has ${e.plural(t.length,"print stylesheet")}. You should include that stylesheet using @media type print instead.`:"",score:Math.max(0,100-i),weight:1,offending:t,tags:["performance","css"]}})(e)}catch(e){c["cssPrint"]=e.message}try{a["firstContentfulPaint"]=(function(e){"use strict";let t=100;let n="";const o=1800;const r=3e3;const i=performance.getEntriesByName("first-contentful-paint")[0].startTime;if(i<=o){`First contentful paint is good ${e.ms(i)}.`}else if(i<=r){t=50;n=`First contentful paint can be improved (${e.ms(i)}). It is in the Google Web Vitals needs improvement range, slower than 1.8 seconds.`}else{t=0;n=`First contentful paint is poor (${e.ms(i)}). It is in the Google Web Vitals poor range, slower than 3 seconds.`;let s=window.performance.getEntriesByType("navigation")[0];if(s){if(Number(s.responseStart.toFixed(0))>1e3){n+=`The page has a high time to first byte (TTFB) ${e.ms(s.responseStart)} that you should look into to improve first contentful paint.`}}}return{id:"firstContentfulPaint",title:"Have a fast first contentful paint",description:'The First Contentful Paint (FCP) metric measures the time from when the page starts loading to when any part of the page content is rendered on the screen. For this metric, "content" refers to text, images (including background images), <svg> elements, or non-white <canvas> elements.',advice:n,score:Math.max(0,t),weight:7,offending:[],tags:["performance"]}})(e)}catch(e){c["firstContentfulPaint"]=e.message}try{a["googleTagManager"]=(function(){"use strict";var e=100;if(window.google_tag_manager){e=0}return{id:"googleTagManager",title:"Avoid using Google Tag Manager.",description:"Google Tag Manager makes it possible for non tech users to add scripts to your page that will downgrade performance.",advice:e===0?"The page is using Google Tag Manager, this is a performance risk since non-tech users can add JavaScript to your page.":"",score:e,weight:5,offending:[],tags:["performance","js"]}})()}catch(e){c["googleTagManager"]=e.message}try{a["inlineCss"]=(function(e){"use strict";const t=[];const n=e.getCSSFiles(document.head);const o=Array.prototype.slice.call(window.document.head.getElementsByTagName("style"));let r="";let i=0;if(e.isHTTP2()&&n.length>0&&o.length>0){i+=5;r="The page has both inline CSS and CSS requests even though it uses a HTTP/2-ish connection. If you have many users on slow connections, it can be better to only inline the CSS. Run your own tests and check the waterfall graph to see what happens."}else if(e.isHTTP2()&&o.length>0&&n.length===0){r+="The page has inline CSS and uses HTTP/2. Do you have a lot of users with slow connections on the site? It is good to inline CSS when using HTTP/2."}else if(e.isHTTP2()&&n.length>0){r+="It is always faster for the user if you inline CSS instead of making a CSS request."}if(e.isHTTP3()){r="The page uses HTTP3. HTTP3 is new and it is hard to say if inlined is good or not. The coach will improve the advice when there is a new best practice."}else if(!e.isHTTP2()){if(n.length>0&&o.length===0){i+=10*n.length;r="The page loads "+e.plural(n.length,"CSS request")+" inside of head, try to inline the CSS for the first render and lazy load the rest.";t.push.apply(t,n)}if(o.length>0&&n.length>0){i+=10;r+="The page has both inline styles as well as it is requesting "+e.plural(n.length,"CSS file")+" inside of the head. Let's only inline CSS for really fast render.";t.push.apply(t,n)}}return{id:"inlineCss",title:"Inline CSS for faster first render",description:"In the early days of the Internet, inlining CSS was one of the ugliest things you can do. That has changed if you want your page to start rendering fast for your user. Always inline the critical CSS when you use HTTP/1 and HTTP/2 (avoid doing CSS requests that block rendering) and lazy load and cache the rest of the CSS. It is a little more complicated when using HTTP/2. Does your server support HTTP push? Then maybe that can help. Do you have a lot of users on a slow connection and are serving large chunks of HTML? Then it could be better to use the inline technique, becasue some servers always prioritize HTML content over CSS so the user needs to download the HTML first, before the CSS is downloaded.",advice:r,score:Math.max(0,100-i),weight:7,offending:t,tags:["performance","css"]}})(e)}catch(e){c["inlineCss"]=e.message}try{a["jquery"]=(function(e){"use strict";const t=[];if(typeof window.jQuery==="function"){let n=window.$;t.push(window.jQuery.fn.jquery);let o=window.jQuery;while(o.fn&&o.fn.jquery){o=window.jQuery.noConflict(true);if(!window.jQuery||!window.jQuery.fn||!window.jQuery.fn.jquery){break}if(o.fn.jquery===window.jQuery.fn.jquery){break}t.push(window.jQuery.fn.jquery)}window.jQuery=window.$=n}return{id:"jquery",title:"Avoid using more than one jQuery version per page",description:"There are sites out there that use multiple versions of jQuery on the same page. You shouldn't do that because the user will then unnecessarily download extra data. Cleanup the code and make sure you only use one version.",advice:t.length>1?"The page uses "+e.plural(t.length,"version")+" of jQuery! You only need one version, please remove the unnecessary version(s).":"",score:t.length>1?0:100,weight:4,offending:t,tags:["jQuery","performance"]}})(e)}catch(e){c["jquery"]=e.message}try{a["largestContentfulPaint"]=(function(e){"use strict";let t=100;let n="";const o=[];const r=PerformanceObserver.supportedEntryTypes;if(!r||r.indexOf("largest-contentful-paint")===-1){n="Largest contentful paint is not supported in this browser"}else{const i=new PerformanceObserver((()=>{}));i.observe({type:"largest-contentful-paint",buffered:true});const s=i.takeRecords();if(s.length>0){const a=s[s.length-1];const c=2500;const u=4e3;const l={url:a.url,renderTime:Number(Math.max(a.renderTime,a.loadTime).toFixed(0)),tagName:a.element?a.element.tagName:"",tag:a.element?a.element.cloneNode(false).outerHTML:""};if(l.renderTime<=c){`Largest contentful paint is good ${e.ms(l.renderTime)}.`}else if(l.renderTime<=u){t=80;n=`Largest contentful paint can be improved ${e.ms(l.renderTime)}. It is in the Google Web Vitals needs improvement range, slower than 2.5 seconds.`;o.push(l.url||l.tag)}else if(l.renderTime>u){t=0;n=`Largest contentful paint is poor ${e.ms(l.renderTime)}. It is in the Google Web Vitals poor range, slower than 4.5 seconds.`;o.push(l.url||l.tag)}if(l.tagName==="IMG"){if(a.element.importance!="high"){t-=5;n+=' You can add importance="high" to the image to increase the load priority that is rolling out soon in Chrome.'}if(a.element.loading==="lazy"){t-=20;n+=" The image is lazy loaded using the lazy attribute, you should avoid that on the LCP image."}}}}return{id:"largestContentfulPaint",title:"Have a fast largest contentful paint",description:"Largest contentful paint is one of Google Web Vitals and reports the render time of the largest image or text block visible within the viewport, relative to when the page first started loading. To be fast according to Google, it needs to render before 2.5 seconds and results over 4 seconds is poor performance.",advice:n,score:Math.max(0,t),weight:7,offending:o,tags:["performance"]}})(e)}catch(e){c["largestContentfulPaint"]=e.message}try{a["longTasks"]=(function(e){"use strict";const t=[];let n=0;let o=0;let r=0;let i=0;let s=0;let a="The page do not have any CPU Long Tasks.";const c=PerformanceObserver.supportedEntryTypes;if(!c||c.indexOf("longtask")===-1){a="The Long Task API is not supported in this browser."}else{const u=new PerformanceObserver((()=>{}));u.observe({type:"longtask",buffered:true});const l=performance.getEntriesByName("first-contentful-paint")[0].startTime;for(let d of u.takeRecords()){n+=20;o+=d.duration;if(l&&d.startTime<l){i++;s+=d.duration}else if(l&&d.startTime>l){r+=d.duration-50}t.push(d.name)}}return{id:"longTasks",title:"Avoid CPU Long Tasks",description:'Long CPU tasks locks the thread. To the user this is commonly visible as a "locked up" page where the browser is unable to respond to user input; this is a major source of bad user experience on the web today. However the CPU Long Task is depending on the computer/phones actual CPU speed, so you should measure this on the same type of the device that your user is using. To debug you should use the Chrome timeline log and drag/drop it into devtools or use Firefox Geckoprofiler.',advice:t.length>0?`The page has ${e.plural(t.length,"CPU long task")} with the total of ${e.ms(o.toFixed(0))}. The total blocking time is ${e.ms(r)} ${i>0?` and ${e.plural(i,"long task")} before first contentful paint with total time of ${e.ms(s)}.`:"."} However the CPU Long Task is depending on the computer/phones actual CPU speed, so you should measure this on the same type of the device that your user is using. Use Geckoprofiler for Firefox or Chromes tracelog to debug your long tasks.`:a,score:Math.max(0,100-n),weight:8,offending:t,tags:["performance","js"]}})(e)}catch(e){c["longTasks"]=e.message}try{a["spof"]=(function(e){"use strict";const t=[];const n=[];const o=document.domain;const r=e.getCSSFiles(document.head);let i=0;r.forEach((function(r){const s=e.getHostname(r);if(s!==o){t.push(r);if(n.indexOf(s)===-1){n.push(s);i+=10}}}));const s=e.getSynchJSFiles(document.head);s.forEach((function(r){const s=e.getHostname(r);if(s!==o){t.push(r);if(n.indexOf(s)===-1){n.push(s);i+=10}}}));return{id:"spof",title:"Avoid Frontend single point of failures",description:"A page can be stopped from loading in the browser if a single JavaScript, CSS, and in some cases a font, couldn't be fetched or is loading really slowly (the white screen of death). That is a scenario you really want to avoid. Never load 3rd-party components synchronously inside of the head tag.",advice:t.length>0?"The page has "+e.plural(t.length,"request")+" inside of the head that can cause a SPOF (single point of failure). Load them asynchronously or move them outside of the document head.":"",score:Math.max(0,100-i),weight:7,offending:t,tags:["performance","css","js"]}})(e)}catch(e){c["spof"]=e.message}t["performance"]={adviceList:a};if(Object.keys(c).length>0){n["performance"]=c}var u={},l={};try{u["facebook"]=(function(){"use strict";const e=[];let t=100;if(window.FB){t=0}return{id:"facebook",title:"Avoid including Facebook",description:"You share share private user information with Facebook that your user hasn't agreed on sharing.",advice:t===0?"The page gets content from Facebook. That means you share your users private information with Facebook.":"",score:t,weight:8,offending:e,tags:["privacy"]}})()}catch(e){l["facebook"]=e.message}try{u["fingerprint"]=(function(){"use strict";const e=[];let t=100;if(window.FingerprintJS||window.Fingerprint2){t=0}return{id:"fingerprint",title:"Do not fingerprint your user.",description:'Fingerprinting consists of collecting different kinds of information about the user with the goal of building a unique "fingerprint" for them. Different types of fingerprinting are used on the web by trackers. Browser fingerprinting use characteristics specific to the browser of the user, relying on the fact that the chance of another user having the exact same browser set-up is fairly small if there are a large enough number of variables to track',advice:t===0?"The page uses https://fingerprintjs.com to fingerprint the user.":"",score:t,weight:8,offending:e,tags:["privacy"]}})()}catch(e){l["fingerprint"]=e.message}try{u["ga"]=(function(){"use strict";const e=[];let t=100;if(window.ga&&window.ga.create){t=0}return{id:"ga",title:"Avoid using Google Analytics",description:"Google Analytics share private user information with Google that your user hasn't agreed on sharing.",advice:t===0?"The page is using Google Analytics meaning you share your users private information with Google. You should use analytics that care about user privacy, something like https://matomo.org.":"",score:t,weight:8,offending:e,tags:["privacy"]}})()}catch(e){l["ga"]=e.message}try{u["https"]=(function(){"use strict";const e=document.URL;let t=100;let n="";if(e.indexOf("https://")===-1){t=0;n="What!! The page is not using HTTPS. Every unencrypted HTTP request reveals information about user’s behavior, read more about it at https://https.cio.gov/everything/. You can get a totally free SSL/TLS certificate from https://letsencrypt.org/."}return{id:"https",title:"Serve your content securely",description:"A page should always use HTTPS (https://https.cio.gov/everything/). You also need that for HTTP/2. You can get your free SSL/TLC certificate from https://letsencrypt.org/.",advice:n,score:t,weight:10,offending:[],tags:["privacy"]}})()}catch(e){l["https"]=e.message}try{u["surveillance"]=(function(){"use strict";const e=document.domain;const t=[];const n=[".google.","facebook.com","youtube.","yahoo.com"];let o=100;for(var r=0;r<n.length;r++){if(e.indexOf(n[r])>-1){o=0;t.push(e)}}return{id:"surveillance",title:"Avoid using surveillance web sites",description:"Do not use web sites that harvest private user information and sell it to other companies. See https://en.wikipedia.org/wiki/Surveillance_capitalism",advice:o===0?e+" harvest user information and sell it to other companies without the users agreement. That is not OK.":"",score:o,weight:10,offending:t,tags:["privacy"]}})()}catch(e){l["surveillance"]=e.message}try{u["youtube"]=(function(){"use strict";const e=[];let t=100;if(window.YT){t=0}return{id:"youtube",title:"Avoid including Youtube videos",description:"If you include Youtube videos on your page, you are sharing private user information with Google.",advice:t===0?"The page is including code from Youtube. You share user private information with Google. Instead you can host a video screenshot and let the user choose to go to Youtube or not, by clicking on the screenshot. You can look at http://labnol.org/?p=27941 and make sure you host your screenshot yourself. Or choose another video service.":"",score:t,weight:6,offending:e,tags:["privacy"]}})()}catch(e){l["youtube"]=e.message}t["privacy"]={adviceList:u};if(Object.keys(l).length>0){n["privacy"]=l}var d={},h={};try{d["elementTimings"]=(function(){"use strict";const e=PerformanceObserver.supportedEntryTypes;if(!e||e.indexOf("element")===-1){return}const t=new PerformanceObserver((()=>{}));t.observe({type:"element",buffered:true});const n=t.takeRecords();const o={};for(let r of n){o[r.identifier]={duration:r.duration,url:r.url,loadTime:Number(r.loadTime.toFixed(0)),renderTime:Number(r.renderTime.toFixed(0)),startTime:Number(r.startTime.toFixed(0)),naturalHeight:r.naturalHeight,naturalWidth:r.naturalWidth,tagName:r.element?r.element.tagName:""}}return o})()}catch(e){h["elementTimings"]=e.message}try{d["fullyLoaded"]=(function(){"use strict";if(window.performance&&window.performance.getEntriesByType){const e=window.performance.getEntriesByType("resource");let t=0;for(let n=1,o=e.length;n<o;n++){if(e[n].responseEnd>t){t=e[n].responseEnd}}return t}else{return-1}})()}catch(e){h["fullyLoaded"]=e.message}try{d["largestContentfulPaint"]=(function(){"use strict";const e=PerformanceObserver.supportedEntryTypes;if(!e||e.indexOf("largest-contentful-paint")===-1){return}const t=new PerformanceObserver((()=>{}));t.observe({type:"largest-contentful-paint",buffered:true});const n=t.takeRecords();if(n.length>0){const o=n[n.length-1];return{duration:o.duration,id:o.id,url:o.url,loadTime:Number(o.loadTime.toFixed(0)),renderTime:Number(Math.max(o.renderTime,o.loadTime).toFixed(0)),size:o.size,startTime:Number(o.startTime.toFixed(0)),tagName:o.element?o.element.tagName:""}}else return})()}catch(e){h["largestContentfulPaint"]=e.message}try{d["navigationTimings"]=(function(){"use strict";const e=window.performance.timing;const t={navigationStart:0,unloadEventStart:e.unloadEventStart>0?e.unloadEventStart-e.navigationStart:undefined,unloadEventEnd:e.unloadEventEnd>0?e.unloadEventEnd-e.navigationStart:undefined,redirectStart:e.redirectStart>0?e.redirectStart-e.navigationStart:undefined,redirectEnd:e.redirectEnd>0?e.redirectEnd-e.navigationStart:undefined,fetchStart:e.fetchStart-e.navigationStart,domainLookupStart:e.domainLookupStart-e.navigationStart,domainLookupEnd:e.domainLookupEnd-e.navigationStart,connectStart:e.connectStart-e.navigationStart,connectEnd:e.connectEnd-e.navigationStart,secureConnectionStart:e.secureConnectionStart?e.secureConnectionStart-e.navigationStart:undefined,requestStart:e.requestStart-e.navigationStart,responseStart:e.responseStart-e.navigationStart,responseEnd:e.responseEnd-e.navigationStart,domLoading:e.domLoading-e.navigationStart,domInteractive:e.domInteractive-e.navigationStart,domContentLoadedEventStart:e.domContentLoadedEventStart-e.navigationStart,domContentLoadedEventEnd:e.domContentLoadedEventEnd-e.navigationStart,domComplete:e.domComplete-e.navigationStart,loadEventStart:e.loadEventStart-e.navigationStart,loadEventEnd:e.loadEventEnd-e.navigationStart};Object.keys(t).forEach((function(e){if(t[e]===undefined){delete t[e]}}));return t})()}catch(e){h["navigationTimings"]=e.message}try{d["paintTimings"]=(function(){"use strict";const e=window.performance.getEntriesByType("paint");const t={};if(e.length>0){for(var n=0;n<e.length;n++){t[e[n].name]=Number(e[n].startTime.toFixed(0))}return t}else return})()}catch(e){h["paintTimings"]=e.message}try{d["userTimings"]=(function(){"use strict";const e=[];const t=[];if(window.performance&&window.performance.getEntriesByType){const n=Array.prototype.slice.call(window.performance.getEntriesByType("mark"));n.forEach((function(e){t.push({name:e.name,startTime:e.startTime})}));const o=Array.prototype.slice.call(window.performance.getEntriesByType("measure"));o.forEach((function(t){e.push({name:t.name,duration:t.duration,startTime:t.startTime})}))}return{marks:t,measures:e}})()}catch(e){h["userTimings"]=e.message}t["timings"]=d;if(Object.keys(h).length>0){n["timings"]=h}"use strict";(function(e){var t=0,n=0;Object.keys(e).forEach((function(o){var r=0,i=0,s=e[o].adviceList;if(s){Object.keys(s).forEach((function(e){var o=s[e];t+=o.score*o.weight;r+=o.score*o.weight;n+=o.weight;i+=o.weight}))}if(i>0){e[o].score=Math.round(r/i)}}));e.score=Math.round(t/n)})(t);return{advice:t,errors:n,url:document.URL,version:"7.1.2"}})(e)}else{console.error("Missing window or window document")}})(); |
{ | ||
"name": "coach-core", | ||
"version": "7.1.1", | ||
"version": "7.1.2", | ||
"description": "Core package for the Coach.", | ||
@@ -83,6 +83,6 @@ "keywords": [ | ||
"lodash.sortby": "4.7.0", | ||
"pagexray": "4.4.1", | ||
"third-party-web": "0.15.0", | ||
"pagexray": "4.4.2", | ||
"third-party-web": "0.17.1", | ||
"wappalyzer-core": "6.6.0" | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
+ Addedpagexray@4.4.2(transitive)
+ Addedthird-party-web@0.17.1(transitive)
- Removedpagexray@4.4.1(transitive)
- Removedthird-party-web@0.15.0(transitive)
Updatedpagexray@4.4.2
Updatedthird-party-web@0.17.1