diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index ce32b387d7..3633ba349c 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -24,6 +24,11 @@ jobs: sudo apt-get update sudo apt-get --only-upgrade install google-chrome-stable google-chrome --version + - name: Install dependencies + run: | + python -m pip install --upgrade --user pip + python -m pip install --user scipy + python -m pip show scipy - name: Install Firefox uses: browser-actions/setup-firefox@latest #with: @@ -69,4 +74,6 @@ jobs: - name: Run test with Influx 2.6.1 run: bin/sitespeed.js http://127.0.0.1:3001/simple/ -n 1 --influxdb.host 127.0.0.1 --influxdb.port 8087 --influxdb.version 2 --influxdb.organisation sitespeed --influxdb.token sitespeed --xvfb - name: Run Chrome test with config - run: node bin/sitespeed.js --config test/exampleConfig.json http://127.0.0.1:3001/simple/ --xvfb \ No newline at end of file + run: node bin/sitespeed.js --config test/exampleConfig.json http://127.0.0.1:3001/simple/ --xvfb + - name: Run Chrome test using compare plugin + run: node bin/sitespeed.js --compare.id compare --compare.saveBaseline --compare.baselinePath test/ http://127.0.0.1:3001/simple/ --xvfb \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 5500817034..fb90e4c4c7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -44,4 +44,6 @@ RUN echo 'ALL ALL=NOPASSWD: /usr/sbin/tc, /usr/sbin/route, /usr/sbin/ip' > /etc/ ENTRYPOINT ["/start.sh"] VOLUME /sitespeed.io +VOLUME /baseline + WORKDIR /sitespeed.io diff --git a/docs/_includes/version/browsertime.txt b/docs/_includes/version/browsertime.txt index 2941b81991..5fc5a7bfee 100644 --- a/docs/_includes/version/browsertime.txt +++ b/docs/_includes/version/browsertime.txt @@ -1 +1 @@ -19.0.0 \ No newline at end of file +19.1.0 \ No newline at end of file diff --git a/lib/cli/cli.js b/lib/cli/cli.js index c20f457f96..c4d2444e3f 100644 --- a/lib/cli/cli.js +++ b/lib/cli/cli.js @@ -1870,6 +1870,68 @@ export async function parseCommandLine() { group: 'API' }); + parsed + .option('compare.id', { + type: 'string', + describe: + 'The id of the test. Will be used to find the baseline test, that is using the id as a part of the name.', + group: 'compare' + }) + .option('compare.baselinePath', { + type: 'string', + describe: + 'Specifies the path to the baseline data file. This file is used as a reference for comparison against the current test data.', + group: 'compare' + }) + .option('compare.saveBaseline', { + type: 'boolean', + default: false, + describe: + 'Determines whether to save the current test data as the new baseline. Set to true to save the current data as baseline for future comparisons.', + group: 'compare' + }) + .option('compare.testType', { + describe: + 'Selects the statistical test type to be used for comparison. Options are mannwhitneyu for the Mann-Whitney U test and wilcoxon for the Wilcoxon signed-rank test.', + choices: ['mannwhitneyu', ' wilcoxon'], + default: 'mannwhitneyu', + group: 'compare' + }) + .option('compare.alternative', { + choices: ['less', ' greater', 'two-sided'], + default: 'less', + describe: + 'Specifies the alternative hypothesis to be tested. Options are less for one-sided test where the first group is expected to be less than the second, greater for one-sided test with the first group expected to be greater, or two-sided for a two-sided test.', + group: 'compare' + }) + .option('compare.wilcoxon.correction', { + type: 'boolean', + describe: + 'Enables or disables the continuity correction in the Wilcoxon signed-rank test. Set to true to enable the correction.', + default: false, + group: 'compare' + }) + .option('compare.wilcoxon.zeroMethod', { + choices: ['wilcox', ' pratt', 'zsplit'], + describe: + 'Specifies the method for handling zero differences in the Wilcoxon test. wilcox discards all zero-difference pairs, pratt includes all, and zsplit splits them evenly among positive and negative ranks.', + default: 'zsplit', + group: 'compare' + }) + .option('compare.mannwhitneyu.useContinuity', { + type: 'boolean', + default: false, + describe: + 'Determines whether to use continuity correction in the Mann-Whitney U test. Set to true to apply the correction.', + group: 'compare' + }) + .option('compare.mannwhitneyu.method', { + choices: ['auto', ' exact', 'symptotic'], + escribe: + 'Selects the method for calculating the Mann-Whitney U test. auto automatically selects between exact and asymptotic based on sample size, exact uses the exact distribution of U, and symptotic uses a normal approximation.', + default: 'auto', + group: 'compare' + }); parsed .option('mobile', { describe: diff --git a/lib/plugins/compare/baseline.js b/lib/plugins/compare/baseline.js new file mode 100644 index 0000000000..a945caee8e --- /dev/null +++ b/lib/plugins/compare/baseline.js @@ -0,0 +1,35 @@ +import fs from 'node:fs/promises'; +import { join, resolve } from 'node:path'; + +export async function getBaseline(id, compareOptions) { + try { + return JSON.parse( + await fs.readFile( + resolve( + join(compareOptions.baselinePath || process.cwd(), `${id}.json`) + ) + ) + ); + } catch { + return; + } +} +/* +async function getBaselineFromInternet(url) { + try { + const response = await fetch(url); + return response.json(); + } catch (error) { + log.error('Could not fetch', error); + } +} + +async function getBaselineFromFile(path) {} + +/* +export async function saveBaseline(json, options) { + +}*/ +export async function saveBaseline(json, name) { + return fs.writeFile(resolve(name), JSON.stringify(json)); +} diff --git a/lib/plugins/compare/helper.js b/lib/plugins/compare/helper.js new file mode 100644 index 0000000000..22df67a32a --- /dev/null +++ b/lib/plugins/compare/helper.js @@ -0,0 +1,347 @@ +import { fileURLToPath } from 'node:url'; +import { join } from 'node:path'; +import path from 'node:path'; + +import { execa } from 'execa'; +import { Stats } from 'fast-stats'; +import intel from 'intel'; +import { decimals } from '../../support/helpers/index.js'; +const log = intel.getLogger('sitespeedio.plugin.compare'); + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); + +class Metric { + constructor(name, values) { + this.name = name; + this.stats = new Stats().push(values); + } + + getName() { + return this.name; + } + getValues() { + return this.stats.data; + } + getStats() { + return this.stats; + } +} + +export async function runStatisticalTests(data) { + let extras = ''; + try { + const { stdout } = await execa( + process.env.PYTHON || 'python', + [join(__dirname, 'statistical.py')], + { + input: JSON.stringify(data) + } + ); + extras = stdout; + const results = JSON.parse(stdout); + log.verbose('Result from the python script %j'.results); + return results; + } catch (error) { + log.error(error); + log.error(extras); + } +} + +export function getStatistics(arrayOfValues) { + return new Stats().push(arrayOfValues); +} + +function getExtras(data) { + const metrics = {}; + const results = {}; + + for (const run of data.extras) { + for (const name of Object.keys(run)) { + if (!metrics[name]) { + metrics[name] = []; + } + metrics[name].push(run[name]); + } + } + + for (const [metricName, values] of Object.entries(metrics)) { + results[metricName] = new Metric(metricName, values); + } + + return results; +} + +function getTimings(data) { + const timingMetrics = { + ttfb: [], + loadEventEnd: [], + firstContentfulPaint: [], + fullyLoaded: [] + }; + + for (const run of data.browserScripts) { + timingMetrics['ttfb'].push(run.timings.ttfb); + timingMetrics['loadEventEnd'].push(run.timings.loadEventEnd); + timingMetrics['firstContentfulPaint'].push( + run.timings.paintTiming['first-contentful-paint'] + ); + } + + for (const run of data.fullyLoaded) { + timingMetrics['fullyLoaded'].push(run); + } + + const results = {}; + for (const [metricName, values] of Object.entries(timingMetrics)) { + if (!results.timings) { + results.timings = {}; + } + results.timings[metricName] = new Metric(`${metricName}`, values); + } + return results; +} + +function getUserTimings(data) { + const userTimingMetrics = {}; + for (const run of data.browserScripts) { + if (run.timings.userTimings) { + const { marks, measures } = run.timings.userTimings; + + for (const mark of marks) { + if (!userTimingMetrics[mark.name]) { + userTimingMetrics[mark.name] = []; + } + userTimingMetrics[mark.name].push(decimals(mark.startTime)); + } + + for (const measure of measures) { + if (!userTimingMetrics[measure.name]) { + userTimingMetrics[measure.name] = []; + } + userTimingMetrics[measure.name].push(decimals(measure.startTime)); + } + } + } + + const results = {}; + for (const [metricName, values] of Object.entries(userTimingMetrics)) { + if (!results.userTimings) { + results.userTimings = {}; + } + results.userTimings[metricName] = new Metric(`${metricName}`, values); + } + return results; +} + +function getElementTimings(data) { + const elementTimingMetrics = {}; + for (const run of data.browserScripts) { + if (run.timings.elementTimings) { + for (const [name, timing] of Object.entries(run.timings.elementTimings)) { + if (!elementTimingMetrics[name]) { + elementTimingMetrics[name] = []; + } + elementTimingMetrics[name].push(timing.renderTime); + } + } + } + + const results = {}; + for (const [metricName, values] of Object.entries(elementTimingMetrics)) { + if (!results.elementTimings) { + results.elementTimings = {}; + } + results.elementTimings[metricName] = new Metric(`${metricName}`, values); + } + return results; +} + +function getGoogleWebVitals(data) { + const googleWebVitalsMetrics = {}; + for (const run of data.googleWebVitals) { + for (const [name, value] of Object.entries(run)) { + if (!googleWebVitalsMetrics[name]) { + googleWebVitalsMetrics[name] = []; + } + googleWebVitalsMetrics[name].push(value); + } + } + + const results = {}; + for (const [metricName, values] of Object.entries(googleWebVitalsMetrics)) { + if (!results.googleWebVitals) { + results.googleWebVitals = {}; + } + results.googleWebVitals[metricName] = new Metric(`${metricName}`, values); + } + return results; +} + +function getVisualMetrics(data) { + const DO_NOT_USE = new Set([ + 'VisualProgress', + 'videoRecordingStart', + 'VisualComplete85', + 'VisualComplete95', + 'VisualComplete99' + ]); + + const visualMetrics = {}; + for (const run of data.visualMetrics) { + for (const [name, value] of Object.entries(run)) { + if (!DO_NOT_USE.has(name)) { + if (!visualMetrics[name]) { + visualMetrics[name] = []; + } + visualMetrics[name].push(value); + } + } + } + + const results = {}; + for (const [metricName, values] of Object.entries(visualMetrics)) { + if (!results.visualMetrics) { + results.visualMetrics = {}; + } + results.visualMetrics[metricName] = new Metric(`${metricName}`, values); + } + return results; +} + +function getCDPPerformance(data) { + const metricsToKeep = new Set([ + 'JSEventListeners', + 'LayoutCount', + 'RecalcStyleCount', + 'LayoutDuration', + 'RecalcStyleDuration', + 'ScriptDuration', + 'V8CompileDuration', + 'TaskDuration', + 'TaskOtherDuration', + 'JSHeapUsedSize' + ]); + const cdpPerformance = {}; + for (const run of data.cdp.performance) { + for (const name of Object.keys(run)) { + if (metricsToKeep.has(name)) { + if (!cdpPerformance[name]) { + cdpPerformance[name] = []; + } + cdpPerformance[name].push(decimals(run[name])); + } + } + } + + // Convert to Metric objects + const results = {}; + for (const [metricName, values] of Object.entries(cdpPerformance)) { + if (!results.cdp) { + results.cdp = {}; + } + results.cdp[metricName] = new Metric(`${metricName}`, values); + } + return results; +} + +function getCPU(data) { + const cpuMetrics = { + tasks: [], + totalDuration: [], + lastLongTask: [], + beforeFirstContentfulPaint: [], + beforeLargestContentfulPaint: [] + }; + + for (const run of data.cpu) { + const longTasks = run.longTasks; + cpuMetrics['tasks'].push(longTasks['tasks']); + cpuMetrics['totalDuration'].push(longTasks['totalDuration']); + cpuMetrics['lastLongTask'].push(longTasks['lastLongTask']); + cpuMetrics['beforeFirstContentfulPaint'].push( + longTasks['beforeFirstContentfulPaint'].totalDuration + ); + cpuMetrics['beforeLargestContentfulPaint'].push( + longTasks['beforeLargestContentfulPaint'].totalDuration + ); + } + + const isEmpty = Object.values(cpuMetrics).every(arr => arr.length === 0); + if (isEmpty) { + return {}; // Return an empty object if no data + } + + const results = {}; + for (const [metricName, values] of Object.entries(cpuMetrics)) { + if (!results.cpu) { + results.cpu = {}; + } + results.cpu[metricName] = new Metric(`${metricName}`, values); + } + return results; +} + +function getRenderBlocking(data) { + const renderBlockingMetrics = { + beforeFCPms: [], + beforeLCPms: [], + beforeFCPelements: [], + beforeLCPelements: [] + }; + + for (const run of data.renderBlocking) { + renderBlockingMetrics['beforeFCPms'].push( + run.recalculateStyle.beforeFCP.durationInMillis + ); + renderBlockingMetrics['beforeFCPelements'].push( + run.recalculateStyle.beforeFCP.elements + ); + renderBlockingMetrics['beforeLCPms'].push( + run.recalculateStyle.beforeLCP.durationInMillis + ); + renderBlockingMetrics['beforeLCPelements'].push( + run.recalculateStyle.beforeLCP.elements + ); + } + + // Check if all arrays in renderBlockingMetrics are empty + const isEmpty = Object.values(renderBlockingMetrics).every( + arr => arr.length === 0 + ); + if (isEmpty) { + return {}; // Return an empty object if no data + } + + const results = {}; + for (const [metricName, values] of Object.entries(renderBlockingMetrics)) { + if (!results.renderBlocking) { + results.renderBlocking = {}; + } + results.renderBlocking[metricName] = new Metric(`${metricName}`, values); + } + + return results; +} + +export function getMetrics(data) { + const userTimings = getUserTimings(data); + const elementTimings = getElementTimings(data); + const visualMetrics = getVisualMetrics(data); + const rb = getRenderBlocking(data); + const gWV = getGoogleWebVitals(data); + const cdp = getCDPPerformance(data); + const cpu = getCPU(data); + const timings = getTimings(data); + const extras = getExtras(data); + return { + ...extras, + ...timings, + ...cpu, + ...cdp, + ...visualMetrics, + ...gWV, + ...rb, + ...elementTimings, + ...userTimings + }; +} diff --git a/lib/plugins/compare/index.js b/lib/plugins/compare/index.js new file mode 100644 index 0000000000..b0958b07c8 --- /dev/null +++ b/lib/plugins/compare/index.js @@ -0,0 +1,229 @@ +import { fileURLToPath } from 'node:url'; +import { readFileSync } from 'node:fs'; +import { resolve, join } from 'node:path'; + +import { SitespeedioPlugin } from '@sitespeed.io/plugin'; +import intel from 'intel'; +import merge from 'lodash.merge'; +import dayjs from 'dayjs'; + +import { throwIfMissing } from '../../support/util.js'; +import { getStatistics, runStatisticalTests, getMetrics } from './helper.js'; +import { getBaseline, saveBaseline } from './baseline.js'; + +const __dirname = fileURLToPath(new URL('.', import.meta.url)); + +const log = intel.getLogger('sitespeedio.plugin.compare'); +const defaultConfig = {}; + +const TIME_FORMAT = 'YYYY-MM-DD HH:mm:ss'; + +const DEFAULT_METRICS_PAGESUMMARY = [ + 'metrics.timings.*.statisticalTestU', + 'metrics.cpu.*.statisticalTestU', + 'metrics.cdp.*.statisticalTestU', + 'metrics.visualMetrics.*.statisticalTestU', + 'metrics.googleWebVitals.*.statisticalTestU', + 'metrics.renderBlocking.*.statisticalTestU', + 'metrics.elementTimings.*.statisticalTestU', + 'metrics.userTimings.*.statisticalTestU', + 'metrics.extras.*.statisticalTestU' +]; + +export default class ComparePlugin extends SitespeedioPlugin { + constructor(options, context, queue) { + super({ name: 'compare', options, context, queue }); + } + + async open(context, options) { + this.page = 0; + this.make = context.messageMaker('compare').make; + this.compareOptions = merge({}, defaultConfig, options.compare); + this.options = options; + throwIfMissing(options.compare, ['id'], 'compare'); + this.pug = readFileSync(resolve(__dirname, 'pug', 'index.pug'), 'utf8'); + log.info( + 'Starting the compare plugin.' + + (this.compareOptions.saveBaseline + ? ' Will save this test as the baseline' + : '') + ); + if (options.browsertime.iterations < 20) { + log.warning( + 'You should use 20+ iterations to get statistical significant data' + ); + } + context.filterRegistry.registerFilterForType( + DEFAULT_METRICS_PAGESUMMARY, + 'compare.pageSummary' + ); + } + async processMessage(message) { + switch (message.type) { + case 'sitespeedio.setup': { + super.sendMessage('compare.setup'); + // Add the HTML pugs + super.sendMessage('html.pug', { + id: 'compare', + name: 'Compare', + pug: this.pug, + type: 'pageSummary' + }); + break; + } + case 'browsertime.pageSummary': { + this.page++; + const baseline = await getBaseline( + this.options.compare.id + '-' + this.page, + this.compareOptions + ); + + if (baseline) { + if ( + baseline && + this.options.browsertime.iterations !== baseline.timestamps.length + ) + log.warning( + 'The baseline test has %s runs and you current have %s. You should make sure you test the same amount of runs', + baseline.timestamps.length, + this.options.browsertime.iterations + ); + log.info( + 'Got a baseline:' + this.options.compare.id + '-' + this.page + ); + const newMetrics = getMetrics(message.data); + const baselineMetrics = getMetrics(baseline); + const metricsInputData = { + options: { + test_type: this.compareOptions.testType, + alternative: this.compareOptions.alternative + }, + metrics: {} + }; + + if (this.compareOptions.testType === 'mannwhitneyu') { + metricsInputData.options.use_continuity = + this.compareOptions.mannwhitneyu.useContinuity; + metricsInputData.options.method = + this.compareOptions.mannwhitneyu.method; + metricsInputData.options.nan_policy = 'omit'; + } else if (this.compareOptions.testType === 'wilcoxon') { + metricsInputData.options.correction = + this.compareOptions.wilcoxon.correction; + metricsInputData.options.zero_method = + this.compareOptions.wilcoxon.zeroMethod; + } + + for (let group in newMetrics) { + if (baselineMetrics[group]) { + metricsInputData.metrics[group] = {}; + for (let metricName in newMetrics[group]) { + // Ensure both current and baseline metrics are available + if ( + baselineMetrics[group][metricName] && + newMetrics[group][metricName] + ) { + // Directly access the Metric instance + const currentMetric = newMetrics[group][metricName]; + const baselineMetric = baselineMetrics[group][metricName]; + + // Ensure these are indeed Metric instances + const currentStats = getStatistics(currentMetric.getValues()); + const baselineStats = getStatistics( + baselineMetric.getValues() + ); + metricsInputData.metrics[group][metricName] = { + sample1: baselineStats.data, + sample2: currentStats.data + }; + } else { + log.info( + `Skipping ${group}.${metricName} as it's not present in both current and baseline metrics.` + ); + } + } + } + } + + const results = await runStatisticalTests(metricsInputData); + const finalResult = {}; + for (let group in results) { + finalResult[group] = {}; + for (let metricName in results[group]) { + const result = results[group][metricName]; + // Again, accessing the metricName within the group + const currentStats = getStatistics( + newMetrics[group][metricName].getValues() + ); + const baselineStats = getStatistics( + baselineMetrics[group][metricName].getValues() + ); + + finalResult[group][metricName] = { + current: { + stdev: currentStats.stddev(), + mean: currentStats.amean(), + median: currentStats.median(), + values: currentStats.data + }, + baseline: { + stdev: baselineStats.stddev(), + mean: baselineStats.amean(), + median: baselineStats.median(), + values: baselineStats.data + }, + statisticalTestU: result['p-value'] + }; + } + } + const meta = { + baseline: { + timestamp: dayjs(baseline.info.timestamp).format(TIME_FORMAT), + url: baseline.info.url, + alias: baseline.info.alias + }, + current: { + timestamp: dayjs(message.data.info.timestamp).format(TIME_FORMAT), + url: message.data.info.url, + alias: message.data.info.alias + }, + testOptions: this.compareOptions, + iterations: this.options.browsertime.iterations + }; + + if (this.compareOptions.saveBaseline) { + await saveBaseline( + message.data, + join( + this.compareOptions.baselinePath || process.cwd(), + `${this.options.compare.id}-${this.page}.json` + ) + ); + } + + super.sendMessage( + 'compare.pageSummary', + { metrics: finalResult, meta }, + { + url: message.url, + group: message.group, + runTime: message.runTime + } + ); + } else { + if (this.compareOptions.saveBaseline) { + await saveBaseline( + message.data, + join( + this.compareOptions.baselinePath || process.cwd(), + `${this.options.compare.id}-${this.page}.json` + ) + ); + } + } + + break; + } + } + } +} diff --git a/lib/plugins/compare/pug/index.pug b/lib/plugins/compare/pug/index.pug new file mode 100644 index 0000000000..c92698f6f5 --- /dev/null +++ b/lib/plugins/compare/pug/index.pug @@ -0,0 +1,135 @@ +- const compare = pageInfo.data.compare.pageSummary; + +h1 Compare + +if compare.meta.iterations < 21 + p.error + | Warning: The number of iterations (#{compare.meta.iterations}) is less than the + a(href='https://en.wikipedia.org/wiki/Mann–Whitney_U_test#Calculations') recommended minimum of 21. + | This may impact the reliability of the statistical comparison. + +p + | In this web performance comparison, statistical tests are employed to analyze the significance of performance changes between baseline and current measurements. The Mann-Whitney U test, ideal for comparing independent samples, is used when analyzing different web pages or different conditions (e.g., comparing load times of a page with and without a new optimization). The Wilcoxon signed-rank test is applied to related or paired samples, such as comparing the response times of the same website before and after applying a specific optimization technique. + +h2 Settings +p + | The test conducted in this comparison is the #{compare.meta.testOptions.testType} test. The alternative hypothesis used for this test is "#{compare.meta.testOptions.alternative}". + if compare.meta.testOptions.testType === 'mannwhitneyu' + | For more information on the settings of the Mann-Whitney U test, please refer to the + a(href='https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.mannwhitneyu.html') official documentation. + | The test was configured to use continuity (set to #{compare.meta.testOptions.mannwhitneyu.useContinuity}) and the method chosen was "#{compare.meta.testOptions.mannwhitneyu.method}". + else if compare.meta.testOptions.testType === 'wilcoxon' + | For more information on the settings of the Wilcoxon test, please refer to the + a(href='https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.wilcoxon.html') official documentation. + | For this test, a correction parameter (#{compare.meta.testOptions.wilcoxon.correction ? 'enabled' : 'disabled'}) was applied to adjust for small sample sizes. + + +p + | The baseline test + if compare.meta.baseline.alias + a(href=compare.meta.baseline.url) #{compare.meta.baseline.alias} + else + a(href=compare.meta.baseline.url) #{compare.meta.baseline.url} + | was conducted at #{compare.meta.baseline.timestamp} and the current test + if compare.meta.current.alias + a(href=compare.meta.current.url) #{compare.meta.current.alias} + else + a(href=compare.meta.current.url) #{compare.meta.current.url} + | was conducted at #{compare.meta.current.timestamp}. + + +h2 Comparison Data + +table + thead + tr + th Metric Name + th Score #{compare.meta.testOptions.testType} + th Baseline mean + th Current mean + th Baseline median + th Current median + th Baseline Std Dev + th Current Std Dev + th Significant Change? + + tbody + each metricGroup, groupName in compare.metrics + each values, metricName in metricGroup + tr + td + b #{groupName + '.' + metricName} + if values.statisticalTestU === "N/A" + td N/A + else + td #{h.decimals(values.statisticalTestU)} + td #{h.decimals(values.baseline.mean)} + td #{h.decimals(values.current.mean)} + td #{h.decimals(values.baseline.median)} + td #{h.decimals(values.current.median)} + td #{h.decimals(values.baseline.stdev)} + td #{h.decimals(values.current.stdev)} + if values.statisticalTestU === "N/A" + td No Test Conducted + else + td #{values.statisticalTestU < 0.05 ? 'Yes' : 'No'} + +h2 Graphs + +each metricGroup, groupName in compare.metrics + each values, metricName in metricGroup + - var fullMetricName = groupName + '.' + metricName + - var metricId = fullMetricName.replace(/\./g, '_') + h3 #{fullMetricName} + .ct-chart(id=`chart-${metricId}`) + .ct-legend + span.ct-legend-item + i(style='background-color: #468847')   + | Baseline: [#{values.baseline.values.join(', ')}] + .ct-legend + span.ct-legend-item + i(style='background-color: #c09853;')   + | Current: [#{values.current.values.join(', ')}] + script(type='text/javascript'). + document.addEventListener("DOMContentLoaded", function() { + var baselineData = !{JSON.stringify(values.baseline.values)}; + var currentData = !{JSON.stringify(values.current.values)}; + var metricId = '#{metricId}'; + var overlapSeriesName = 'Overlap'; + + var chartData = { + series: [ + { + name: 'Baseline', + data: baselineData.map((value, index) => ({ x: index + 1, y: value })), + className: 'baseline-series' + }, + { + name: 'Current', + data: currentData.map((value, index) => ({ x: index + 1, y: value })), + className: 'current-series' + }, + { + name: overlapSeriesName, + data: baselineData.map((value, index) => ({ x: index + 1, y: currentData[index] === value ? value : null })) + } + ] + }; + var optionsApa = { + showLine: false, + axisX: { + + }, + axisY: { + + } + }; + var chart = new Chartist.Line(`#chart-${metricId}`, chartData, optionsApa); + + // Take care of series that has the same value + chart.on('draw', function(data) { + if(data.type === 'point' && data.series.name === overlapSeriesName && data.value.y !== null) { + data.element._node.setAttribute('style', 'stroke: #59922b; stroke-width: 20px;'); + } + }); + }); diff --git a/lib/plugins/compare/statistical.py b/lib/plugins/compare/statistical.py new file mode 100644 index 0000000000..97a53fd4fd --- /dev/null +++ b/lib/plugins/compare/statistical.py @@ -0,0 +1,37 @@ +import sys +import json +from scipy.stats import wilcoxon, mannwhitneyu + +def has_variability(sample): + """Check if the sample has more than one unique value.""" + return len(set(sample)) > 1 + +def perform_test(test_type, sample1, sample2, **kwargs): + """Perform the statistical test based on the test type.""" + if not has_variability(sample1) or not has_variability(sample2): + return None, "No variability" + + if test_type == 'wilcoxon': + return wilcoxon(sample1, sample2, **kwargs) + elif test_type == 'mannwhitneyu': + return mannwhitneyu(sample1, sample2, **kwargs) + else: + raise ValueError("Invalid test type. Choose 'wilcoxon' or 'mannwhitneyu'.") + +input_data = json.loads(sys.stdin.read()) +options = input_data['options'] +test_type = options.pop('test_type') +final_results = {} + +# Iterate over each metric group in the metrics dictionary +for group_name, metrics in input_data['metrics'].items(): + group_results = {} + for metric_name, metric_data in metrics.items(): + stat, p = perform_test(test_type, metric_data['sample1'], metric_data['sample2'], **options) + if p == "No variability": + group_results[metric_name] = {'statistic': "N/A", 'p-value': "N/A"} + else: + group_results[metric_name] = {'statistic': stat, 'p-value': p} + final_results[group_name] = group_results + +print(json.dumps(final_results)) diff --git a/lib/plugins/graphite/data-generator.js b/lib/plugins/graphite/data-generator.js index 08007a82b2..a5dd7436fd 100644 --- a/lib/plugins/graphite/data-generator.js +++ b/lib/plugins/graphite/data-generator.js @@ -18,7 +18,7 @@ function keyPathFromMessage(message, options, includeQueryParameters, alias) { // always have browser and connectivity in Browsertime and related tools if ( - /(^pagexray|^coach|^browsertime|^largestassets|^slowestassets|^aggregateassets|^domains|^thirdparty|^axe|^sustainable)/.test( + /(^pagexray|^coach|^browsertime|^largestassets|^slowestassets|^aggregateassets|^domains|^thirdparty|^axe|^compare|^sustainable)/.test( message.type ) ) { diff --git a/lib/plugins/html/assets/css/index.min.css b/lib/plugins/html/assets/css/index.min.css index 38d77fa459..aa9bf14c3d 100644 --- a/lib/plugins/html/assets/css/index.min.css +++ b/lib/plugins/html/assets/css/index.min.css @@ -1 +1 @@ -/*! normalize.css v4.1.1 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block}audio:not([controls]){display:none;height:0}progress{vertical-align:baseline}[hidden],template{display:none}a{background-color:transparent;-webkit-text-decoration-skip:objects}a:active,a:hover{outline-width:0}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:inherit}b,strong{font-weight:bolder}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}svg:not(:root){overflow:hidden}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}figure{margin:1em 40px}hr{box-sizing:content-box;height:0;overflow:visible}button,input,optgroup,select,textarea{font:inherit;margin:0}optgroup{font-weight:700}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-input-placeholder{color:inherit;opacity:.54}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}*,:after,:before{box-sizing:border-box}ol,ul{margin-bottom:2.5rem}ul{margin-top:0;padding-left:0;list-style:circle inside}ul ol,ul ul{margin:1.5rem 0 1.5rem 3rem;font-size:.9rem}ol{margin-top:0;padding-left:0;list-style:decimal inside}ol ol,ol ul{margin:1.5rem 0 1.5rem 3rem;font-size:.9rem}li{margin-bottom:0}figure{margin-bottom:2.5rem}footer{text-align:center}hr{margin-top:3rem;margin-bottom:3.5rem;border-width:0;border-top:1px solid #e1e1e1}.container:after,.row:after{content:"";display:table;clear:both}.container{position:relative;width:100%;max-width:1140px;margin:0 auto;padding:0 20px;box-sizing:border-box}.column,.columns{width:100%;float:left;box-sizing:border-box}@media (min-width:400px){.container{width:85%;padding:0}}@media (min-width:550px){.container{width:80%}.column,.columns{margin-left:4%}.column:first-child,.columns:first-child{margin-left:0}.one.column,.one.columns{width:4.6666666667%}.two.columns{width:13.3333333333%}.three.columns{width:22%}.four.columns{width:30.6666666667%}.five.columns{width:39.3333333333%}.six.columns{width:48%}.seven.columns{width:56.6666666667%}.eight.columns{width:65.3333333333%}.nine.columns{width:74%}.ten.columns{width:82.6666666667%}.eleven.columns{width:91.3333333333%}.twelve.columns{width:100%;margin-left:0}.one-third.column{width:30.6666666667%}.two-thirds.column{width:65.3333333333%}.one-half.column{width:48%}.offset-by-one.column,.offset-by-one.columns{margin-left:8.6666666667%}.offset-by-two.column,.offset-by-two.columns{margin-left:17.3333333333%}.offset-by-three.column,.offset-by-three.columns{margin-left:26%}.offset-by-four.column,.offset-by-four.columns{margin-left:34.6666666667%}.offset-by-five.column,.offset-by-five.columns{margin-left:43.3333333333%}.offset-by-six.column,.offset-by-six.columns{margin-left:52%}.offset-by-seven.column,.offset-by-seven.columns{margin-left:60.6666666667%}.offset-by-eight.column,.offset-by-eight.columns{margin-left:69.3333333333%}.offset-by-nine.column,.offset-by-nine.columns{margin-left:78%}.offset-by-ten.column,.offset-by-ten.columns{margin-left:86.6666666667%}.offset-by-eleven.column,.offset-by-eleven.columns{margin-left:95.3333333333%}.offset-by-one-third.column,.offset-by-one-third.columns{margin-left:34.6666666667%}.offset-by-two-thirds.column,.offset-by-two-thirds.columns{margin-left:69.3333333333%}.offset-by-one-half.column,.offset-by-one-half.columns{margin-left:52%}}@media (min-width:1550px){.container{max-width:1400px;font-size:1.2em}}@media (min-width:1900px){.container{max-width:1800px;font-size:1.4em}}table{width:100%;margin-bottom:2.5rem;border-collapse:separate;border-spacing:1px;background-color:#e1e1e1}td,th{padding:4px 1rem;vertical-align:top;text-align:left}td:first-child,th:first-child{padding-left:1rem}td:last-child,th:last-child{padding-right:1rem}tr:nth-child(odd){background:#fafafa}tr:nth-child(2n){background:#fff}tr.odd{background:#fafafa}tr.even{background:#fff}th{background:#f1fbff}td.number,th.number{text-align:right}td.right{text-align:right}td.url{overflow-wrap:break-word;word-wrap:break-word;-webkit-hyphens:auto;-ms-hyphens:auto;-moz-hyphens:auto;hyphens:auto}td.assetsurl{max-width:400px}td.pagesurl{max-width:350px}td.offendingurl{max-width:900px}td.break{word-break:break-all}td.extraheader{font-weight:700;background:#f5f5f5}@media only screen and (max-width:800px){.responsive table,.responsive tbody,.responsive td,.responsive th,.responsive thead,.responsive tr{display:block}.responsive tr.u-hideable{display:none}.responsive thead tr{position:absolute;top:-9999px;left:-9999px}.responsive tr{border:2px solid #e1e1e1}.responsive td{border:none;border-bottom:1px solid #e1e1e1;position:relative;padding-left:50%;white-space:normal;text-align:left;max-width:none}.responsive td:before{position:absolute;top:6px;left:6px;width:30%;padding-right:10px;white-space:nowrap;text-align:left;font-weight:700}.responsive td:before{content:attr(data-title)}.responsive td.url.offendingurl{word-break:break-all;padding-left:2px}.hidden-small{display:none}}html{font-size:100%}body{font-size:1em;line-height:1.6;font-weight:400;font-family:-apple-system,BlinkMacSystemFont,"Helvetica Neue",Helvetica,Arial,sans-serif;color:#222}h1,h2,h3,h4,h5,h6{margin-top:1rem;margin-bottom:2rem;font-weight:300}h1{font-size:3rem;line-height:1.2}h2{font-size:2.8rem;line-height:1.25}h3{font-size:2.6rem;line-height:1.3}h4{font-size:2.4rem;line-height:1.35}h5{font-size:1.8rem;line-height:1.5}h6{font-size:1.5rem;line-height:1.6;letter-spacing:0}p{margin-top:0}a{color:#0095d2}a:hover{color:#00719f}blockquote,dl,p,pre{margin-bottom:2.5rem}code{padding:.2rem .5rem;margin:0 .2rem;font-size:.9rem;white-space:nowrap;background:#fafafa;border:1px solid #e1e1e1;border-radius:4px}pre>code{display:block;padding:1rem 1.5rem;white-space:pre;overflow:auto}.u-full-width{width:100%}.u-max-full-width{max-width:100%}.u-pull-right{float:right}.u-pull-left{float:left}.u-cf{content:"";display:table;clear:both}.u-hideable{display:none}.button{display:inline-block;height:38px;padding:0 30px;margin-bottom:1rem;color:#222;text-align:center;font-size:80%;font-weight:600;line-height:38px;letter-spacing:.1rem;text-transform:uppercase;text-decoration:none;white-space:nowrap;background-color:transparent;border-radius:4px;border:1px solid #e1e1e1;cursor:pointer}.button:active,.button:focus,.button:hover{color:#222;border-color:#aeaeae;outline:0}.button--primary{color:#fff;background-color:#0095d2;border-color:#0095d2}.button--primary:active,.button--primary:focus,.button--primary:hover{color:#fff;background-color:#0087be;border-color:#0087be}.button-download{color:#fff;background-color:#ec971f;border-color:#eb9316;padding:0 10px;margin-right:1rem}.button-download:active,.button-download:focus,.button-download:hover{color:#fff;background-color:#e38d13;border-color:#da8813}.navgrid{width:100%;min-width:0;margin-left:0;margin-right:0;padding-left:0;padding-right:10px}.nav{background:#0095d2}.nav ul{list-style:none;text-align:center;padding:0;margin:0;background-color:#0095d2}.nav li{line-height:40px;height:40px;border-bottom:none;margin-bottom:0}.nav a{text-decoration:none;color:#fff;display:block}.nav a:hover{background-color:#0073b0}.nav a.active{background-color:#0073b0;color:#fff;cursor:default}.logo{text-align:center;background-color:#0095d2}.navbar-brand{padding:0;font-size:18px;max-width:250px}@media screen and (min-width:820px){body{padding-top:50px}.navgrid{width:100%;max-width:1140px;min-width:755px;margin:0 auto;overflow:hidden}.nav{height:50px;width:100%;z-index:1000;position:fixed;top:0}.navbar-brand{padding:0;font-size:18px;float:left;max-width:250px}.nav{z-index:10;top:0;background-color:#0095d2}.nav a{padding-left:20px;padding-right:20px}.nav li{border-bottom:none;height:50px;line-height:50px;float:left;display:inline-block;margin-right:0}.nav a{text-decoration:none;color:#fff;display:block}.nav ul{list-style:none;text-align:center;padding:0;margin:0;background-color:#0095d2}:target:before{content:"";display:block;height:50px;margin:-50px 0 0}}@media (min-width:1550px){.nav li{font-size:1.2em}}@media (min-width:1900px){.nav li{font-size:1.4em}}table[data-sortable] th[data-sorted=true]{color:#3a87ad;background:#d9edf7;border-bottom-color:#bce8f1}table[data-sortable] th:not([data-sortable=false]){cursor:pointer;color:#222;text-decoration:underline}.summarybox{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.summarybox.ok{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.summarybox.warning{color:#c09853;background-color:#fcf8e3;border-color:#fbeed5}.summarybox.error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.summarybox.info{background-color:#d9edf7;border-color:#bce8f1;color:#3a87ad}a.summaries{text-decoration:none}.summarynumber{font-size:2rem;line-height:1;font-weight:700}.summarysmall{font-size:1rem;line-height:1}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}.normal{font-size:100%}.ok{background-color:#468847}.warning{background-color:#f0ad4e}.error{background-color:#d9534f}.info{background-color:#0095d2}ul.menu{list-style:none;font-size:125%;text-transform:uppercase}.errors{margin-bottom:1.333em;background:#ffb6c1;padding-left:1em}.subtableheader{background:#ffe3eb}.large{font-size:1.333rem;line-height:1.8rem}.hidden-small{display:inline}.url{overflow-wrap:break-word;word-wrap:break-word;-webkit-hyphens:auto;-ms-hyphens:auto;-moz-hyphens:auto;hyphens:auto}/*! github.com/micmro/PerfCascade Version:2.11.0 (24/11/2021) */.water-fall-chart{width:100%;overflow:visible;font-size:12px;line-height:1em}.water-fall-chart *{box-sizing:border-box}.water-fall-chart button{cursor:pointer}.water-fall-holder{fill:#ccc}.water-fall-chart .left-fixed-holder{overflow:visible}.water-fall-chart .marker-holder{width:100%}.water-fall-chart .line-label-holder{cursor:pointer}.water-fall-chart .line-holder{stroke-width:1;stroke:#ccc;stroke-opacity:0.5;transition:all 60ms}.water-fall-chart .line-holder .line-mark{fill:#69009e;opacity:.01;stroke-width:0;transition:all 60ms}.water-fall-chart .line-holder.active{stroke:#69009e;stroke-width:2;stroke-opacity:1}.water-fall-chart .line-holder.active .line-mark{opacity:.4}.water-fall-chart .type-onload .line-holder{stroke:#c0c0ff}.water-fall-chart .type-oncontentload .line-holder{stroke:#d888df}.water-fall-chart .labels{width:100%}.water-fall-chart .labels .inner-label{pointer-events:none}.water-fall-chart .time-block.active{opacity:.8}.water-fall-chart .line-end,.water-fall-chart .line-start{display:none;stroke-width:1;stroke-opacity:0.5;stroke:#000}.water-fall-chart .line-end.active,.water-fall-chart .line-start.active{display:block}.left-fixed-holder .label-full-bg{fill:#fff;opacity:.9}.time-scale line{stroke:#0cc;stroke-width:1}.time-scale line.sub-second-line{stroke:#ccc;opacity:.75;stroke-width:.5}.time-scale text{font-weight:700}.row-item{cursor:pointer}.row-item .even{fill:#ccc;opacity:.05}.row-item .odd{fill:#000;opacity:.05}.row-item:hover .even,.row-item:hover .odd{fill:#000;opacity:.1}.row-item:focus{outline:solid 1.5px #aaa;outline-offset:-1.5px}.row-item:focus .even,.row-item:focus .odd{fill:#000;opacity:.2}.row-item .rect-holder text{fill:#aaa}.row-item.status0 .even,.row-item.status5xx .even{fill:#f66}.row-item.status0 .odd,.row-item.status5xx .odd{fill:#f00}.row-item.status4xx .even{fill:#c33}.row-item.status4xx .odd{fill:#c00}.row-item.status3xx .even{fill:#ff6}.row-item.status3xx .odd{fill:#ff0}.row-item.potentiallyRenderBlocking .even,.row-item.potentiallyRenderBlocking .odd{fill:#e5a331}.row-item.renderBlocking .even,.row-item.renderBlocking .odd{fill:#e57231;stroke-dasharray:5;stroke:black;stroke-width:2px}.row-item.largestContentfulPaint .even,.row-item.largestContentfulPaint .odd{fill:#c9e531;stroke-dasharray:8;stroke-width:2px;stroke:black}.row-item.largestContentfulPaint .even,.row-item.largestContentfulPaint .odd,.row-item.potentiallyRenderBlocking .even,.row-item.potentiallyRenderBlocking .odd,.row-item.renderBlocking .even,.row-item.renderBlocking .odd,.row-item.status0 .even,.row-item.status0 .odd,.row-item.status3xx .even,.row-item.status3xx .odd,.row-item.status4xx .even,.row-item.status4xx .odd,.row-item.status5xx .even,.row-item.status5xx .odd{opacity:.3}.row-item.largestContentfulPaint:hover .even,.row-item.largestContentfulPaint:hover .odd,.row-item.potentiallyRenderBlocking:hover .even,.row-item.potentiallyRenderBlocking:hover .odd,.row-item.renderBlocking:hover .even,.row-item.renderBlocking:hover .odd,.row-item.status0:hover .even,.row-item.status0:hover .odd,.row-item.status3xx:hover .even,.row-item.status3xx:hover .odd,.row-item.status4xx:hover .even,.row-item.status4xx:hover .odd,.row-item.status5xx:hover .even,.row-item.status5xx:hover .odd{opacity:.5}.tooltip-holder{overflow:visible}.tooltip *{padding:0;margin:0}.tooltip html{font-size:10px;line-height:1.2em}.tooltip body{position:relative}.tooltip-payload{position:absolute;top:0;left:0;padding:.25em;font-size:10px;display:inline-block;background:rgba(255,255,255,.9);border:solid 1px #f0f0f0;word-break:break-all;overflow-wrap:break-word;transition:opacity .3s}.tooltip-payload.no-anim{transition:none}.row-item,.time-scale line,.time-scale text,.water-fall-chart .line-holder line,.water-fall-chart .line-label-holder{transition:transform 60ms}.water-fall-chart.closing{transition-delay:60ms}.labels{overflow:hidden}.block-css{fill:#a6d18f}.block-html,.block-iframe,.block-internal,.block-svg{fill:#82a8de}.block-image,.block-img{fill:#b394cf}.block-javascript,.block-js,.block-script{fill:#e0b483}.block-link{fill:#89afe6}.block-flash,.block-swf{fill:#42aab1}.block-font{fill:#e15d4e}.block-ajax,.block-xmlhttprequest{fill:#f00}.block-other,.block-plain{fill:#b3b3b3}.block-blocked{fill:#aaa}.block-dns{fill:#159588}.block-connect{fill:#fd9727}.block-ssl{fill:#c141cd}.block-send{fill:#b0bec5}.block-wait{fill:#1ec659}.block-receive{fill:#1eaaf1}.block-receive-chunk{fill:#a1c3fa}.block-undefined{fill:#0f0}.info-overlay-bg{fill:#fff;stroke:#cdcdcd}.info-overlay-close-btn{fill:rgba(205,205,205,0.8);transform:translate(-23px,-23px);cursor:pointer}.info-overlay-close-btn text{fill:#111;pointer-events:none}.info-overlay-close-btn:focus{border:solid 1px #36c}.info-overlay-holder .connect{border-right:solid 5px #fd9727;padding-right:5px}.info-overlay-holder .blocked{border-right:solid 5px #aaa;padding-right:5px}.info-overlay-holder .ssltls{border-right:solid 5px #c141cd;padding-right:5px}.info-overlay-holder .send{border-right:solid 5px #b0bec5;padding-right:5px}.info-overlay-holder .wait{border-right:solid 5px #1ec659;padding-right:5px}.info-overlay-holder .receive{border-right:solid 5px #1eaaf1;padding-right:5px}.info-overlay-holder .dns{border-right:solid 5px #159588;padding-right:5px}.type-css{background:#406b29}.type-html,.type-iframe,.type-internal,.type-svg{background:#1c4278}.type-image,.type-img{background:#4d2e69}.type-javascript,.type-js,.type-script{background:#7a4e1d}.type-link{background:#89afe6}.type-flash,.type-swf{background:#234980}.type-font{background:#ae2a1b}.type-ajax,.type-xmlhttprequest{background:#c00}.type-other,.type-plain{background:grey}.info-overlay-holder *{padding:0;margin:0;font-size:12px}.info-overlay-holder body{position:relative;height:450px;clear:both;padding:0;margin:0;width:100%;background:#fff;color:#666}.info-overlay-holder body .wrapper{height:450px;width:100%;overflow:scroll}.info-overlay-holder header{position:relative;box-shadow:0 0 2px 2px rgba(0,0,0,.25)}.info-overlay-holder header,.info-overlay-holder header a,.info-overlay-holder header button{color:#fff;text-decoration:none}.info-overlay-holder header a:focus,.info-overlay-holder header a:hover{text-decoration:underline}.info-overlay-holder .requestID{font-weight:700}.info-overlay-holder h3,.info-overlay-holder h3 a{font-size:1.1em;padding:1em;margin:0;font-weight:400;overflow-wrap:break-word}.info-overlay-holder h3 strong{font-size:1.1em}.info-overlay-holder .tab-nav ul{margin:0;padding:0}.info-overlay-holder .tab-nav li{margin:0;padding:0;display:inline-block}.info-overlay-holder button{background:0 0;outline:0;border:0;border-bottom:solid 2px transparent;padding:.5em 1em;margin:0 .25em}.info-overlay-holder li:first-child button{margin-left:1em}.info-overlay-holder button.active:focus,.info-overlay-holder button:focus,.info-overlay-holder button:hover{border-color:rgba(255,255,255,.6)}.info-overlay-holder button.active{border-color:#fff;cursor:default}.info-overlay-holder button.active:focus{border-color:rgba(255,255,255,.8)}.info-overlay-holder button.copy-tab-data{position:absolute;top:.5em;right:.5em;border:0;margin:0;border-radius:1em;background:#e0e0e0}.info-overlay-holder button.copy-tab-data:focus,.info-overlay-holder button.copy-tab-data:hover{background:#ccc}.info-overlay-holder dt{float:left;clear:both;margin-top:.5em;width:25%;text-align:right;font-weight:700}.info-overlay-holder dd{float:left;width:73%;margin:.5em 0 0 2%;padding:0 0 .5em 0}.info-overlay-holder dt:after{content:":"}.info-overlay-holder pre{font-size:11px;line-height:23px;border-radius:0;background:#f6f3f3}.info-overlay-holder .tab{float:left;position:relative;width:100%;height:350px;padding:12px 12px 24px}.info-overlay-holder .tab h2{font-size:1.2em;margin:.5em 0 0;padding:.5em 0 .5em 1em;clear:both;border-top:solid 1px #efefef}.info-overlay-holder .tab h2:first-child{border-top:0;padding-top:0}.info-overlay-holder .tab pre{overflow-y:hidden;width:100%;min-height:100%}.info-overlay-holder .tab .preview{width:auto;max-width:100%;max-height:500px;border:solid 1px #666}.info-overlay-holder .tab dl:after{content:"";display:table;clear:both}.info-overlay-holder .tab.rendered-data{padding:0}.info-overlay-holder .tab.rendered-data pre{padding:12px 12px 24px}.info-overlay-holder .tab.rendered-data pre>code{white-space:pre-wrap}.resource-legend{margin:0;padding:0;font-size:.75em;line-height:1.5em;display:inline-block}.resource-legend li{margin:0 1em 0 0;padding:0;white-space:nowrap;display:inline-block}.resource-legend li:before{content:"";width:1em;height:1em;margin:0 .5em 0 0;vertical-align:text-top;display:inline-block}.resource-legend .legend-blocked:before{background:#aaa}.resource-legend .legend-dns:before{background:#159588}.resource-legend .legend-connect:before{background:#fd9727}.resource-legend .legend-ssl:before{background:#c141cd}.resource-legend .legend-send:before{background:#b0bec5}.resource-legend .legend-wait:before{background:#1ec659}.resource-legend .legend-receive:before{background:#1eaaf1}.icon{fill:#666}.icon-4xx,.icon-5xx,.icon-no-cache,.icon-no-gzip,.icon-warning{fill:#b55}.water-fall-chart .type-firstpaint .line-holder{stroke:#42f46e;stroke-opacity:1;stroke-width:3}.water-fall-chart .type-firstvisualchange .line-holder{stroke:#42f46e;stroke-opacity:1;stroke-width:3}.water-fall-chart .type-visualcomplete85 .line-holder{stroke:#ee7777;stroke-opacity:1;stroke-width:3}.water-fall-chart .type-lastvisualchange .line-holder{stroke:#ee42f4;stroke-opacity:1;stroke-width:3}.water-fall-chart .type-onload .line-holder{stroke:#9c99e5;stroke-opacity:1;stroke-width:3}.water-fall-chart .type-oncontentload .line-holder{stroke:#9842f4;stroke-opacity:1;stroke-width:3}.water-fall-chart .type-dominteractivetime .line-holder{stroke:#1842f4;stroke-opacity:1;stroke-width:2}.water-fall-chart .type-domcontentloadedtime .line-holder{stroke:#1212f4;stroke-opacity:1;stroke-width:2}.water-fall-chart .type-lastcpulongtask .line-holder{stroke:#f41229;stroke-opacity:1;stroke-width:3}.water-fall-chart .type-largestcontentfulpaint .line-holder{stroke:#c7f412;stroke-opacity:1;stroke-width:3}.water-fall-chart{font-size:14px}#page-selector{display:none;clear:both;margin:1em 0}*{box-sizing:border-box}@media screen and (max-width:400px){select{max-width:100%}}.screenshot{padding:4px;background-color:#fff;border:1px solid #ddd;border-radius:4px}*,:after,:before{margin:0;padding:0;box-sizing:border-box}section{display:block;padding:20px 0 0;border-top:1px solid #ddd}#tabs a{display:inline-block;margin:0 0 -1px;padding:15px 22px;font-weight:600;text-align:center;color:#bbb;border:1px solid transparent;text-decoration:none;text-transform:uppercase}#tabs a:before{font-weight:400}#tabs a:hover{color:#888;cursor:pointer}#tabs a:target:focus{outline:0}#tabs a[selected]{color:#555;border:1px solid #ddd;border-top:2px solid #0095d2;border-bottom:1px solid #fff}@media screen and (max-width:650px){#tabs a:before{margin:0;font-size:18px}}@media screen and (max-width:400px){#tabs a{padding:13px}}.group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd;font-weight:700}.group-item.active{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7}.group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.loader,.loader:after,.loader:before{background:#000;-webkit-animation:load1 1s infinite ease-in-out;animation:load1 1s infinite ease-in-out;width:1em;height:4em}.loader{color:#000;text-indent:-9999em;margin:88px auto;position:relative;font-size:11px;-webkit-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0);-webkit-animation-delay:-.16s;animation-delay:-.16s}.loader:after,.loader:before{position:absolute;top:0;content:""}.loader:before{left:-1.5em;-webkit-animation-delay:-.32s;animation-delay:-.32s}.loader:after{left:1.5em}@-webkit-keyframes load1{0%,100%,80%{box-shadow:0 0;height:4em}40%{box-shadow:0 -2em;height:5em}}@keyframes load1{0%,100%,80%{box-shadow:0 0;height:4em}40%{box-shadow:0 -2em;height:5em}}.ct-label{fill:rgba(0,0,0,0.4);color:rgba(0,0,0,.4);font-size:.75rem;line-height:1}.ct-chart-bar .ct-label,.ct-chart-line .ct-label{display:block;display:-webkit-box;display:-moz-box;display:-ms-flexbox;display:-webkit-flex;display:flex}.ct-chart-donut .ct-label,.ct-chart-pie .ct-label{dominant-baseline:central}.ct-label.ct-horizontal.ct-start{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-label.ct-horizontal.ct-end{-webkit-box-align:flex-start;-webkit-align-items:flex-start;-ms-flex-align:flex-start;align-items:flex-start;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-label.ct-vertical.ct-start{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:flex-end;-webkit-justify-content:flex-end;-ms-flex-pack:flex-end;justify-content:flex-end;text-align:right;text-anchor:end}.ct-label.ct-vertical.ct-end{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-chart-bar .ct-label.ct-horizontal.ct-start{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;text-align:center;text-anchor:start}.ct-chart-bar .ct-label.ct-horizontal.ct-end{-webkit-box-align:flex-start;-webkit-align-items:flex-start;-ms-flex-align:flex-start;align-items:flex-start;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;text-align:center;text-anchor:start}.ct-chart-bar.ct-horizontal-bars .ct-label.ct-horizontal.ct-start{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-chart-bar.ct-horizontal-bars .ct-label.ct-horizontal.ct-end{-webkit-box-align:flex-start;-webkit-align-items:flex-start;-ms-flex-align:flex-start;align-items:flex-start;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-chart-bar.ct-horizontal-bars .ct-label.ct-vertical.ct-start{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:flex-end;-webkit-justify-content:flex-end;-ms-flex-pack:flex-end;justify-content:flex-end;text-align:right;text-anchor:end}.ct-chart-bar.ct-horizontal-bars .ct-label.ct-vertical.ct-end{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:end}.ct-grid{stroke:rgba(0,0,0,0.2);stroke-width:1px;stroke-dasharray:2px}.ct-grid-background{fill:none}.ct-point{stroke-width:10px;stroke-linecap:round}.ct-line{fill:none;stroke-width:4px}.ct-area{stroke:none;fill-opacity:0.1}.ct-bar{fill:none;stroke-width:10px}.ct-slice-donut{fill:none;stroke-width:60px}.ct-series-a .ct-bar,.ct-series-a .ct-line,.ct-series-a .ct-point,.ct-series-a .ct-slice-donut{stroke:#d70206}.ct-series-a .ct-area,.ct-series-a .ct-slice-donut-solid,.ct-series-a .ct-slice-pie{fill:#d70206}.ct-series-b .ct-bar,.ct-series-b .ct-line,.ct-series-b .ct-point,.ct-series-b .ct-slice-donut{stroke:#f05b4f}.ct-series-b .ct-area,.ct-series-b .ct-slice-donut-solid,.ct-series-b .ct-slice-pie{fill:#f05b4f}.ct-series-c .ct-bar,.ct-series-c .ct-line,.ct-series-c .ct-point,.ct-series-c .ct-slice-donut{stroke:#f4c63d}.ct-series-c .ct-area,.ct-series-c .ct-slice-donut-solid,.ct-series-c .ct-slice-pie{fill:#f4c63d}.ct-series-d .ct-bar,.ct-series-d .ct-line,.ct-series-d .ct-point,.ct-series-d .ct-slice-donut{stroke:#d17905}.ct-series-d .ct-area,.ct-series-d .ct-slice-donut-solid,.ct-series-d .ct-slice-pie{fill:#d17905}.ct-series-e .ct-bar,.ct-series-e .ct-line,.ct-series-e .ct-point,.ct-series-e .ct-slice-donut{stroke:#453d3f}.ct-series-e .ct-area,.ct-series-e .ct-slice-donut-solid,.ct-series-e .ct-slice-pie{fill:#453d3f}.ct-series-f .ct-bar,.ct-series-f .ct-line,.ct-series-f .ct-point,.ct-series-f .ct-slice-donut{stroke:#59922b}.ct-series-f .ct-area,.ct-series-f .ct-slice-donut-solid,.ct-series-f .ct-slice-pie{fill:#59922b}.ct-series-g .ct-bar,.ct-series-g .ct-line,.ct-series-g .ct-point,.ct-series-g .ct-slice-donut{stroke:#0544d3}.ct-series-g .ct-area,.ct-series-g .ct-slice-donut-solid,.ct-series-g .ct-slice-pie{fill:#0544d3}.ct-series-h .ct-bar,.ct-series-h .ct-line,.ct-series-h .ct-point,.ct-series-h .ct-slice-donut{stroke:#6b0392}.ct-series-h .ct-area,.ct-series-h .ct-slice-donut-solid,.ct-series-h .ct-slice-pie{fill:#6b0392}.ct-series-i .ct-bar,.ct-series-i .ct-line,.ct-series-i .ct-point,.ct-series-i .ct-slice-donut{stroke:#f05b4f}.ct-series-i .ct-area,.ct-series-i .ct-slice-donut-solid,.ct-series-i .ct-slice-pie{fill:#f05b4f}.ct-series-j .ct-bar,.ct-series-j .ct-line,.ct-series-j .ct-point,.ct-series-j .ct-slice-donut{stroke:#dda458}.ct-series-j .ct-area,.ct-series-j .ct-slice-donut-solid,.ct-series-j .ct-slice-pie{fill:#dda458}.ct-series-k .ct-bar,.ct-series-k .ct-line,.ct-series-k .ct-point,.ct-series-k .ct-slice-donut{stroke:#eacf7d}.ct-series-k .ct-area,.ct-series-k .ct-slice-donut-solid,.ct-series-k .ct-slice-pie{fill:#eacf7d}.ct-series-l .ct-bar,.ct-series-l .ct-line,.ct-series-l .ct-point,.ct-series-l .ct-slice-donut{stroke:#86797d}.ct-series-l .ct-area,.ct-series-l .ct-slice-donut-solid,.ct-series-l .ct-slice-pie{fill:#86797d}.ct-series-m .ct-bar,.ct-series-m .ct-line,.ct-series-m .ct-point,.ct-series-m .ct-slice-donut{stroke:#b2c326}.ct-series-m .ct-area,.ct-series-m .ct-slice-donut-solid,.ct-series-m .ct-slice-pie{fill:#b2c326}.ct-series-n .ct-bar,.ct-series-n .ct-line,.ct-series-n .ct-point,.ct-series-n .ct-slice-donut{stroke:#6188e2}.ct-series-n .ct-area,.ct-series-n .ct-slice-donut-solid,.ct-series-n .ct-slice-pie{fill:#6188e2}.ct-series-o .ct-bar,.ct-series-o .ct-line,.ct-series-o .ct-point,.ct-series-o .ct-slice-donut{stroke:#a748ca}.ct-series-o .ct-area,.ct-series-o .ct-slice-donut-solid,.ct-series-o .ct-slice-pie{fill:#a748ca}.ct-square{display:block;position:relative;width:100%}.ct-square:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:100%}.ct-square:after{content:"";display:table;clear:both}.ct-square>svg{display:block;position:absolute;top:0;left:0}.ct-minor-second{display:block;position:relative;width:100%}.ct-minor-second:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:93.75%}.ct-minor-second:after{content:"";display:table;clear:both}.ct-minor-second>svg{display:block;position:absolute;top:0;left:0}.ct-major-second{display:block;position:relative;width:100%}.ct-major-second:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:88.8888888889%}.ct-major-second:after{content:"";display:table;clear:both}.ct-major-second>svg{display:block;position:absolute;top:0;left:0}.ct-minor-third{display:block;position:relative;width:100%}.ct-minor-third:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:83.3333333333%}.ct-minor-third:after{content:"";display:table;clear:both}.ct-minor-third>svg{display:block;position:absolute;top:0;left:0}.ct-major-third{display:block;position:relative;width:100%}.ct-major-third:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:80%}.ct-major-third:after{content:"";display:table;clear:both}.ct-major-third>svg{display:block;position:absolute;top:0;left:0}.ct-perfect-fourth{display:block;position:relative;width:100%}.ct-perfect-fourth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:75%}.ct-perfect-fourth:after{content:"";display:table;clear:both}.ct-perfect-fourth>svg{display:block;position:absolute;top:0;left:0}.ct-perfect-fifth{display:block;position:relative;width:100%}.ct-perfect-fifth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:66.6666666667%}.ct-perfect-fifth:after{content:"";display:table;clear:both}.ct-perfect-fifth>svg{display:block;position:absolute;top:0;left:0}.ct-minor-sixth{display:block;position:relative;width:100%}.ct-minor-sixth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:62.5%}.ct-minor-sixth:after{content:"";display:table;clear:both}.ct-minor-sixth>svg{display:block;position:absolute;top:0;left:0}.ct-golden-section{display:block;position:relative;width:100%}.ct-golden-section:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:61.804697157%}.ct-golden-section:after{content:"";display:table;clear:both}.ct-golden-section>svg{display:block;position:absolute;top:0;left:0}.ct-major-sixth{display:block;position:relative;width:100%}.ct-major-sixth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:60%}.ct-major-sixth:after{content:"";display:table;clear:both}.ct-major-sixth>svg{display:block;position:absolute;top:0;left:0}.ct-minor-seventh{display:block;position:relative;width:100%}.ct-minor-seventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:56.25%}.ct-minor-seventh:after{content:"";display:table;clear:both}.ct-minor-seventh>svg{display:block;position:absolute;top:0;left:0}.ct-major-seventh{display:block;position:relative;width:100%}.ct-major-seventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:53.3333333333%}.ct-major-seventh:after{content:"";display:table;clear:both}.ct-major-seventh>svg{display:block;position:absolute;top:0;left:0}.ct-octave{display:block;position:relative;width:100%}.ct-octave:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:50%}.ct-octave:after{content:"";display:table;clear:both}.ct-octave>svg{display:block;position:absolute;top:0;left:0}.ct-major-tenth{display:block;position:relative;width:100%}.ct-major-tenth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:40%}.ct-major-tenth:after{content:"";display:table;clear:both}.ct-major-tenth>svg{display:block;position:absolute;top:0;left:0}.ct-major-eleventh{display:block;position:relative;width:100%}.ct-major-eleventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:37.5%}.ct-major-eleventh:after{content:"";display:table;clear:both}.ct-major-eleventh>svg{display:block;position:absolute;top:0;left:0}.ct-major-twelfth{display:block;position:relative;width:100%}.ct-major-twelfth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:33.3333333333%}.ct-major-twelfth:after{content:"";display:table;clear:both}.ct-major-twelfth>svg{display:block;position:absolute;top:0;left:0}.ct-double-octave{display:block;position:relative;width:100%}.ct-double-octave:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:25%}.ct-double-octave:after{content:"";display:table;clear:both}.ct-double-octave>svg{display:block;position:absolute;top:0;left:0}.chartist-tooltip{position:absolute;display:inline-block;opacity:0;min-width:5em;padding:.5em;background:#f4c63d;color:#453d3f;font-family:Oxygen,Helvetica,Arial,sans-serif;font-weight:700;text-align:center;pointer-events:none;z-index:1;-webkit-transition:opacity .2s linear;-moz-transition:opacity .2s linear;-o-transition:opacity .2s linear;transition:opacity .2s linear}.chartist-tooltip:before{content:"";position:absolute;top:100%;left:50%;width:0;height:0;margin-left:-15px;border:15px solid transparent;border-top-color:#f4c63d}.chartist-tooltip.tooltip-show{opacity:1}.ct-area,.ct-line{pointer-events:none}.chartist-tooltip{background:#0095d2;color:#fff}.chartist-tooltip:before{border-top-color:#0095d2}.ct-bar{stroke-width:16px}.ct-series-a .ct-bar,.ct-series-a .ct-line,.ct-series-a .ct-point,.ct-series-a .ct-slice-donut{stroke:#82b5fc}.ct-series-a .ct-area,.ct-series-a .ct-slice-donut-solid,.ct-series-a .ct-slice-pie{fill:#468847}.ct-series-b .ct-bar,.ct-series-b .ct-line,.ct-series-b .ct-point,.ct-series-b .ct-slice-donut{stroke:#b2ea94}.ct-series-b .ct-area,.ct-series-b .ct-slice-donut-solid,.ct-series-b .ct-slice-pie{fill:#c09853}.ct-series-c .ct-bar,.ct-series-c .ct-line,.ct-series-c .ct-point,.ct-series-c .ct-slice-donut{stroke:#fec584}.ct-series-c .ct-area,.ct-series-c .ct-slice-donut-solid,.ct-series-c .ct-slice-pie{fill:#b94a48}.ct-series-d .ct-bar,.ct-series-d .ct-line,.ct-series-d .ct-point,.ct-series-d .ct-slice-donut{stroke:#c49ae8}.ct-series-d .ct-area,.ct-series-d .ct-slice-donut-solid,.ct-series-d .ct-slice-pie{fill:#c49ae8}.ct-series-e .ct-bar,.ct-series-e .ct-line,.ct-series-e .ct-point,.ct-series-e .ct-slice-donut{stroke:#ff523e}.ct-series-e .ct-area,.ct-series-e .ct-slice-donut-solid,.ct-series-e .ct-slice-pie{fill:#ff523e}.ct-series-f .ct-bar,.ct-series-f .ct-line,.ct-series-f .ct-point,.ct-series-f .ct-slice-donut{stroke:#c4c4c4}.ct-series-f .ct-area,.ct-series-f .ct-slice-donut-solid,.ct-series-f .ct-slice-pie{fill:#c4c4c4}.ct-series-g .ct-bar,.ct-series-g .ct-line,.ct-series-g .ct-point,.ct-series-g .ct-slice-donut{stroke:#c4c4c4}.ct-series-g .ct-area,.ct-series-g .ct-slice-donut-solid,.ct-series-g .ct-slice-pie{fill:#c4c4c4}.ct-series-h .ct-bar,.ct-series-h .ct-line,.ct-series-h .ct-point,.ct-series-h .ct-slice-donut{stroke:#c4c4c4}.ct-series-h .ct-area,.ct-series-h .ct-slice-donut-solid,.ct-series-h .ct-slice-pie{fill:#c4c4c4}.ct-series-i .ct-bar,.ct-series-i .ct-line,.ct-series-i .ct-point,.ct-series-i .ct-slice-donut{stroke:#EAB839}.ct-series-i .ct-area,.ct-series-i .ct-slice-donut-solid,.ct-series-i .ct-slice-pie{fill:#EAB839}.ct-chart .ct-legend{position:relative;z-index:10;list-style:none;text-align:left;line-height:.8;font-size:.8em}.ct-chart .ct-legend li{padding-left:23px;margin-right:10px;margin-bottom:3px;cursor:pointer}.ct-chart .ct-legend li:before{width:12px;height:12px;position:absolute;left:0;content:"";border:3px solid transparent;border-radius:2px}.ct-chart .ct-legend li .inactive:before{background:0 0}.ct-chart .ct-legend li:first-child::before{background-color:#468847}.ct-chart .ct-legend li:nth-child(2)::before{background-color:#c09853}.ct-chart .ct-legend li:nth-child(3)::before{background-color:#b94a48}.ct-chart .ct-legend .ct-legend-inside{position:absolute;top:0;right:0}.ct-chart g:not(.ct-grids):not(.ct-labels) g:first-child .ct-line,.ct-chart g:not(.ct-grids):not(.ct-labels) g:first-child .ct-point{stroke:#468847}.ct-chart g:not(.ct-grids):not(.ct-labels) g:nth-child(2) .ct-line,.ct-chart g:not(.ct-grids):not(.ct-labels) g:nth-child(2) .ct-point{stroke:#c09853}.ct-chart g:not(.ct-grids):not(.ct-labels) g:nth-child(3) .ct-line,.ct-chart g:not(.ct-grids):not(.ct-labels) g:nth-child(3) .ct-point{stroke:#b94a48}.filmstrip{padding-bottom:20px}.videoframe{vertical-align:top;display:inline-block;padding:4px;background-color:#fff;border:1px solid #ddd;border-radius:4px;width:100%}.videoframe.blue{border:2px solid #0095d2}.videoframetime{text-align:center;display:block}.videoframetext{text-align:left;display:block;line-height:1.2em;font-size:.8em;white-space:nowrap;margin-bottom:.2em} \ No newline at end of file +/*! normalize.css v4.1.1 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block}audio:not([controls]){display:none;height:0}progress{vertical-align:baseline}[hidden],template{display:none}a{background-color:transparent;-webkit-text-decoration-skip:objects}a:active,a:hover{outline-width:0}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:inherit}b,strong{font-weight:bolder}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}svg:not(:root){overflow:hidden}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}figure{margin:1em 40px}hr{box-sizing:content-box;height:0;overflow:visible}button,input,optgroup,select,textarea{font:inherit;margin:0}optgroup{font-weight:700}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-input-placeholder{color:inherit;opacity:.54}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}*,:after,:before{box-sizing:border-box}ol,ul{margin-bottom:2.5rem}ul{margin-top:0;padding-left:0;list-style:circle inside}ul ol,ul ul{margin:1.5rem 0 1.5rem 3rem;font-size:.9rem}ol{margin-top:0;padding-left:0;list-style:decimal inside}ol ol,ol ul{margin:1.5rem 0 1.5rem 3rem;font-size:.9rem}li{margin-bottom:0}figure{margin-bottom:2.5rem}footer{text-align:center}hr{margin-top:3rem;margin-bottom:3.5rem;border-width:0;border-top:1px solid #e1e1e1}.container:after,.row:after{content:"";display:table;clear:both}.container{position:relative;width:100%;max-width:1140px;margin:0 auto;padding:0 20px;box-sizing:border-box}.column,.columns{width:100%;float:left;box-sizing:border-box}@media (min-width:400px){.container{width:85%;padding:0}}@media (min-width:550px){.container{width:80%}.column,.columns{margin-left:4%}.column:first-child,.columns:first-child{margin-left:0}.one.column,.one.columns{width:4.6666666667%}.two.columns{width:13.3333333333%}.three.columns{width:22%}.four.columns{width:30.6666666667%}.five.columns{width:39.3333333333%}.six.columns{width:48%}.seven.columns{width:56.6666666667%}.eight.columns{width:65.3333333333%}.nine.columns{width:74%}.ten.columns{width:82.6666666667%}.eleven.columns{width:91.3333333333%}.twelve.columns{width:100%;margin-left:0}.one-third.column{width:30.6666666667%}.two-thirds.column{width:65.3333333333%}.one-half.column{width:48%}.offset-by-one.column,.offset-by-one.columns{margin-left:8.6666666667%}.offset-by-two.column,.offset-by-two.columns{margin-left:17.3333333333%}.offset-by-three.column,.offset-by-three.columns{margin-left:26%}.offset-by-four.column,.offset-by-four.columns{margin-left:34.6666666667%}.offset-by-five.column,.offset-by-five.columns{margin-left:43.3333333333%}.offset-by-six.column,.offset-by-six.columns{margin-left:52%}.offset-by-seven.column,.offset-by-seven.columns{margin-left:60.6666666667%}.offset-by-eight.column,.offset-by-eight.columns{margin-left:69.3333333333%}.offset-by-nine.column,.offset-by-nine.columns{margin-left:78%}.offset-by-ten.column,.offset-by-ten.columns{margin-left:86.6666666667%}.offset-by-eleven.column,.offset-by-eleven.columns{margin-left:95.3333333333%}.offset-by-one-third.column,.offset-by-one-third.columns{margin-left:34.6666666667%}.offset-by-two-thirds.column,.offset-by-two-thirds.columns{margin-left:69.3333333333%}.offset-by-one-half.column,.offset-by-one-half.columns{margin-left:52%}}@media (min-width:1550px){.container{max-width:1400px;font-size:1.2em}}@media (min-width:1900px){.container{max-width:1800px;font-size:1.4em}}table{width:100%;margin-bottom:2.5rem;border-collapse:separate;border-spacing:1px;background-color:#e1e1e1}td,th{padding:4px 1rem;vertical-align:top;text-align:left}td:first-child,th:first-child{padding-left:1rem}td:last-child,th:last-child{padding-right:1rem}tr:nth-child(odd){background:#fafafa}tr:nth-child(2n){background:#fff}tr.odd{background:#fafafa}tr.even{background:#fff}th{background:#f1fbff}td.number,th.number{text-align:right}td.right{text-align:right}td.url{overflow-wrap:break-word;word-wrap:break-word;-webkit-hyphens:auto;-ms-hyphens:auto;-moz-hyphens:auto;hyphens:auto}td.assetsurl{max-width:400px}td.pagesurl{max-width:350px}td.offendingurl{max-width:900px}td.break{word-break:break-all}td.extraheader{font-weight:700;background:#f5f5f5}@media only screen and (max-width:800px){.responsive table,.responsive tbody,.responsive td,.responsive th,.responsive thead,.responsive tr{display:block}.responsive tr.u-hideable{display:none}.responsive thead tr{position:absolute;top:-9999px;left:-9999px}.responsive tr{border:2px solid #e1e1e1}.responsive td{border:none;border-bottom:1px solid #e1e1e1;position:relative;padding-left:50%;white-space:normal;text-align:left;max-width:none}.responsive td:before{position:absolute;top:6px;left:6px;width:30%;padding-right:10px;white-space:nowrap;text-align:left;font-weight:700}.responsive td:before{content:attr(data-title)}.responsive td.url.offendingurl{word-break:break-all;padding-left:2px}.hidden-small{display:none}}html{font-size:100%}body{font-size:1em;line-height:1.6;font-weight:400;font-family:-apple-system,BlinkMacSystemFont,"Helvetica Neue",Helvetica,Arial,sans-serif;color:#222}h1,h2,h3,h4,h5,h6{margin-top:1rem;margin-bottom:2rem;font-weight:300}h1{font-size:3rem;line-height:1.2}h2{font-size:2.8rem;line-height:1.25}h3{font-size:2.6rem;line-height:1.3}h4{font-size:2.4rem;line-height:1.35}h5{font-size:1.8rem;line-height:1.5}h6{font-size:1.5rem;line-height:1.6;letter-spacing:0}p{margin-top:0}a{color:#0095d2}a:hover{color:#00719f}blockquote,dl,p,pre{margin-bottom:2.5rem}code{padding:.2rem .5rem;margin:0 .2rem;font-size:.9rem;white-space:nowrap;background:#fafafa;border:1px solid #e1e1e1;border-radius:4px}pre>code{display:block;padding:1rem 1.5rem;white-space:pre;overflow:auto}.u-full-width{width:100%}.u-max-full-width{max-width:100%}.u-pull-right{float:right}.u-pull-left{float:left}.u-cf{content:"";display:table;clear:both}.u-hideable{display:none}.button{display:inline-block;height:38px;padding:0 30px;margin-bottom:1rem;color:#222;text-align:center;font-size:80%;font-weight:600;line-height:38px;letter-spacing:.1rem;text-transform:uppercase;text-decoration:none;white-space:nowrap;background-color:transparent;border-radius:4px;border:1px solid #e1e1e1;cursor:pointer}.button:active,.button:focus,.button:hover{color:#222;border-color:#aeaeae;outline:0}.button--primary{color:#fff;background-color:#0095d2;border-color:#0095d2}.button--primary:active,.button--primary:focus,.button--primary:hover{color:#fff;background-color:#0087be;border-color:#0087be}.button-download{color:#fff;background-color:#ec971f;border-color:#eb9316;padding:0 10px;margin-right:1rem}.button-download:active,.button-download:focus,.button-download:hover{color:#fff;background-color:#e38d13;border-color:#da8813}.navgrid{width:100%;min-width:0;margin-left:0;margin-right:0;padding-left:0;padding-right:10px}.nav{background:#0095d2}.nav ul{list-style:none;text-align:center;padding:0;margin:0;background-color:#0095d2}.nav li{line-height:40px;height:40px;border-bottom:none;margin-bottom:0}.nav a{text-decoration:none;color:#fff;display:block}.nav a:hover{background-color:#0073b0}.nav a.active{background-color:#0073b0;color:#fff;cursor:default}.logo{text-align:center;background-color:#0095d2}.navbar-brand{padding:0;font-size:18px;max-width:250px}@media screen and (min-width:820px){body{padding-top:50px}.navgrid{width:100%;max-width:1140px;min-width:755px;margin:0 auto;overflow:hidden}.nav{height:50px;width:100%;z-index:1000;position:fixed;top:0}.navbar-brand{padding:0;font-size:18px;float:left;max-width:250px}.nav{z-index:10;top:0;background-color:#0095d2}.nav a{padding-left:20px;padding-right:20px}.nav li{border-bottom:none;height:50px;line-height:50px;float:left;display:inline-block;margin-right:0}.nav a{text-decoration:none;color:#fff;display:block}.nav ul{list-style:none;text-align:center;padding:0;margin:0;background-color:#0095d2}:target:before{content:"";display:block;height:50px;margin:-50px 0 0}}@media (min-width:1550px){.nav li{font-size:1.2em}}@media (min-width:1900px){.nav li{font-size:1.4em}}table[data-sortable] th[data-sorted=true]{color:#3a87ad;background:#d9edf7;border-bottom-color:#bce8f1}table[data-sortable] th:not([data-sortable=false]){cursor:pointer;color:#222;text-decoration:underline}.summarybox{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.summarybox.ok{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.summarybox.warning{color:#c09853;background-color:#fcf8e3;border-color:#fbeed5}.summarybox.error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.summarybox.info{background-color:#d9edf7;border-color:#bce8f1;color:#3a87ad}a.summaries{text-decoration:none}.summarynumber{font-size:2rem;line-height:1;font-weight:700}.summarysmall{font-size:1rem;line-height:1}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}.normal{font-size:100%}.ok{background-color:#468847}.warning{background-color:#f0ad4e}.error{background-color:#d9534f}.info{background-color:#0095d2}ul.menu{list-style:none;font-size:125%;text-transform:uppercase}.errors{margin-bottom:1.333em;background:#ffb6c1;padding-left:1em}.subtableheader{background:#ffe3eb}.large{font-size:1.333rem;line-height:1.8rem}.hidden-small{display:inline}.url{overflow-wrap:break-word;word-wrap:break-word;-webkit-hyphens:auto;-ms-hyphens:auto;-moz-hyphens:auto;hyphens:auto}/*! github.com/micmro/PerfCascade Version:2.11.0 (24/11/2021) */.water-fall-chart{width:100%;overflow:visible;font-size:12px;line-height:1em}.water-fall-chart *{box-sizing:border-box}.water-fall-chart button{cursor:pointer}.water-fall-holder{fill:#ccc}.water-fall-chart .left-fixed-holder{overflow:visible}.water-fall-chart .marker-holder{width:100%}.water-fall-chart .line-label-holder{cursor:pointer}.water-fall-chart .line-holder{stroke-width:1;stroke:#ccc;stroke-opacity:0.5;transition:all 60ms}.water-fall-chart .line-holder .line-mark{fill:#69009e;opacity:.01;stroke-width:0;transition:all 60ms}.water-fall-chart .line-holder.active{stroke:#69009e;stroke-width:2;stroke-opacity:1}.water-fall-chart .line-holder.active .line-mark{opacity:.4}.water-fall-chart .type-onload .line-holder{stroke:#c0c0ff}.water-fall-chart .type-oncontentload .line-holder{stroke:#d888df}.water-fall-chart .labels{width:100%}.water-fall-chart .labels .inner-label{pointer-events:none}.water-fall-chart .time-block.active{opacity:.8}.water-fall-chart .line-end,.water-fall-chart .line-start{display:none;stroke-width:1;stroke-opacity:0.5;stroke:#000}.water-fall-chart .line-end.active,.water-fall-chart .line-start.active{display:block}.left-fixed-holder .label-full-bg{fill:#fff;opacity:.9}.time-scale line{stroke:#0cc;stroke-width:1}.time-scale line.sub-second-line{stroke:#ccc;opacity:.75;stroke-width:.5}.time-scale text{font-weight:700}.row-item{cursor:pointer}.row-item .even{fill:#ccc;opacity:.05}.row-item .odd{fill:#000;opacity:.05}.row-item:hover .even,.row-item:hover .odd{fill:#000;opacity:.1}.row-item:focus{outline:solid 1.5px #aaa;outline-offset:-1.5px}.row-item:focus .even,.row-item:focus .odd{fill:#000;opacity:.2}.row-item .rect-holder text{fill:#aaa}.row-item.status0 .even,.row-item.status5xx .even{fill:#f66}.row-item.status0 .odd,.row-item.status5xx .odd{fill:#f00}.row-item.status4xx .even{fill:#c33}.row-item.status4xx .odd{fill:#c00}.row-item.status3xx .even{fill:#ff6}.row-item.status3xx .odd{fill:#ff0}.row-item.potentiallyRenderBlocking .even,.row-item.potentiallyRenderBlocking .odd{fill:#e5a331}.row-item.renderBlocking .even,.row-item.renderBlocking .odd{fill:#e57231;stroke-dasharray:5;stroke:black;stroke-width:2px}.row-item.largestContentfulPaint .even,.row-item.largestContentfulPaint .odd{fill:#c9e531;stroke-dasharray:8;stroke-width:2px;stroke:black}.row-item.largestContentfulPaint .even,.row-item.largestContentfulPaint .odd,.row-item.potentiallyRenderBlocking .even,.row-item.potentiallyRenderBlocking .odd,.row-item.renderBlocking .even,.row-item.renderBlocking .odd,.row-item.status0 .even,.row-item.status0 .odd,.row-item.status3xx .even,.row-item.status3xx .odd,.row-item.status4xx .even,.row-item.status4xx .odd,.row-item.status5xx .even,.row-item.status5xx .odd{opacity:.3}.row-item.largestContentfulPaint:hover .even,.row-item.largestContentfulPaint:hover .odd,.row-item.potentiallyRenderBlocking:hover .even,.row-item.potentiallyRenderBlocking:hover .odd,.row-item.renderBlocking:hover .even,.row-item.renderBlocking:hover .odd,.row-item.status0:hover .even,.row-item.status0:hover .odd,.row-item.status3xx:hover .even,.row-item.status3xx:hover .odd,.row-item.status4xx:hover .even,.row-item.status4xx:hover .odd,.row-item.status5xx:hover .even,.row-item.status5xx:hover .odd{opacity:.5}.tooltip-holder{overflow:visible}.tooltip *{padding:0;margin:0}.tooltip html{font-size:10px;line-height:1.2em}.tooltip body{position:relative}.tooltip-payload{position:absolute;top:0;left:0;padding:.25em;font-size:10px;display:inline-block;background:rgba(255,255,255,.9);border:solid 1px #f0f0f0;word-break:break-all;overflow-wrap:break-word;transition:opacity .3s}.tooltip-payload.no-anim{transition:none}.row-item,.time-scale line,.time-scale text,.water-fall-chart .line-holder line,.water-fall-chart .line-label-holder{transition:transform 60ms}.water-fall-chart.closing{transition-delay:60ms}.labels{overflow:hidden}.block-css{fill:#a6d18f}.block-html,.block-iframe,.block-internal,.block-svg{fill:#82a8de}.block-image,.block-img{fill:#b394cf}.block-javascript,.block-js,.block-script{fill:#e0b483}.block-link{fill:#89afe6}.block-flash,.block-swf{fill:#42aab1}.block-font{fill:#e15d4e}.block-ajax,.block-xmlhttprequest{fill:#f00}.block-other,.block-plain{fill:#b3b3b3}.block-blocked{fill:#aaa}.block-dns{fill:#159588}.block-connect{fill:#fd9727}.block-ssl{fill:#c141cd}.block-send{fill:#b0bec5}.block-wait{fill:#1ec659}.block-receive{fill:#1eaaf1}.block-receive-chunk{fill:#a1c3fa}.block-undefined{fill:#0f0}.info-overlay-bg{fill:#fff;stroke:#cdcdcd}.info-overlay-close-btn{fill:rgba(205,205,205,0.8);transform:translate(-23px,-23px);cursor:pointer}.info-overlay-close-btn text{fill:#111;pointer-events:none}.info-overlay-close-btn:focus{border:solid 1px #36c}.info-overlay-holder .connect{border-right:solid 5px #fd9727;padding-right:5px}.info-overlay-holder .blocked{border-right:solid 5px #aaa;padding-right:5px}.info-overlay-holder .ssltls{border-right:solid 5px #c141cd;padding-right:5px}.info-overlay-holder .send{border-right:solid 5px #b0bec5;padding-right:5px}.info-overlay-holder .wait{border-right:solid 5px #1ec659;padding-right:5px}.info-overlay-holder .receive{border-right:solid 5px #1eaaf1;padding-right:5px}.info-overlay-holder .dns{border-right:solid 5px #159588;padding-right:5px}.type-css{background:#406b29}.type-html,.type-iframe,.type-internal,.type-svg{background:#1c4278}.type-image,.type-img{background:#4d2e69}.type-javascript,.type-js,.type-script{background:#7a4e1d}.type-link{background:#89afe6}.type-flash,.type-swf{background:#234980}.type-font{background:#ae2a1b}.type-ajax,.type-xmlhttprequest{background:#c00}.type-other,.type-plain{background:grey}.info-overlay-holder *{padding:0;margin:0;font-size:12px}.info-overlay-holder body{position:relative;height:450px;clear:both;padding:0;margin:0;width:100%;background:#fff;color:#666}.info-overlay-holder body .wrapper{height:450px;width:100%;overflow:scroll}.info-overlay-holder header{position:relative;box-shadow:0 0 2px 2px rgba(0,0,0,.25)}.info-overlay-holder header,.info-overlay-holder header a,.info-overlay-holder header button{color:#fff;text-decoration:none}.info-overlay-holder header a:focus,.info-overlay-holder header a:hover{text-decoration:underline}.info-overlay-holder .requestID{font-weight:700}.info-overlay-holder h3,.info-overlay-holder h3 a{font-size:1.1em;padding:1em;margin:0;font-weight:400;overflow-wrap:break-word}.info-overlay-holder h3 strong{font-size:1.1em}.info-overlay-holder .tab-nav ul{margin:0;padding:0}.info-overlay-holder .tab-nav li{margin:0;padding:0;display:inline-block}.info-overlay-holder button{background:0 0;outline:0;border:0;border-bottom:solid 2px transparent;padding:.5em 1em;margin:0 .25em}.info-overlay-holder li:first-child button{margin-left:1em}.info-overlay-holder button.active:focus,.info-overlay-holder button:focus,.info-overlay-holder button:hover{border-color:rgba(255,255,255,.6)}.info-overlay-holder button.active{border-color:#fff;cursor:default}.info-overlay-holder button.active:focus{border-color:rgba(255,255,255,.8)}.info-overlay-holder button.copy-tab-data{position:absolute;top:.5em;right:.5em;border:0;margin:0;border-radius:1em;background:#e0e0e0}.info-overlay-holder button.copy-tab-data:focus,.info-overlay-holder button.copy-tab-data:hover{background:#ccc}.info-overlay-holder dt{float:left;clear:both;margin-top:.5em;width:25%;text-align:right;font-weight:700}.info-overlay-holder dd{float:left;width:73%;margin:.5em 0 0 2%;padding:0 0 .5em 0}.info-overlay-holder dt:after{content:":"}.info-overlay-holder pre{font-size:11px;line-height:23px;border-radius:0;background:#f6f3f3}.info-overlay-holder .tab{float:left;position:relative;width:100%;height:350px;padding:12px 12px 24px}.info-overlay-holder .tab h2{font-size:1.2em;margin:.5em 0 0;padding:.5em 0 .5em 1em;clear:both;border-top:solid 1px #efefef}.info-overlay-holder .tab h2:first-child{border-top:0;padding-top:0}.info-overlay-holder .tab pre{overflow-y:hidden;width:100%;min-height:100%}.info-overlay-holder .tab .preview{width:auto;max-width:100%;max-height:500px;border:solid 1px #666}.info-overlay-holder .tab dl:after{content:"";display:table;clear:both}.info-overlay-holder .tab.rendered-data{padding:0}.info-overlay-holder .tab.rendered-data pre{padding:12px 12px 24px}.info-overlay-holder .tab.rendered-data pre>code{white-space:pre-wrap}.resource-legend{margin:0;padding:0;font-size:.75em;line-height:1.5em;display:inline-block}.resource-legend li{margin:0 1em 0 0;padding:0;white-space:nowrap;display:inline-block}.resource-legend li:before{content:"";width:1em;height:1em;margin:0 .5em 0 0;vertical-align:text-top;display:inline-block}.resource-legend .legend-blocked:before{background:#aaa}.resource-legend .legend-dns:before{background:#159588}.resource-legend .legend-connect:before{background:#fd9727}.resource-legend .legend-ssl:before{background:#c141cd}.resource-legend .legend-send:before{background:#b0bec5}.resource-legend .legend-wait:before{background:#1ec659}.resource-legend .legend-receive:before{background:#1eaaf1}.icon{fill:#666}.icon-4xx,.icon-5xx,.icon-no-cache,.icon-no-gzip,.icon-warning{fill:#b55}.water-fall-chart .type-firstpaint .line-holder{stroke:#42f46e;stroke-opacity:1;stroke-width:3}.water-fall-chart .type-firstvisualchange .line-holder{stroke:#42f46e;stroke-opacity:1;stroke-width:3}.water-fall-chart .type-visualcomplete85 .line-holder{stroke:#ee7777;stroke-opacity:1;stroke-width:3}.water-fall-chart .type-lastvisualchange .line-holder{stroke:#ee42f4;stroke-opacity:1;stroke-width:3}.water-fall-chart .type-onload .line-holder{stroke:#9c99e5;stroke-opacity:1;stroke-width:3}.water-fall-chart .type-oncontentload .line-holder{stroke:#9842f4;stroke-opacity:1;stroke-width:3}.water-fall-chart .type-dominteractivetime .line-holder{stroke:#1842f4;stroke-opacity:1;stroke-width:2}.water-fall-chart .type-domcontentloadedtime .line-holder{stroke:#1212f4;stroke-opacity:1;stroke-width:2}.water-fall-chart .type-lastcpulongtask .line-holder{stroke:#f41229;stroke-opacity:1;stroke-width:3}.water-fall-chart .type-largestcontentfulpaint .line-holder{stroke:#c7f412;stroke-opacity:1;stroke-width:3}.water-fall-chart{font-size:14px}#page-selector{display:none;clear:both;margin:1em 0}*{box-sizing:border-box}@media screen and (max-width:400px){select{max-width:100%}}.screenshot{padding:4px;background-color:#fff;border:1px solid #ddd;border-radius:4px}*,:after,:before{margin:0;padding:0;box-sizing:border-box}section{display:block;padding:20px 0 0;border-top:1px solid #ddd}#tabs a{display:inline-block;margin:0 0 -1px;padding:15px 22px;font-weight:600;text-align:center;color:#bbb;border:1px solid transparent;text-decoration:none;text-transform:uppercase}#tabs a:before{font-weight:400}#tabs a:hover{color:#888;cursor:pointer}#tabs a:target:focus{outline:0}#tabs a[selected]{color:#555;border:1px solid #ddd;border-top:2px solid #0095d2;border-bottom:1px solid #fff}@media screen and (max-width:650px){#tabs a:before{margin:0;font-size:18px}}@media screen and (max-width:400px){#tabs a{padding:13px}}.group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd;font-weight:700}.group-item.active{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7}.group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.loader,.loader:after,.loader:before{background:#000;-webkit-animation:load1 1s infinite ease-in-out;animation:load1 1s infinite ease-in-out;width:1em;height:4em}.loader{color:#000;text-indent:-9999em;margin:88px auto;position:relative;font-size:11px;-webkit-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0);-webkit-animation-delay:-.16s;animation-delay:-.16s}.loader:after,.loader:before{position:absolute;top:0;content:""}.loader:before{left:-1.5em;-webkit-animation-delay:-.32s;animation-delay:-.32s}.loader:after{left:1.5em}@-webkit-keyframes load1{0%,100%,80%{box-shadow:0 0;height:4em}40%{box-shadow:0 -2em;height:5em}}@keyframes load1{0%,100%,80%{box-shadow:0 0;height:4em}40%{box-shadow:0 -2em;height:5em}}.ct-label{fill:rgba(0,0,0,0.4);color:rgba(0,0,0,.4);font-size:.75rem;line-height:1}.ct-chart-bar .ct-label,.ct-chart-line .ct-label{display:block;display:-webkit-box;display:-moz-box;display:-ms-flexbox;display:-webkit-flex;display:flex}.ct-chart-donut .ct-label,.ct-chart-pie .ct-label{dominant-baseline:central}.ct-label.ct-horizontal.ct-start{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-label.ct-horizontal.ct-end{-webkit-box-align:flex-start;-webkit-align-items:flex-start;-ms-flex-align:flex-start;align-items:flex-start;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-label.ct-vertical.ct-start{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:flex-end;-webkit-justify-content:flex-end;-ms-flex-pack:flex-end;justify-content:flex-end;text-align:right;text-anchor:end}.ct-label.ct-vertical.ct-end{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-chart-bar .ct-label.ct-horizontal.ct-start{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;text-align:center;text-anchor:start}.ct-chart-bar .ct-label.ct-horizontal.ct-end{-webkit-box-align:flex-start;-webkit-align-items:flex-start;-ms-flex-align:flex-start;align-items:flex-start;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;text-align:center;text-anchor:start}.ct-chart-bar.ct-horizontal-bars .ct-label.ct-horizontal.ct-start{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-chart-bar.ct-horizontal-bars .ct-label.ct-horizontal.ct-end{-webkit-box-align:flex-start;-webkit-align-items:flex-start;-ms-flex-align:flex-start;align-items:flex-start;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-chart-bar.ct-horizontal-bars .ct-label.ct-vertical.ct-start{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:flex-end;-webkit-justify-content:flex-end;-ms-flex-pack:flex-end;justify-content:flex-end;text-align:right;text-anchor:end}.ct-chart-bar.ct-horizontal-bars .ct-label.ct-vertical.ct-end{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:end}.ct-grid{stroke:rgba(0,0,0,0.2);stroke-width:1px;stroke-dasharray:2px}.ct-grid-background{fill:none}.ct-point{stroke-width:10px;stroke-linecap:round}.ct-line{fill:none;stroke-width:4px}.ct-area{stroke:none;fill-opacity:0.1}.ct-bar{fill:none;stroke-width:10px}.ct-slice-donut{fill:none;stroke-width:60px}.ct-series-a .ct-bar,.ct-series-a .ct-line,.ct-series-a .ct-point,.ct-series-a .ct-slice-donut{stroke:#d70206}.ct-series-a .ct-area,.ct-series-a .ct-slice-donut-solid,.ct-series-a .ct-slice-pie{fill:#d70206}.ct-series-b .ct-bar,.ct-series-b .ct-line,.ct-series-b .ct-point,.ct-series-b .ct-slice-donut{stroke:#f05b4f}.ct-series-b .ct-area,.ct-series-b .ct-slice-donut-solid,.ct-series-b .ct-slice-pie{fill:#f05b4f}.ct-series-c .ct-bar,.ct-series-c .ct-line,.ct-series-c .ct-point,.ct-series-c .ct-slice-donut{stroke:#f4c63d}.ct-series-c .ct-area,.ct-series-c .ct-slice-donut-solid,.ct-series-c .ct-slice-pie{fill:#f4c63d}.ct-series-d .ct-bar,.ct-series-d .ct-line,.ct-series-d .ct-point,.ct-series-d .ct-slice-donut{stroke:#d17905}.ct-series-d .ct-area,.ct-series-d .ct-slice-donut-solid,.ct-series-d .ct-slice-pie{fill:#d17905}.ct-series-e .ct-bar,.ct-series-e .ct-line,.ct-series-e .ct-point,.ct-series-e .ct-slice-donut{stroke:#453d3f}.ct-series-e .ct-area,.ct-series-e .ct-slice-donut-solid,.ct-series-e .ct-slice-pie{fill:#453d3f}.ct-series-f .ct-bar,.ct-series-f .ct-line,.ct-series-f .ct-point,.ct-series-f .ct-slice-donut{stroke:#59922b}.ct-series-f .ct-area,.ct-series-f .ct-slice-donut-solid,.ct-series-f .ct-slice-pie{fill:#59922b}.ct-series-g .ct-bar,.ct-series-g .ct-line,.ct-series-g .ct-point,.ct-series-g .ct-slice-donut{stroke:#0544d3}.ct-series-g .ct-area,.ct-series-g .ct-slice-donut-solid,.ct-series-g .ct-slice-pie{fill:#0544d3}.ct-series-h .ct-bar,.ct-series-h .ct-line,.ct-series-h .ct-point,.ct-series-h .ct-slice-donut{stroke:#6b0392}.ct-series-h .ct-area,.ct-series-h .ct-slice-donut-solid,.ct-series-h .ct-slice-pie{fill:#6b0392}.ct-series-i .ct-bar,.ct-series-i .ct-line,.ct-series-i .ct-point,.ct-series-i .ct-slice-donut{stroke:#f05b4f}.ct-series-i .ct-area,.ct-series-i .ct-slice-donut-solid,.ct-series-i .ct-slice-pie{fill:#f05b4f}.ct-series-j .ct-bar,.ct-series-j .ct-line,.ct-series-j .ct-point,.ct-series-j .ct-slice-donut{stroke:#dda458}.ct-series-j .ct-area,.ct-series-j .ct-slice-donut-solid,.ct-series-j .ct-slice-pie{fill:#dda458}.ct-series-k .ct-bar,.ct-series-k .ct-line,.ct-series-k .ct-point,.ct-series-k .ct-slice-donut{stroke:#eacf7d}.ct-series-k .ct-area,.ct-series-k .ct-slice-donut-solid,.ct-series-k .ct-slice-pie{fill:#eacf7d}.ct-series-l .ct-bar,.ct-series-l .ct-line,.ct-series-l .ct-point,.ct-series-l .ct-slice-donut{stroke:#86797d}.ct-series-l .ct-area,.ct-series-l .ct-slice-donut-solid,.ct-series-l .ct-slice-pie{fill:#86797d}.ct-series-m .ct-bar,.ct-series-m .ct-line,.ct-series-m .ct-point,.ct-series-m .ct-slice-donut{stroke:#b2c326}.ct-series-m .ct-area,.ct-series-m .ct-slice-donut-solid,.ct-series-m .ct-slice-pie{fill:#b2c326}.ct-series-n .ct-bar,.ct-series-n .ct-line,.ct-series-n .ct-point,.ct-series-n .ct-slice-donut{stroke:#6188e2}.ct-series-n .ct-area,.ct-series-n .ct-slice-donut-solid,.ct-series-n .ct-slice-pie{fill:#6188e2}.ct-series-o .ct-bar,.ct-series-o .ct-line,.ct-series-o .ct-point,.ct-series-o .ct-slice-donut{stroke:#a748ca}.ct-series-o .ct-area,.ct-series-o .ct-slice-donut-solid,.ct-series-o .ct-slice-pie{fill:#a748ca}.ct-square{display:block;position:relative;width:100%}.ct-square:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:100%}.ct-square:after{content:"";display:table;clear:both}.ct-square>svg{display:block;position:absolute;top:0;left:0}.ct-minor-second{display:block;position:relative;width:100%}.ct-minor-second:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:93.75%}.ct-minor-second:after{content:"";display:table;clear:both}.ct-minor-second>svg{display:block;position:absolute;top:0;left:0}.ct-major-second{display:block;position:relative;width:100%}.ct-major-second:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:88.8888888889%}.ct-major-second:after{content:"";display:table;clear:both}.ct-major-second>svg{display:block;position:absolute;top:0;left:0}.ct-minor-third{display:block;position:relative;width:100%}.ct-minor-third:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:83.3333333333%}.ct-minor-third:after{content:"";display:table;clear:both}.ct-minor-third>svg{display:block;position:absolute;top:0;left:0}.ct-major-third{display:block;position:relative;width:100%}.ct-major-third:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:80%}.ct-major-third:after{content:"";display:table;clear:both}.ct-major-third>svg{display:block;position:absolute;top:0;left:0}.ct-perfect-fourth{display:block;position:relative;width:100%}.ct-perfect-fourth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:75%}.ct-perfect-fourth:after{content:"";display:table;clear:both}.ct-perfect-fourth>svg{display:block;position:absolute;top:0;left:0}.ct-perfect-fifth{display:block;position:relative;width:100%}.ct-perfect-fifth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:66.6666666667%}.ct-perfect-fifth:after{content:"";display:table;clear:both}.ct-perfect-fifth>svg{display:block;position:absolute;top:0;left:0}.ct-minor-sixth{display:block;position:relative;width:100%}.ct-minor-sixth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:62.5%}.ct-minor-sixth:after{content:"";display:table;clear:both}.ct-minor-sixth>svg{display:block;position:absolute;top:0;left:0}.ct-golden-section{display:block;position:relative;width:100%}.ct-golden-section:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:61.804697157%}.ct-golden-section:after{content:"";display:table;clear:both}.ct-golden-section>svg{display:block;position:absolute;top:0;left:0}.ct-major-sixth{display:block;position:relative;width:100%}.ct-major-sixth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:60%}.ct-major-sixth:after{content:"";display:table;clear:both}.ct-major-sixth>svg{display:block;position:absolute;top:0;left:0}.ct-minor-seventh{display:block;position:relative;width:100%}.ct-minor-seventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:56.25%}.ct-minor-seventh:after{content:"";display:table;clear:both}.ct-minor-seventh>svg{display:block;position:absolute;top:0;left:0}.ct-major-seventh{display:block;position:relative;width:100%}.ct-major-seventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:53.3333333333%}.ct-major-seventh:after{content:"";display:table;clear:both}.ct-major-seventh>svg{display:block;position:absolute;top:0;left:0}.ct-octave{display:block;position:relative;width:100%}.ct-octave:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:50%}.ct-octave:after{content:"";display:table;clear:both}.ct-octave>svg{display:block;position:absolute;top:0;left:0}.ct-major-tenth{display:block;position:relative;width:100%}.ct-major-tenth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:40%}.ct-major-tenth:after{content:"";display:table;clear:both}.ct-major-tenth>svg{display:block;position:absolute;top:0;left:0}.ct-major-eleventh{display:block;position:relative;width:100%}.ct-major-eleventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:37.5%}.ct-major-eleventh:after{content:"";display:table;clear:both}.ct-major-eleventh>svg{display:block;position:absolute;top:0;left:0}.ct-major-twelfth{display:block;position:relative;width:100%}.ct-major-twelfth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:33.3333333333%}.ct-major-twelfth:after{content:"";display:table;clear:both}.ct-major-twelfth>svg{display:block;position:absolute;top:0;left:0}.ct-double-octave{display:block;position:relative;width:100%}.ct-double-octave:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:25%}.ct-double-octave:after{content:"";display:table;clear:both}.ct-double-octave>svg{display:block;position:absolute;top:0;left:0}.ct-legend{display:flex;margin-top:10px;margin-left:16px;margin-bottom:14x}.ct-legend-item{display:flex;margin-right:15px;line-height:18px}.ct-legend-item i{display:inline-block;width:18px;height:18px;margin-right:5px}.baseline-series .ct-line,.baseline-series .ct-point{stroke:green}.current-series .ct-line,.current-series .ct-point{stroke:blue}.chartist-tooltip{position:absolute;display:inline-block;opacity:0;min-width:5em;padding:.5em;background:#f4c63d;color:#453d3f;font-family:Oxygen,Helvetica,Arial,sans-serif;font-weight:700;text-align:center;pointer-events:none;z-index:1;-webkit-transition:opacity .2s linear;-moz-transition:opacity .2s linear;-o-transition:opacity .2s linear;transition:opacity .2s linear}.chartist-tooltip:before{content:"";position:absolute;top:100%;left:50%;width:0;height:0;margin-left:-15px;border:15px solid transparent;border-top-color:#f4c63d}.chartist-tooltip.tooltip-show{opacity:1}.ct-area,.ct-line{pointer-events:none}.chartist-tooltip{background:#0095d2;color:#fff}.chartist-tooltip:before{border-top-color:#0095d2}.ct-bar{stroke-width:16px}.ct-series-a .ct-bar,.ct-series-a .ct-line,.ct-series-a .ct-point,.ct-series-a .ct-slice-donut{stroke:#82b5fc}.ct-series-a .ct-area,.ct-series-a .ct-slice-donut-solid,.ct-series-a .ct-slice-pie{fill:#468847}.ct-series-b .ct-bar,.ct-series-b .ct-line,.ct-series-b .ct-point,.ct-series-b .ct-slice-donut{stroke:#b2ea94}.ct-series-b .ct-area,.ct-series-b .ct-slice-donut-solid,.ct-series-b .ct-slice-pie{fill:#c09853}.ct-series-c .ct-bar,.ct-series-c .ct-line,.ct-series-c .ct-point,.ct-series-c .ct-slice-donut{stroke:#fec584}.ct-series-c .ct-area,.ct-series-c .ct-slice-donut-solid,.ct-series-c .ct-slice-pie{fill:#b94a48}.ct-series-d .ct-bar,.ct-series-d .ct-line,.ct-series-d .ct-point,.ct-series-d .ct-slice-donut{stroke:#c49ae8}.ct-series-d .ct-area,.ct-series-d .ct-slice-donut-solid,.ct-series-d .ct-slice-pie{fill:#c49ae8}.ct-series-e .ct-bar,.ct-series-e .ct-line,.ct-series-e .ct-point,.ct-series-e .ct-slice-donut{stroke:#ff523e}.ct-series-e .ct-area,.ct-series-e .ct-slice-donut-solid,.ct-series-e .ct-slice-pie{fill:#ff523e}.ct-series-f .ct-bar,.ct-series-f .ct-line,.ct-series-f .ct-point,.ct-series-f .ct-slice-donut{stroke:#c4c4c4}.ct-series-f .ct-area,.ct-series-f .ct-slice-donut-solid,.ct-series-f .ct-slice-pie{fill:#c4c4c4}.ct-series-g .ct-bar,.ct-series-g .ct-line,.ct-series-g .ct-point,.ct-series-g .ct-slice-donut{stroke:#c4c4c4}.ct-series-g .ct-area,.ct-series-g .ct-slice-donut-solid,.ct-series-g .ct-slice-pie{fill:#c4c4c4}.ct-series-h .ct-bar,.ct-series-h .ct-line,.ct-series-h .ct-point,.ct-series-h .ct-slice-donut{stroke:#c4c4c4}.ct-series-h .ct-area,.ct-series-h .ct-slice-donut-solid,.ct-series-h .ct-slice-pie{fill:#c4c4c4}.ct-series-i .ct-bar,.ct-series-i .ct-line,.ct-series-i .ct-point,.ct-series-i .ct-slice-donut{stroke:#EAB839}.ct-series-i .ct-area,.ct-series-i .ct-slice-donut-solid,.ct-series-i .ct-slice-pie{fill:#EAB839}.ct-chart .ct-legend{position:relative;z-index:10;list-style:none;text-align:left;line-height:.8;font-size:.8em}.ct-chart .ct-legend li{padding-left:23px;margin-right:10px;margin-bottom:3px;cursor:pointer}.ct-chart .ct-legend li:before{width:12px;height:12px;position:absolute;left:0;content:"";border:3px solid transparent;border-radius:2px}.ct-chart .ct-legend li .inactive:before{background:0 0}.ct-chart .ct-legend li:first-child::before{background-color:#468847}.ct-chart .ct-legend li:nth-child(2)::before{background-color:#c09853}.ct-chart .ct-legend li:nth-child(3)::before{background-color:#b94a48}.ct-chart .ct-legend .ct-legend-inside{position:absolute;top:0;right:0}.ct-chart g:not(.ct-grids):not(.ct-labels) g:first-child .ct-line,.ct-chart g:not(.ct-grids):not(.ct-labels) g:first-child .ct-point{stroke:#468847}.ct-chart g:not(.ct-grids):not(.ct-labels) g:nth-child(2) .ct-line,.ct-chart g:not(.ct-grids):not(.ct-labels) g:nth-child(2) .ct-point{stroke:#c09853}.ct-chart g:not(.ct-grids):not(.ct-labels) g:nth-child(3) .ct-line,.ct-chart g:not(.ct-grids):not(.ct-labels) g:nth-child(3) .ct-point{stroke:#b94a48}.filmstrip{padding-bottom:20px}.videoframe{vertical-align:top;display:inline-block;padding:4px;background-color:#fff;border:1px solid #ddd;border-radius:4px;width:100%}.videoframe.blue{border:2px solid #0095d2}.videoframetime{text-align:center;display:block}.videoframetext{text-align:left;display:block;line-height:1.2em;font-size:.8em;white-space:nowrap;margin-bottom:.2em} \ No newline at end of file diff --git a/lib/plugins/html/src/sass/components/chartist.scss b/lib/plugins/html/src/sass/components/chartist.scss index a377ad20ac..7e540e75ec 100644 --- a/lib/plugins/html/src/sass/components/chartist.scss +++ b/lib/plugins/html/src/sass/components/chartist.scss @@ -613,3 +613,34 @@ left: 0; } /*# sourceMappingURL=chartist.css.map */ + +.ct-legend { + display: flex; + // justify-content: center; + // align-items: center; + margin-top: 10px; + margin-left: 16px; + margin-bottom: 14x; +} + +.ct-legend-item { + display: flex; + // align-items: center; + margin-right: 15px; + line-height: 18px; +} + +.ct-legend-item i { + display: inline-block; + width: 18px; + height: 18px; + margin-right: 5px; +} + +.baseline-series .ct-point, .baseline-series .ct-line { + stroke: green; +} + +.current-series .ct-point, .current-series .ct-line { + stroke: blue; +} diff --git a/lib/support/helpers/decimals.js b/lib/support/helpers/decimals.js index 63199a8256..4a465ec42d 100644 --- a/lib/support/helpers/decimals.js +++ b/lib/support/helpers/decimals.js @@ -1,4 +1,16 @@ export function decimals(decimals) { - let number = Number(decimals).toFixed(3); - return number === '0.000' ? 0 : number; + const num = Number(decimals); + + // Check if the number is an integer (no decimals) + if (Number.isInteger(num)) { + return num; + } + + // If the number is less than 1, use three decimals + if (num < 1) { + return Number(num.toFixed(3)); + } + + // If the number is greater than 1 and has decimals, use one decimal + return Number(num.toFixed(1)); } diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 5e66c2abf2..1741a422d7 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -15,7 +15,7 @@ "@tgwf/co2": "0.13.6", "aws-sdk": "2.1327.0", "axe-core": "4.8.2", - "browsertime": "18.0.0", + "browsertime": "19.1.0", "cli-color": "2.0.3", "coach-core": "8.0.2", "concurrent-queue": "7.0.2", @@ -985,9 +985,9 @@ } }, "node_modules/@sitespeed.io/geckodriver": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/@sitespeed.io/geckodriver/-/geckodriver-0.33.0.tgz", - "integrity": "sha512-w6w+x9/Q44JekTPi8NlRsfh5Uz4TfquJcUEs0tA/oEcxLVxRS7VtaiaJEE0GzzN6cUmFS6Twas7E4bCA4k/Yxg==", + "version": "0.33.0-c", + "resolved": "https://registry.npmjs.org/@sitespeed.io/geckodriver/-/geckodriver-0.33.0-c.tgz", + "integrity": "sha512-HRZubf9VOvPcMl9gjOjsom1vVGPZhc53n+BVdXh9uVloT603rO/1W6ny12WcR1EDVctPXfPoneFguqHdT5W5rQ==", "hasInstallScript": true, "dependencies": { "node-downloader-helper": "2.1.5", @@ -1759,15 +1759,15 @@ } }, "node_modules/browsertime": { - "version": "18.0.0", - "resolved": "https://registry.npmjs.org/browsertime/-/browsertime-18.0.0.tgz", - "integrity": "sha512-E0BJVPahR/MgzyuANrvm2gnA7SiMgDw83VzEiYttd9YA/5uO26wmaRMs46Xo9xzah/d+0LQA/GO9a7bzc0dx+g==", + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/browsertime/-/browsertime-19.1.0.tgz", + "integrity": "sha512-LurCshUpj/W8XiN1Cfzem6RpqVSm/g9efW2PijO0y5KLuzZb4a+In5LIFH10Zm9PnHTyfs1aMow5ECnXNXQRag==", "dependencies": { "@cypress/xvfb": "1.2.4", "@devicefarmer/adbkit": "3.2.5", "@sitespeed.io/chromedriver": "119.0.6045-105", "@sitespeed.io/edgedriver": "119.0.2151-42", - "@sitespeed.io/geckodriver": "0.33.0", + "@sitespeed.io/geckodriver": "0.33.0-c", "@sitespeed.io/throttle": "5.0.0", "@sitespeed.io/tracium": "0.3.3", "btoa": "1.2.1", @@ -6115,9 +6115,9 @@ "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" }, "node_modules/minipass": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.5.tgz", - "integrity": "sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q==", + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", + "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==", "engines": { "node": ">=8" } @@ -9990,9 +9990,9 @@ } }, "@sitespeed.io/geckodriver": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/@sitespeed.io/geckodriver/-/geckodriver-0.33.0.tgz", - "integrity": "sha512-w6w+x9/Q44JekTPi8NlRsfh5Uz4TfquJcUEs0tA/oEcxLVxRS7VtaiaJEE0GzzN6cUmFS6Twas7E4bCA4k/Yxg==", + "version": "0.33.0-c", + "resolved": "https://registry.npmjs.org/@sitespeed.io/geckodriver/-/geckodriver-0.33.0-c.tgz", + "integrity": "sha512-HRZubf9VOvPcMl9gjOjsom1vVGPZhc53n+BVdXh9uVloT603rO/1W6ny12WcR1EDVctPXfPoneFguqHdT5W5rQ==", "requires": { "node-downloader-helper": "2.1.5", "node-stream-zip": "1.15.0", @@ -10574,15 +10574,15 @@ } }, "browsertime": { - "version": "18.0.0", - "resolved": "https://registry.npmjs.org/browsertime/-/browsertime-18.0.0.tgz", - "integrity": "sha512-E0BJVPahR/MgzyuANrvm2gnA7SiMgDw83VzEiYttd9YA/5uO26wmaRMs46Xo9xzah/d+0LQA/GO9a7bzc0dx+g==", + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/browsertime/-/browsertime-19.1.0.tgz", + "integrity": "sha512-LurCshUpj/W8XiN1Cfzem6RpqVSm/g9efW2PijO0y5KLuzZb4a+In5LIFH10Zm9PnHTyfs1aMow5ECnXNXQRag==", "requires": { "@cypress/xvfb": "1.2.4", "@devicefarmer/adbkit": "3.2.5", "@sitespeed.io/chromedriver": "119.0.6045-105", "@sitespeed.io/edgedriver": "119.0.2151-42", - "@sitespeed.io/geckodriver": "0.33.0", + "@sitespeed.io/geckodriver": "0.33.0-c", "@sitespeed.io/throttle": "5.0.0", "@sitespeed.io/tracium": "0.3.3", "btoa": "1.2.1", @@ -13878,9 +13878,9 @@ "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" }, "minipass": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.5.tgz", - "integrity": "sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q==" + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", + "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==" }, "minizlib": { "version": "2.1.2", diff --git a/package.json b/package.json index db1bebb599..bfb48bc9d7 100644 --- a/package.json +++ b/package.json @@ -83,7 +83,7 @@ "@tgwf/co2": "0.13.6", "aws-sdk": "2.1327.0", "axe-core": "4.8.2", - "browsertime": "18.0.0", + "browsertime": "19.1.0", "coach-core": "8.0.2", "cli-color": "2.0.3", "concurrent-queue": "7.0.2", diff --git a/test/compare-1.json b/test/compare-1.json new file mode 100644 index 0000000000..694815ba7c --- /dev/null +++ b/test/compare-1.json @@ -0,0 +1 @@ +{"info":{"browsertime":{"version":"18.0.0"},"url":"https://www.sitespeed.io","timestamp":"2023-11-24T04:16:28+01:00","connectivity":{"engine":"external","profile":"native"},"extra":{},"browser":{"name":"Chrome","userAgent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36","version":"119.0.6045.159"}},"files":{"video":["pages/www_sitespeed_io/data/video/1.mp4","pages/www_sitespeed_io/data/video/2.mp4","pages/www_sitespeed_io/data/video/3.mp4"],"screenshot":[["pages/www_sitespeed_io/data/screenshots/1/afterPageCompleteCheck.png","pages/www_sitespeed_io/data/screenshots/1/layoutShift.png","pages/www_sitespeed_io/data/screenshots/1/largestContentfulPaint.png"],["pages/www_sitespeed_io/data/screenshots/2/afterPageCompleteCheck.png","pages/www_sitespeed_io/data/screenshots/2/layoutShift.png","pages/www_sitespeed_io/data/screenshots/2/largestContentfulPaint.png"],["pages/www_sitespeed_io/data/screenshots/3/afterPageCompleteCheck.png","pages/www_sitespeed_io/data/screenshots/3/layoutShift.png","pages/www_sitespeed_io/data/screenshots/3/largestContentfulPaint.png"]],"timeline":[],"consoleLog":[],"netLog":[],"perfLog":[],"geckoProfiles":[],"memoryReports":[]},"markedAsFailure":0,"failureMessages":[],"cdp":{"performance":[{"AudioHandlers":0,"AudioWorkletProcessors":0,"Documents":4,"Frames":1,"JSEventListeners":4,"LayoutObjects":645,"MediaKeySessions":0,"MediaKeys":0,"Nodes":702,"Resources":10,"ContextLifecycleStateObservers":5,"V8PerContextDatas":3,"WorkerGlobalScopes":0,"UACSSResources":0,"RTCPeerConnections":0,"ResourceFetchers":4,"AdSubframes":0,"DetachedScriptStates":2,"ArrayBufferContents":0,"LayoutCount":6,"RecalcStyleCount":5,"LayoutDuration":121.092,"RecalcStyleDuration":5.365,"DevToolsCommandDuration":27.226,"ScriptDuration":22.325000000000003,"V8CompileDuration":0.415,"TaskDuration":266.00800000000004,"TaskOtherDuration":89.585,"ThreadTime":0.204547,"ProcessTime":0.436757,"JSHeapUsedSize":2027704,"JSHeapTotalSize":2793472,"FirstMeaningfulPaint":898.0640000081621},{"AudioHandlers":0,"AudioWorkletProcessors":0,"Documents":4,"Frames":1,"JSEventListeners":4,"LayoutObjects":645,"MediaKeySessions":0,"MediaKeys":0,"Nodes":702,"Resources":10,"ContextLifecycleStateObservers":5,"V8PerContextDatas":3,"WorkerGlobalScopes":0,"UACSSResources":0,"RTCPeerConnections":0,"ResourceFetchers":4,"AdSubframes":0,"DetachedScriptStates":2,"ArrayBufferContents":0,"LayoutCount":6,"RecalcStyleCount":5,"LayoutDuration":103.473,"RecalcStyleDuration":4.497,"DevToolsCommandDuration":21.946,"ScriptDuration":31.144000000000002,"V8CompileDuration":0.432,"TaskDuration":242.352,"TaskOtherDuration":80.86,"ThreadTime":0.202672,"ProcessTime":0.422026,"JSHeapUsedSize":2020440,"JSHeapTotalSize":3055616,"FirstMeaningfulPaint":671.833999993396},{"AudioHandlers":0,"AudioWorkletProcessors":0,"Documents":4,"Frames":1,"JSEventListeners":4,"LayoutObjects":645,"MediaKeySessions":0,"MediaKeys":0,"Nodes":702,"Resources":10,"ContextLifecycleStateObservers":5,"V8PerContextDatas":3,"WorkerGlobalScopes":0,"UACSSResources":0,"RTCPeerConnections":0,"ResourceFetchers":4,"AdSubframes":0,"DetachedScriptStates":2,"ArrayBufferContents":0,"LayoutCount":6,"RecalcStyleCount":4,"LayoutDuration":110.89699999999999,"RecalcStyleDuration":3.741,"DevToolsCommandDuration":20.811,"ScriptDuration":19.959,"V8CompileDuration":0.335,"TaskDuration":219.809,"TaskOtherDuration":64.066,"ThreadTime":0.183858,"ProcessTime":0.390395,"JSHeapUsedSize":2067180,"JSHeapTotalSize":3055616,"FirstMeaningfulPaint":684.4899999996414}]},"android":{"batteryTemperature":[],"power":[]},"timestamps":["2023-11-24T04:15:58+01:00","2023-11-24T04:16:30+01:00","2023-11-24T04:17:00+01:00"],"browserScripts":[{"browser":{"cpuBenchmark":87,"userAgent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36","windowSize":"1366x623"},"pageinfo":{"cumulativeLayoutShift":0,"cumulativeLayoutShiftInfo":[],"documentHeight":4372,"documentSize":{"decodedBodySize":37800,"encodedBodySize":9383,"transferSize":9683},"documentTitle":"Welcome to the wonderful world of Web Performance","documentWidth":1366,"domElements":368,"largestContentfulPaintInfo":[{"className":"","domPath":"body > main > div:eq(0) > div > div:eq(0) > picture > img","duration":0,"id":"","loadTime":728,"renderTime":898,"size":216250,"startTime":898,"tag":"\"sitespeed.io","tagName":"IMG","url":"https://www.sitespeed.io/img/team.png"}],"navigationStartTime":1700795762871,"nextHopProtocol":"h2","resources":{"count":10,"duration":2191.10000000149,"servedFromCache":0},"responsive":true,"url":"https://www.sitespeed.io/","visualElements":{"heroes":[{"filename":"team.png","height":433,"html":"\"sitespeed.io","name":"LargestImage","width":500,"x":153,"y":50},{"filename":null,"height":173,"html":"

","name":"Heading","width":510,"x":703,"y":66},{"filename":"sitespeed-logo-2c.png","height":50,"html":"\"Sitespeed.io","name":"header-logo","width":162,"x":153,"y":0},{"filename":"team.png","height":433,"html":"\"sitespeed.io","name":"logo","width":500,"x":153,"y":50},{"filename":"team.png","height":433,"html":"\"sitespeed.io","name":"LargestContentfulPaint","width":500,"x":153,"y":50}],"viewport":{"height":623,"width":1366}},"longTask":[{"attribution":[{"containerId":"","containerName":"","containerSrc":"","containerType":"window"}],"duration":103,"name":"unknown","startTime":725.1000000014901}]},"timings":{"elementTimings":{"header-logo":{"duration":0,"loadTime":663,"naturalHeight":100,"naturalWidth":324,"renderTime":717,"startTime":717,"tagName":"IMG","url":"https://www.sitespeed.io/img/sitespeed-logo-2c.png"},"logo":{"duration":0,"loadTime":728,"naturalHeight":865,"naturalWidth":1000,"renderTime":717,"startTime":717,"tagName":"IMG","url":"https://www.sitespeed.io/img/team.png"}},"firstPaint":717,"largestContentfulPaint":{"className":"","domPath":"body > main > div:eq(0) > div > div:eq(0) > picture > img","duration":0,"id":"","loadTime":728,"renderTime":898,"size":216250,"startTime":898,"tag":"\"sitespeed.io","tagName":"IMG","url":"https://www.sitespeed.io/img/team.png"},"loadEventEnd":835,"navigationTiming":{"connectStart":41,"domComplete":834,"domContentLoadedEventEnd":834,"domContentLoadedEventStart":834,"domInteractive":828,"domainLookupEnd":41,"domainLookupStart":41,"duration":835,"fetchStart":6,"loadEventEnd":835,"loadEventStart":835,"redirectEnd":0,"redirectStart":0,"requestStart":261,"responseEnd":458,"responseStart":422,"secureConnectionStart":72,"startTime":0,"unloadEventEnd":0,"unloadEventStart":0,"workerStart":0},"pageTimings":{"backEndTime":422,"domContentLoadedTime":834,"domInteractiveTime":828,"domainLookupTime":0,"frontEndTime":376,"pageDownloadTime":37,"pageLoadTime":835,"redirectionTime":0,"serverConnectionTime":219,"serverResponseTime":197},"paintTiming":{"first-contentful-paint":717,"first-paint":717},"serverTimings":[],"ttfb":422,"userTimings":{"marks":[{"name":"userTimingHeader","startTime":721.5},{"name":"userTimingFooter","startTime":724.5}],"measures":[{"duration":3,"name":"exampleMeasurement","startTime":721.5}]}},"coach":{"coachAdvice":{"advice":{"bestpractice":{"adviceList":{"amp":{"advice":"","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.","id":"amp","offending":[],"score":100,"tags":["bestpractice"],"title":"Avoid using AMP","weight":10},"charset":{"advice":"","description":"The Unicode Standard (UTF-8) covers (almost) all the characters, punctuations, and symbols in the world. Please use that.","id":"charset","offending":[],"score":100,"tags":["bestpractice"],"title":"Declare a charset in your document","weight":2},"cumulativeLayoutShift":{"advice":"There is no Layout Shift on the page.","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.","id":"cumulativeLayoutShift","offending":[],"score":100,"tags":["bestpractice"],"title":"Cumulative Layout Shift","weight":8},"doctype":{"advice":"","description":"The declaration is not an HTML tag; it is an instruction to the web browser about what version of HTML the page is written in.","id":"doctype","offending":[],"score":100,"tags":["bestpractice"],"title":"Declare a doctype in your document","weight":2},"language":{"advice":"","description":"According to the W3C recommendation you should declare the primary language for each Web page with the lang attribute inside the tag https://www.w3.org/International/questions/qa-html-language-declarations#basics.","id":"language","offending":[],"score":100,"tags":["bestpractice"],"title":"Declare the language code for your document","weight":3},"metaDescription":{"advice":"","description":"Use a page description to make the page more relevant to search engines.","id":"metaDescription","offending":[],"score":100,"tags":["bestpractice"],"title":"Meta description","weight":5},"optimizely":{"advice":"","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.","id":"optimizely","offending":[],"score":100,"tags":["bestpractice"],"title":"Only use Optimizely when you need it","weight":2},"pageTitle":{"advice":"","description":"Use a title to make the page more relevant to search engines.","id":"pageTitle","offending":[],"score":100,"tags":["bestpractice"],"title":"Page title","weight":5},"spdy":{"advice":"","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.","id":"spdy","offending":[],"score":100,"tags":["bestpractice"],"title":"EOL for SPDY in Chrome","weight":1},"url":{"advice":"","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.","id":"url","offending":[],"score":100,"tags":["bestpractice"],"title":"Have a good URL format","weight":2},"longHeaders":{"id":"longHeaders","title":"Do not send too long headers","description":"Do not send response headers that are too long.","advice":"","weight":1,"tags":["bestpractice","header"],"score":100,"offending":[]},"manyHeaders":{"id":"manyHeaders","title":"Avoid use too many response headers","description":"Avoid send too many response headers.","advice":"","weight":1,"tags":["bestpractice","headers"],"score":100,"offending":[]},"thirdParty":{"id":"thirdParty","title":"Avoid too many third party requests","description":"Do not load most of your content from third party URLs.","advice":"","weight":7,"tags":["bestpractice"],"score":100,"offending":[]},"unnecessaryHeaders":{"id":"unnecessaryHeaders","title":"Avoid unnecessary headers","description":"Do not send headers that you don't need. We look for p3p, cache-control and max-age, pragma, server and x-frame-options headers. Have a look at Andrew Betts - Headers for Hackers talk as a guide https://www.youtube.com/watch?v=k92ZbrY815c or read https://www.fastly.com/blog/headers-we-dont-want.","advice":"There are 11 responses that sets a server header. ","weight":1,"tags":["bestpractice","header"],"score":89,"offending":["https://www.sitespeed.io/","https://www.sitespeed.io/css/prism-1.15.css","https://www.sitespeed.io/js/clipboard-2.0.4.min.js","https://www.sitespeed.io/img/team.png","https://www.sitespeed.io/img/pippi.png","https://www.sitespeed.io/img/dashboard-front.png","https://www.sitespeed.io/js/prism-1.15.js","https://www.sitespeed.io/img/public.png","https://www.sitespeed.io/img/sitespeed-logo-2c.png","https://www.sitespeed.io/img/black-logo-120.png","https://www.sitespeed.io/img/ico/sitespeed.io.ico"]}},"score":100},"info":{"amp":false,"browser":"Chrome 119.0.0.0","connectionType":"h2","documentHeight":4372,"documentTitle":"Welcome to the wonderful world of Web Performance","documentWidth":1366,"domDepth":{"avg":8,"max":13},"domElements":368,"generator":null,"head":{"css":["https://www.sitespeed.io/css/prism-1.15.css"],"jsasync":[],"jssync":[]},"iframes":0,"localStorageSize":0,"metaDescription":"Sitespeed.io is an open source tool that helps you analyse and optimise your website speed and performance, based on performance best practices.","networkConnectionType":"4g","resourceHints":{"dns-prefetch":[],"preconnect":[],"prefetch":[],"prerender":[]},"responsive":true,"scripts":4,"serializedDomSize":16837,"serviceWorker":false,"sessionStorageSize":0,"userTiming":{"marks":2,"measures":1},"windowSize":"1366x623","pageTransferSize":"210.7 kB","pageContentSize":"257.7 kB","pageRequests":11,"pageDomains":1,"pageContentTypes":{"html":{"transferSize":9852,"contentSize":37800,"headerSize":0,"requests":1},"css":{"transferSize":1250,"contentSize":3553,"headerSize":0,"requests":1},"javascript":{"transferSize":9707,"contentSize":27296,"headerSize":0,"requests":2},"image":{"transferSize":183283,"contentSize":182560,"headerSize":0,"requests":6},"font":{"transferSize":0,"contentSize":0,"headerSize":0,"requests":0},"favicon":{"transferSize":6636,"contentSize":6518,"headerSize":0,"requests":1}},"pageExpireStats":{"min":"0 seconds","median":"6 weeks","max":"6 weeks","total":"1 year","values":"11 seconds"},"thirdParty":{"requestsByCategory":{},"requestsByTool":{}},"technology":[{"name":"Netlify","description":"Netlify providers hosting and server-less backend services for web applications and static websites.","slug":"netlify","categories":[{"id":62,"slug":"paas","groups":[7],"name":"PaaS","priority":8},{"id":31,"slug":"cdn","groups":[7],"name":"CDN","priority":9}],"confidence":100,"version":"","icon":"Netlify.svg","website":"https://www.netlify.com/","pricing":[],"cpe":null},{"name":"HSTS","description":"HTTP Strict Transport Security (HSTS) informs browsers that the site should only be accessed using HTTPS.","slug":"hsts","categories":[{"id":16,"slug":"security","groups":[11],"name":"Security","priority":9}],"confidence":100,"version":"","icon":"default.svg","website":"https://www.rfc-editor.org/rfc/rfc6797#section-6.1","pricing":[],"cpe":null}],"thirdparty":{"thirdPartyTransferSizeBytes":0,"totalThirdPartyRequests":0,"toolsByCategory":{},"byCategory":{},"offending":[]}},"performance":{"adviceList":{"avoidRenderBlocking":{"advice":"There are no render blocking resources.","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.","id":"avoidRenderBlocking","offending":[],"score":100,"tags":["performance"],"title":"Avoid slowing down the critical rendering path","weight":10},"avoidScalingImages":{"advice":"The page has 4 images that are scaled more than 100 pixels. It would be better if those images are sent so the browser don't need to scale them.","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.","id":"avoidScalingImages","offending":["https://www.sitespeed.io/img/sitespeed-logo-2c.png","https://www.sitespeed.io/img/pippi.png","https://www.sitespeed.io/img/dashboard-front.png","https://www.sitespeed.io/img/public.png"],"score":60,"tags":["performance","image"],"title":"Don't scale images in the browser","weight":5},"cssPrint":{"advice":"","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.","id":"cssPrint","offending":[],"score":100,"tags":["performance","css"],"title":"Do not load specific print stylesheets.","weight":1},"firstContentfulPaint":{"advice":"","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), elements, or non-white elements.","id":"firstContentfulPaint","offending":[],"score":100,"tags":["performance"],"title":"Have a fast first contentful paint","weight":7},"googleTagManager":{"advice":"","description":"Google Tag Manager makes it possible for non tech users to add scripts to your page that will downgrade performance.","id":"googleTagManager","offending":[],"score":100,"tags":["performance","js"],"title":"Avoid using Google Tag Manager.","weight":5},"inlineCss":{"advice":"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.","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.","id":"inlineCss","offending":[],"score":95,"tags":["performance","css"],"title":"Inline CSS for faster first render","weight":7},"jquery":{"advice":"","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.","id":"jquery","offending":[],"score":100,"tags":["jQuery","performance"],"title":"Avoid using more than one jQuery version per page","weight":4},"largestContentfulPaint":{"advice":" You can add fetchPriority=\"high\" to the image to increase the load priority in Chrome.","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.","id":"largestContentfulPaint","offending":[],"score":95,"tags":["performance"],"title":"Have a fast largest contentful paint","weight":7},"longTasks":{"advice":"The page has 1 CPU long task with the total of 103 ms. The total blocking time is 53 ms . 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.","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.","id":"longTasks","offending":["unknown"],"score":80,"tags":["performance","js"],"title":"Avoid CPU Long Tasks","weight":8},"spof":{"advice":"","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.","id":"spof","offending":[],"score":100,"tags":["performance","css","js"],"title":"Avoid Frontend single point of failures","weight":7},"assetsRedirects":{"id":"assetsRedirects","title":"Avoid doing redirects","description":"A redirect is one extra step for the user to download the asset. Avoid that if you want to be fast. Redirects are even more of a showstopper on mobile.","advice":"","weight":2,"tags":["performance"],"score":100,"offending":[]},"cacheHeaders":{"id":"cacheHeaders","title":"Avoid extra requests by setting cache headers","description":"The easiest way to make your page fast is to avoid doing requests to the server. Setting a cache header on your server response will tell the browser that it doesn't need to download the asset again during the configured cache time! Always try to set a cache time if the content doesn't change for every request.","advice":"","weight":30,"tags":["performance","server"],"score":100,"offending":[]},"cacheHeadersLong":{"id":"cacheHeadersLong","title":"Long cache headers is good","description":"Setting a cache header is good. Setting a long cache header (at least 30 days) is even better beacause then it will stay long in the browser cache. But what do you do if that asset change? Rename it and the browser will pick up the new version.","advice":"","weight":3,"tags":["performance","server"],"score":100,"offending":[]},"compressAssets":{"id":"compressAssets","title":"Always compress text content","description":"In the early days of the Internet there were browsers that didn't support compressing (gzipping) text content. They do now. Make sure you compress HTML, JSON, JavaScript, CSS and SVG. It will save bytes for the user; making the page load faster and use less bandwith. ","advice":"","weight":8,"tags":["performance","server"],"score":100,"offending":[]},"connectionKeepAlive":{"id":"connectionKeepAlive","title":"Don't close a connection that is used multiple times","description":"Use keep-alive headers and don't close the connection when we have multiple requests to the same domain. There has been some hacks in the past that suggested closing the connection as fast as possible in order to create new ones, but that shouldn't be applicable anymore.","advice":"","weight":5,"tags":["performance","server"],"score":100,"offending":[]},"cpuTimeSpentInRendering":{"id":"cpuTimeSpentInRendering","title":"Avoid spend too much CPU time to render the page","description":"You need to be able to render the page fast. This metric depends on which computer/device you run on but the limit here is high: Spending more time than 500 ms will alert this advice.","advice":"We can only get CPU spent time if you use Chrome to test the page.","weight":7,"tags":["performance","CSS"],"score":100,"offending":[]},"cpuTimeSpentInScripting":{"id":"cpuTimeSpentInScripting","title":"Avoid executing too much JavaScript","description":"Do not run too much JavaSript, that will slow down the page for your user. This metric depends on which computer/device you run on but the limit here is high: Spending more time than 1000 ms will alert this advice","advice":"We can only get CPU spent time if you use Chrome to test the page.","weight":7,"tags":["performance","JavaScript"],"score":100,"offending":[]},"cssSize":{"id":"cssSize","title":"Total CSS size shouldn't be too big","description":"Delivering a massive amount of CSS to the browser is not the best thing you can do, because it means more work for the browser when parsing the CSS against the HTML and that makes the rendering slower. Try to send only the CSS that is used on that page. And make sure to remove CSS rules when they aren't used anymore.","advice":"","weight":5,"tags":["performance","css"],"score":100,"offending":[{"url":"https://www.sitespeed.io/css/prism-1.15.css","transferSize":1250,"contentSize":3553}]},"documentRedirect":{"id":"documentRedirect","title":"Avoid redirecting the main document","description":"You should never ever redirect the main document, because it will make the page load slower for the user. Well, you should redirect the user if the user tries to use HTTP and there's an HTTPS version of the page. The coach checks for that. :)","advice":"","weight":9,"tags":["performance"],"score":100,"offending":[]},"favicon":{"id":"favicon","title":"The favicon should be small and cacheable","description":"It is easy to make the favicon big but please avoid doing that, because every browser will then perform an unnecessarily large download. And make sure the cache headers are set for a long time for the favicon. It is easy to miss since it's another content type.","advice":"","weight":1,"tags":["performance","favicon"],"score":100,"offending":[]},"fewFonts":{"id":"fewFonts","title":"Avoid too many fonts","description":"How many fonts do you need on a page for the user to get the message? Fonts can slow down the rendering of content, try to avoid loading too many of them because worst case it can make the text invisible until they are loaded (FOIT—flash of invisible text), best case they will flicker the text content when they arrive.","advice":"","weight":2,"tags":["performance","font"],"score":100,"offending":[]},"fewRequestsPerDomain":{"id":"fewRequestsPerDomain","title":"Avoid too many requests per domain [HTTP/1]","description":"Browsers have a limit on how many concurrent requests they can do per domain when using HTTP/1. When you hit the limit, the browser will wait before it can download more assets on that domain. So avoid having too many requests per domain.","advice":"There are almost no limits on HTTP/2 connections with the number of requests, but that is not completely true. It depends on how they are downloaded. Please check your HAR file, does it look OK?","weight":5,"tags":["performance","HTTP/1"],"score":100,"offending":[]},"headerSize":{"id":"headerSize","title":"Response headers should't be too big [HTTP/1]","description":"Avoid a lot of cookies and other stuff that makes your headers big when you use HTTP/1 because the headers are not compressed. You will send extra data to the user.","advice":"The page uses an HTTP/2 connection and the headers are sent compressed, that's good. The current coach version cannot say if the size is good or not.","weight":4,"tags":["performance","mobile"],"score":100,"offending":[]},"imageSize":{"id":"imageSize","title":"Total image size shouldn't be too big","description":"Avoid having too many large images on the page. The images will not affect the first paint of the page, but it will eat bandwidth for the user.","advice":"","weight":5,"tags":["performance","image"],"score":100,"offending":[]},"javascriptSize":{"id":"javascriptSize","title":"Total JavaScript size shouldn't be too big","description":"A lot of JavaScript often means you are downloading more than you need. How complex is the page and what can the user do on the page? Do you use multiple JavaScript frameworks?","advice":"","weight":5,"tags":["performance","javascript"],"score":100,"offending":[]},"mimeTypes":{"id":"mimeTypes","title":"Avoid using incorrect mime types","description":"It's not a great idea to let browsers guess content types (content sniffing), in some cases it can actually be a security risk.","advice":"","weight":0,"tags":["performance","bestpractice"],"score":100,"offending":[]},"optimalCssSize":{"id":"optimalCssSize","title":"Make each CSS response small","description":"Make CSS responses small to fit into the magic number TCP window size of 14.5 KB. The browser can then download the CSS faster and that will make the page start rendering earlier.","advice":"","weight":3,"tags":["performance","css"],"score":100,"offending":[]},"pageSize":{"id":"pageSize","title":"Total page size shouldn't be too big","description":"Avoid having pages that have a transfer size over the wire of more than 2 MB (desktop) and 1 MB (mobile) because that is really big and will hurt performance and will make the page expensive for the user if she/he pays for the bandwidth.","advice":"","weight":3,"tags":["performance","mobile"],"score":100,"offending":[]},"privateAssets":{"id":"privateAssets","title":"Don't use private headers on static content","description":"If you set private headers on content, that means that the content are specific for that user. Static content should be able to be cached and used by everyone. Avoid setting the cache header to private.","advice":"","weight":5,"tags":["performance","server"],"score":100,"offending":[]},"responseOk":{"id":"responseOk","title":"Avoid missing and error requests","description":"Your page should never request assets that return a 400 or 500 error. These requests are never cached. If that happens something is broken. Please fix it.","advice":"","weight":7,"tags":["performance","server"],"score":100,"offending":[]}},"score":98},"privacy":{"adviceList":{"facebook":{"advice":"","description":"You share share private user information with Facebook that your user hasn't agreed on sharing.","id":"facebook","offending":[],"score":100,"tags":["privacy"],"title":"Avoid including Facebook","weight":8},"fingerprint":{"advice":"","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","id":"fingerprint","offending":[],"score":100,"tags":["privacy"],"title":"Do not fingerprint your user.","weight":8},"ga":{"advice":"","description":"Google Analytics share private user information with Google that your user hasn't agreed on sharing.","id":"ga","offending":[],"score":100,"tags":["privacy"],"title":"Avoid using Google Analytics","weight":8},"https":{"advice":"","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/.","id":"https","offending":[],"score":100,"tags":["privacy"],"title":"Serve your content securely","weight":10},"surveillance":{"advice":"","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","id":"surveillance","offending":[],"score":100,"tags":["privacy"],"title":"Avoid using surveillance web sites","weight":10},"youtube":{"advice":"","description":"If you include Youtube videos on your page, you are sharing private user information with Google.","id":"youtube","offending":[],"score":100,"tags":["privacy"],"title":"Avoid including Youtube videos","weight":6},"contentSecurityPolicyHeader":{"id":"contentSecurityPolicyHeader","title":"Use a good Content-Security-Policy header to make sure you you avoid Cross Site Scripting (XSS) attacks.","description":"Content Security Policy is delivered via a HTTP response header, and defines approved sources of content that the browser may load. It can be an effective countermeasure to Cross Site Scripting (XSS) attacks and is also widely supported and usually easily deployed. https://scotthelme.co.uk/content-security-policy-an-introduction/.","advice":"","weight":5,"tags":["privacy","bestpractice","headers"],"score":100,"offending":[]},"googleReCaptcha":{"id":"googleReCaptcha","title":"Avoid using Google reCAPTCHA","description":"You should avoid using Google reCAPTCHA since it will share your users information with Google.","advice":"","weight":9,"tags":["privacy"],"score":100,"offending":[]},"mixedContent":{"id":"mixedContent","title":"Serve all responses on HTTPS (when you are on HTTPS)","description":"You need to make sure that if you are on HTTPS, all responses are on HTTPS so that the content served are secured.","advice":"","weight":7,"tags":["privacy"],"score":100,"offending":[]},"referrerPolicyHeader":{"id":"referrerPolicyHeader","title":"Set a referrer-policy header to make sure you do not leak user information.","description":"Referrer Policy is a new header that allows a site to control how much information the browser includes with navigations away from a document and should be set by all sites. https://scotthelme.co.uk/a-new-security-header-referrer-policy/.","advice":"","weight":6,"tags":["headers","privacy"],"score":100,"offending":[]},"strictTransportSecurityHeader":{"id":"strictTransportSecurityHeader","title":"Set a strict transport header to make sure the user always use HTTPS.","description":"The HTTP Strict-Transport-Security response header (often abbreviated as HSTS) lets a web site tell browsers that it should only be accessed using HTTPS, instead of using HTTP. https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security.","advice":"","weight":6,"tags":["headers","privacy"],"score":100,"offending":[]},"thirdPartyCookies":{"id":"thirdPartyCookies","title":"Avoid third party cookies that is used to track the user.","description":"Third party cookies are used to track the user. They are automatically blocked in Safari and Firefox.","advice":"","weight":6,"tags":["cookies","privacy"],"score":100,"offending":[]},"thirdPartyPrivacy":{"id":"thirdPartyPrivacy","title":"Do not share user data with third parties.","description":"Using third party requests shares user information with that third party. Please avoid that! The project https://github.com/patrickhulce/third-party-web is used to categorize first/third party requests.","advice":"The page has 0% requests that are 3rd party (0 requests with a size of 0 B).","weight":5,"tags":["privacy"],"score":100,"offending":[]}},"score":100},"score":99,"timings":{"elementTimings":{"header-logo":{"duration":0,"loadTime":663,"naturalHeight":100,"naturalWidth":324,"renderTime":717,"startTime":717,"tagName":"IMG","url":"https://www.sitespeed.io/img/sitespeed-logo-2c.png"},"logo":{"duration":0,"loadTime":728,"naturalHeight":865,"naturalWidth":1000,"renderTime":717,"startTime":717,"tagName":"IMG","url":"https://www.sitespeed.io/img/team.png"}},"fullyLoaded":1007.1000000014901,"largestContentfulPaint":{"duration":0,"id":"","loadTime":728,"renderTime":898,"size":216250,"startTime":898,"tagName":"IMG","url":"https://www.sitespeed.io/img/team.png"},"navigationTimings":{"connectEnd":260,"connectStart":41,"domComplete":835,"domContentLoadedEventEnd":834,"domContentLoadedEventStart":834,"domInteractive":829,"domLoading":431,"domainLookupEnd":41,"domainLookupStart":41,"fetchStart":6,"loadEventEnd":835,"loadEventStart":835,"navigationStart":0,"requestStart":262,"responseEnd":458,"responseStart":422,"secureConnectionStart":72},"paintTimings":{"first-contentful-paint":717,"first-paint":717},"userTimings":{"marks":[{"name":"userTimingHeader","startTime":721.5},{"name":"userTimingFooter","startTime":724.5}],"measures":[{"duration":3,"name":"exampleMeasurement","startTime":721.5}]}}},"errors":{},"url":"https://www.sitespeed.io/","version":"8.0.2","thirdPartyWebVersion":"0.24.0","wappalyzerVersion":"6.10.66"}}},{"browser":{"cpuBenchmark":80,"userAgent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36","windowSize":"1366x623"},"pageinfo":{"cumulativeLayoutShift":0,"cumulativeLayoutShiftInfo":[],"documentHeight":4372,"documentSize":{"decodedBodySize":37800,"encodedBodySize":9375,"transferSize":9675},"documentTitle":"Welcome to the wonderful world of Web Performance","documentWidth":1366,"domElements":368,"largestContentfulPaintInfo":[{"className":"","domPath":"body > main > div:eq(0) > div > div:eq(0) > picture > img","duration":0,"id":"","loadTime":620,"renderTime":714,"size":216250,"startTime":714,"tag":"\"sitespeed.io","tagName":"IMG","url":"https://www.sitespeed.io/img/team.png"}],"navigationStartTime":1700795793319,"nextHopProtocol":"h2","resources":{"count":10,"duration":2102.2000000029802,"servedFromCache":0},"responsive":true,"url":"https://www.sitespeed.io/","visualElements":{"heroes":[{"filename":"team.png","height":433,"html":"\"sitespeed.io","name":"LargestImage","width":500,"x":153,"y":50},{"filename":null,"height":173,"html":"

","name":"Heading","width":510,"x":703,"y":66},{"filename":"sitespeed-logo-2c.png","height":50,"html":"\"Sitespeed.io","name":"header-logo","width":162,"x":153,"y":0},{"filename":"team.png","height":433,"html":"\"sitespeed.io","name":"logo","width":500,"x":153,"y":50},{"filename":"team.png","height":433,"html":"\"sitespeed.io","name":"LargestContentfulPaint","width":500,"x":153,"y":50}],"viewport":{"height":623,"width":1366}},"longTask":[{"attribution":[{"containerId":"","containerName":"","containerSrc":"","containerType":"window"}],"duration":85,"name":"unknown","startTime":527.1000000014901}]},"timings":{"elementTimings":{"header-logo":{"duration":0,"loadTime":616,"naturalHeight":100,"naturalWidth":324,"renderTime":714,"startTime":714,"tagName":"IMG","url":"https://www.sitespeed.io/img/sitespeed-logo-2c.png"},"logo":{"duration":0,"loadTime":620,"naturalHeight":865,"naturalWidth":1000,"renderTime":714,"startTime":714,"tagName":"IMG","url":"https://www.sitespeed.io/img/team.png"}},"firstPaint":530,"largestContentfulPaint":{"className":"","domPath":"body > main > div:eq(0) > div > div:eq(0) > picture > img","duration":0,"id":"","loadTime":620,"renderTime":714,"size":216250,"startTime":714,"tag":"\"sitespeed.io","tagName":"IMG","url":"https://www.sitespeed.io/img/team.png"},"loadEventEnd":645,"navigationTiming":{"connectStart":37,"domComplete":645,"domContentLoadedEventEnd":644,"domContentLoadedEventStart":644,"domInteractive":617,"domainLookupEnd":37,"domainLookupStart":37,"duration":645,"fetchStart":5,"loadEventEnd":645,"loadEventStart":645,"redirectEnd":0,"redirectStart":0,"requestStart":107,"responseEnd":361,"responseStart":329,"secureConnectionStart":69,"startTime":0,"unloadEventEnd":0,"unloadEventStart":0,"workerStart":0},"pageTimings":{"backEndTime":329,"domContentLoadedTime":644,"domInteractiveTime":617,"domainLookupTime":0,"frontEndTime":284,"pageDownloadTime":32,"pageLoadTime":645,"redirectionTime":0,"serverConnectionTime":70,"serverResponseTime":254},"paintTiming":{"first-contentful-paint":530,"first-paint":530},"serverTimings":[],"ttfb":329,"userTimings":{"marks":[{"name":"userTimingHeader","startTime":490.3999999985099},{"name":"userTimingFooter","startTime":526.2999999970198}],"measures":[{"duration":35.899999998509884,"name":"exampleMeasurement","startTime":490.3999999985099}]}},"coach":{"coachAdvice":{"advice":{"bestpractice":{"adviceList":{"amp":{"advice":"","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.","id":"amp","offending":[],"score":100,"tags":["bestpractice"],"title":"Avoid using AMP","weight":10},"charset":{"advice":"","description":"The Unicode Standard (UTF-8) covers (almost) all the characters, punctuations, and symbols in the world. Please use that.","id":"charset","offending":[],"score":100,"tags":["bestpractice"],"title":"Declare a charset in your document","weight":2},"cumulativeLayoutShift":{"advice":"There is no Layout Shift on the page.","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.","id":"cumulativeLayoutShift","offending":[],"score":100,"tags":["bestpractice"],"title":"Cumulative Layout Shift","weight":8},"doctype":{"advice":"","description":"The declaration is not an HTML tag; it is an instruction to the web browser about what version of HTML the page is written in.","id":"doctype","offending":[],"score":100,"tags":["bestpractice"],"title":"Declare a doctype in your document","weight":2},"language":{"advice":"","description":"According to the W3C recommendation you should declare the primary language for each Web page with the lang attribute inside the tag https://www.w3.org/International/questions/qa-html-language-declarations#basics.","id":"language","offending":[],"score":100,"tags":["bestpractice"],"title":"Declare the language code for your document","weight":3},"metaDescription":{"advice":"","description":"Use a page description to make the page more relevant to search engines.","id":"metaDescription","offending":[],"score":100,"tags":["bestpractice"],"title":"Meta description","weight":5},"optimizely":{"advice":"","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.","id":"optimizely","offending":[],"score":100,"tags":["bestpractice"],"title":"Only use Optimizely when you need it","weight":2},"pageTitle":{"advice":"","description":"Use a title to make the page more relevant to search engines.","id":"pageTitle","offending":[],"score":100,"tags":["bestpractice"],"title":"Page title","weight":5},"spdy":{"advice":"","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.","id":"spdy","offending":[],"score":100,"tags":["bestpractice"],"title":"EOL for SPDY in Chrome","weight":1},"url":{"advice":"","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.","id":"url","offending":[],"score":100,"tags":["bestpractice"],"title":"Have a good URL format","weight":2},"longHeaders":{"id":"longHeaders","title":"Do not send too long headers","description":"Do not send response headers that are too long.","advice":"","weight":1,"tags":["bestpractice","header"],"score":100,"offending":[]},"manyHeaders":{"id":"manyHeaders","title":"Avoid use too many response headers","description":"Avoid send too many response headers.","advice":"","weight":1,"tags":["bestpractice","headers"],"score":100,"offending":[]},"thirdParty":{"id":"thirdParty","title":"Avoid too many third party requests","description":"Do not load most of your content from third party URLs.","advice":"","weight":7,"tags":["bestpractice"],"score":100,"offending":[]},"unnecessaryHeaders":{"id":"unnecessaryHeaders","title":"Avoid unnecessary headers","description":"Do not send headers that you don't need. We look for p3p, cache-control and max-age, pragma, server and x-frame-options headers. Have a look at Andrew Betts - Headers for Hackers talk as a guide https://www.youtube.com/watch?v=k92ZbrY815c or read https://www.fastly.com/blog/headers-we-dont-want.","advice":"There are 11 responses that sets a server header. ","weight":1,"tags":["bestpractice","header"],"score":89,"offending":["https://www.sitespeed.io/","https://www.sitespeed.io/css/prism-1.15.css","https://www.sitespeed.io/js/clipboard-2.0.4.min.js","https://www.sitespeed.io/img/team.png","https://www.sitespeed.io/img/pippi.png","https://www.sitespeed.io/img/dashboard-front.png","https://www.sitespeed.io/js/prism-1.15.js","https://www.sitespeed.io/img/sitespeed-logo-2c.png","https://www.sitespeed.io/img/public.png","https://www.sitespeed.io/img/black-logo-120.png","https://www.sitespeed.io/img/ico/sitespeed.io.ico"]}},"score":100},"info":{"amp":false,"browser":"Chrome 119.0.0.0","connectionType":"h2","documentHeight":4372,"documentTitle":"Welcome to the wonderful world of Web Performance","documentWidth":1366,"domDepth":{"avg":8,"max":13},"domElements":368,"generator":null,"head":{"css":["https://www.sitespeed.io/css/prism-1.15.css"],"jsasync":[],"jssync":[]},"iframes":0,"localStorageSize":0,"metaDescription":"Sitespeed.io is an open source tool that helps you analyse and optimise your website speed and performance, based on performance best practices.","networkConnectionType":"4g","resourceHints":{"dns-prefetch":[],"preconnect":[],"prefetch":[],"prerender":[]},"responsive":true,"scripts":4,"serializedDomSize":16837,"serviceWorker":false,"sessionStorageSize":0,"userTiming":{"marks":2,"measures":1},"windowSize":"1366x623","pageTransferSize":"210.7 kB","pageContentSize":"257.7 kB","pageRequests":11,"pageDomains":1,"pageContentTypes":{"html":{"transferSize":9844,"contentSize":37800,"headerSize":0,"requests":1},"css":{"transferSize":1279,"contentSize":3553,"headerSize":0,"requests":1},"javascript":{"transferSize":9662,"contentSize":27296,"headerSize":0,"requests":2},"image":{"transferSize":183243,"contentSize":182560,"headerSize":0,"requests":6},"font":{"transferSize":0,"contentSize":0,"headerSize":0,"requests":0},"favicon":{"transferSize":6660,"contentSize":6518,"headerSize":0,"requests":1}},"pageExpireStats":{"min":"0 seconds","median":"6 weeks","max":"6 weeks","total":"1 year","values":"11 seconds"},"thirdParty":{"requestsByCategory":{},"requestsByTool":{}},"technology":[{"name":"Netlify","description":"Netlify providers hosting and server-less backend services for web applications and static websites.","slug":"netlify","categories":[{"id":62,"slug":"paas","groups":[7],"name":"PaaS","priority":8},{"id":31,"slug":"cdn","groups":[7],"name":"CDN","priority":9}],"confidence":100,"version":"","icon":"Netlify.svg","website":"https://www.netlify.com/","pricing":[],"cpe":null},{"name":"HSTS","description":"HTTP Strict Transport Security (HSTS) informs browsers that the site should only be accessed using HTTPS.","slug":"hsts","categories":[{"id":16,"slug":"security","groups":[11],"name":"Security","priority":9}],"confidence":100,"version":"","icon":"default.svg","website":"https://www.rfc-editor.org/rfc/rfc6797#section-6.1","pricing":[],"cpe":null}],"thirdparty":{"thirdPartyTransferSizeBytes":0,"totalThirdPartyRequests":0,"toolsByCategory":{},"byCategory":{},"offending":[]}},"performance":{"adviceList":{"avoidRenderBlocking":{"advice":"There are no render blocking resources.","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.","id":"avoidRenderBlocking","offending":[],"score":100,"tags":["performance"],"title":"Avoid slowing down the critical rendering path","weight":10},"avoidScalingImages":{"advice":"The page has 4 images that are scaled more than 100 pixels. It would be better if those images are sent so the browser don't need to scale them.","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.","id":"avoidScalingImages","offending":["https://www.sitespeed.io/img/sitespeed-logo-2c.png","https://www.sitespeed.io/img/pippi.png","https://www.sitespeed.io/img/dashboard-front.png","https://www.sitespeed.io/img/public.png"],"score":60,"tags":["performance","image"],"title":"Don't scale images in the browser","weight":5},"cssPrint":{"advice":"","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.","id":"cssPrint","offending":[],"score":100,"tags":["performance","css"],"title":"Do not load specific print stylesheets.","weight":1},"firstContentfulPaint":{"advice":"","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), elements, or non-white elements.","id":"firstContentfulPaint","offending":[],"score":100,"tags":["performance"],"title":"Have a fast first contentful paint","weight":7},"googleTagManager":{"advice":"","description":"Google Tag Manager makes it possible for non tech users to add scripts to your page that will downgrade performance.","id":"googleTagManager","offending":[],"score":100,"tags":["performance","js"],"title":"Avoid using Google Tag Manager.","weight":5},"inlineCss":{"advice":"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.","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.","id":"inlineCss","offending":[],"score":95,"tags":["performance","css"],"title":"Inline CSS for faster first render","weight":7},"jquery":{"advice":"","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.","id":"jquery","offending":[],"score":100,"tags":["jQuery","performance"],"title":"Avoid using more than one jQuery version per page","weight":4},"largestContentfulPaint":{"advice":" You can add fetchPriority=\"high\" to the image to increase the load priority in Chrome.","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.","id":"largestContentfulPaint","offending":[],"score":95,"tags":["performance"],"title":"Have a fast largest contentful paint","weight":7},"longTasks":{"advice":"The page has 1 CPU long task with the total of 85 ms. The total blocking time is 0 ms and 1 long task before first contentful paint with total time of 85 ms. 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.","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.","id":"longTasks","offending":["unknown"],"score":80,"tags":["performance","js"],"title":"Avoid CPU Long Tasks","weight":8},"spof":{"advice":"","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.","id":"spof","offending":[],"score":100,"tags":["performance","css","js"],"title":"Avoid Frontend single point of failures","weight":7},"assetsRedirects":{"id":"assetsRedirects","title":"Avoid doing redirects","description":"A redirect is one extra step for the user to download the asset. Avoid that if you want to be fast. Redirects are even more of a showstopper on mobile.","advice":"","weight":2,"tags":["performance"],"score":100,"offending":[]},"cacheHeaders":{"id":"cacheHeaders","title":"Avoid extra requests by setting cache headers","description":"The easiest way to make your page fast is to avoid doing requests to the server. Setting a cache header on your server response will tell the browser that it doesn't need to download the asset again during the configured cache time! Always try to set a cache time if the content doesn't change for every request.","advice":"","weight":30,"tags":["performance","server"],"score":100,"offending":[]},"cacheHeadersLong":{"id":"cacheHeadersLong","title":"Long cache headers is good","description":"Setting a cache header is good. Setting a long cache header (at least 30 days) is even better beacause then it will stay long in the browser cache. But what do you do if that asset change? Rename it and the browser will pick up the new version.","advice":"","weight":3,"tags":["performance","server"],"score":100,"offending":[]},"compressAssets":{"id":"compressAssets","title":"Always compress text content","description":"In the early days of the Internet there were browsers that didn't support compressing (gzipping) text content. They do now. Make sure you compress HTML, JSON, JavaScript, CSS and SVG. It will save bytes for the user; making the page load faster and use less bandwith. ","advice":"","weight":8,"tags":["performance","server"],"score":100,"offending":[]},"connectionKeepAlive":{"id":"connectionKeepAlive","title":"Don't close a connection that is used multiple times","description":"Use keep-alive headers and don't close the connection when we have multiple requests to the same domain. There has been some hacks in the past that suggested closing the connection as fast as possible in order to create new ones, but that shouldn't be applicable anymore.","advice":"","weight":5,"tags":["performance","server"],"score":100,"offending":[]},"cpuTimeSpentInRendering":{"id":"cpuTimeSpentInRendering","title":"Avoid spend too much CPU time to render the page","description":"You need to be able to render the page fast. This metric depends on which computer/device you run on but the limit here is high: Spending more time than 500 ms will alert this advice.","advice":"We can only get CPU spent time if you use Chrome to test the page.","weight":7,"tags":["performance","CSS"],"score":100,"offending":[]},"cpuTimeSpentInScripting":{"id":"cpuTimeSpentInScripting","title":"Avoid executing too much JavaScript","description":"Do not run too much JavaSript, that will slow down the page for your user. This metric depends on which computer/device you run on but the limit here is high: Spending more time than 1000 ms will alert this advice","advice":"We can only get CPU spent time if you use Chrome to test the page.","weight":7,"tags":["performance","JavaScript"],"score":100,"offending":[]},"cssSize":{"id":"cssSize","title":"Total CSS size shouldn't be too big","description":"Delivering a massive amount of CSS to the browser is not the best thing you can do, because it means more work for the browser when parsing the CSS against the HTML and that makes the rendering slower. Try to send only the CSS that is used on that page. And make sure to remove CSS rules when they aren't used anymore.","advice":"","weight":5,"tags":["performance","css"],"score":100,"offending":[{"url":"https://www.sitespeed.io/css/prism-1.15.css","transferSize":1279,"contentSize":3553}]},"documentRedirect":{"id":"documentRedirect","title":"Avoid redirecting the main document","description":"You should never ever redirect the main document, because it will make the page load slower for the user. Well, you should redirect the user if the user tries to use HTTP and there's an HTTPS version of the page. The coach checks for that. :)","advice":"","weight":9,"tags":["performance"],"score":100,"offending":[]},"favicon":{"id":"favicon","title":"The favicon should be small and cacheable","description":"It is easy to make the favicon big but please avoid doing that, because every browser will then perform an unnecessarily large download. And make sure the cache headers are set for a long time for the favicon. It is easy to miss since it's another content type.","advice":"","weight":1,"tags":["performance","favicon"],"score":100,"offending":[]},"fewFonts":{"id":"fewFonts","title":"Avoid too many fonts","description":"How many fonts do you need on a page for the user to get the message? Fonts can slow down the rendering of content, try to avoid loading too many of them because worst case it can make the text invisible until they are loaded (FOIT—flash of invisible text), best case they will flicker the text content when they arrive.","advice":"","weight":2,"tags":["performance","font"],"score":100,"offending":[]},"fewRequestsPerDomain":{"id":"fewRequestsPerDomain","title":"Avoid too many requests per domain [HTTP/1]","description":"Browsers have a limit on how many concurrent requests they can do per domain when using HTTP/1. When you hit the limit, the browser will wait before it can download more assets on that domain. So avoid having too many requests per domain.","advice":"There are almost no limits on HTTP/2 connections with the number of requests, but that is not completely true. It depends on how they are downloaded. Please check your HAR file, does it look OK?","weight":5,"tags":["performance","HTTP/1"],"score":100,"offending":[]},"headerSize":{"id":"headerSize","title":"Response headers should't be too big [HTTP/1]","description":"Avoid a lot of cookies and other stuff that makes your headers big when you use HTTP/1 because the headers are not compressed. You will send extra data to the user.","advice":"The page uses an HTTP/2 connection and the headers are sent compressed, that's good. The current coach version cannot say if the size is good or not.","weight":4,"tags":["performance","mobile"],"score":100,"offending":[]},"imageSize":{"id":"imageSize","title":"Total image size shouldn't be too big","description":"Avoid having too many large images on the page. The images will not affect the first paint of the page, but it will eat bandwidth for the user.","advice":"","weight":5,"tags":["performance","image"],"score":100,"offending":[]},"javascriptSize":{"id":"javascriptSize","title":"Total JavaScript size shouldn't be too big","description":"A lot of JavaScript often means you are downloading more than you need. How complex is the page and what can the user do on the page? Do you use multiple JavaScript frameworks?","advice":"","weight":5,"tags":["performance","javascript"],"score":100,"offending":[]},"mimeTypes":{"id":"mimeTypes","title":"Avoid using incorrect mime types","description":"It's not a great idea to let browsers guess content types (content sniffing), in some cases it can actually be a security risk.","advice":"","weight":0,"tags":["performance","bestpractice"],"score":100,"offending":[]},"optimalCssSize":{"id":"optimalCssSize","title":"Make each CSS response small","description":"Make CSS responses small to fit into the magic number TCP window size of 14.5 KB. The browser can then download the CSS faster and that will make the page start rendering earlier.","advice":"","weight":3,"tags":["performance","css"],"score":100,"offending":[]},"pageSize":{"id":"pageSize","title":"Total page size shouldn't be too big","description":"Avoid having pages that have a transfer size over the wire of more than 2 MB (desktop) and 1 MB (mobile) because that is really big and will hurt performance and will make the page expensive for the user if she/he pays for the bandwidth.","advice":"","weight":3,"tags":["performance","mobile"],"score":100,"offending":[]},"privateAssets":{"id":"privateAssets","title":"Don't use private headers on static content","description":"If you set private headers on content, that means that the content are specific for that user. Static content should be able to be cached and used by everyone. Avoid setting the cache header to private.","advice":"","weight":5,"tags":["performance","server"],"score":100,"offending":[]},"responseOk":{"id":"responseOk","title":"Avoid missing and error requests","description":"Your page should never request assets that return a 400 or 500 error. These requests are never cached. If that happens something is broken. Please fix it.","advice":"","weight":7,"tags":["performance","server"],"score":100,"offending":[]}},"score":98},"privacy":{"adviceList":{"facebook":{"advice":"","description":"You share share private user information with Facebook that your user hasn't agreed on sharing.","id":"facebook","offending":[],"score":100,"tags":["privacy"],"title":"Avoid including Facebook","weight":8},"fingerprint":{"advice":"","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","id":"fingerprint","offending":[],"score":100,"tags":["privacy"],"title":"Do not fingerprint your user.","weight":8},"ga":{"advice":"","description":"Google Analytics share private user information with Google that your user hasn't agreed on sharing.","id":"ga","offending":[],"score":100,"tags":["privacy"],"title":"Avoid using Google Analytics","weight":8},"https":{"advice":"","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/.","id":"https","offending":[],"score":100,"tags":["privacy"],"title":"Serve your content securely","weight":10},"surveillance":{"advice":"","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","id":"surveillance","offending":[],"score":100,"tags":["privacy"],"title":"Avoid using surveillance web sites","weight":10},"youtube":{"advice":"","description":"If you include Youtube videos on your page, you are sharing private user information with Google.","id":"youtube","offending":[],"score":100,"tags":["privacy"],"title":"Avoid including Youtube videos","weight":6},"contentSecurityPolicyHeader":{"id":"contentSecurityPolicyHeader","title":"Use a good Content-Security-Policy header to make sure you you avoid Cross Site Scripting (XSS) attacks.","description":"Content Security Policy is delivered via a HTTP response header, and defines approved sources of content that the browser may load. It can be an effective countermeasure to Cross Site Scripting (XSS) attacks and is also widely supported and usually easily deployed. https://scotthelme.co.uk/content-security-policy-an-introduction/.","advice":"","weight":5,"tags":["privacy","bestpractice","headers"],"score":100,"offending":[]},"googleReCaptcha":{"id":"googleReCaptcha","title":"Avoid using Google reCAPTCHA","description":"You should avoid using Google reCAPTCHA since it will share your users information with Google.","advice":"","weight":9,"tags":["privacy"],"score":100,"offending":[]},"mixedContent":{"id":"mixedContent","title":"Serve all responses on HTTPS (when you are on HTTPS)","description":"You need to make sure that if you are on HTTPS, all responses are on HTTPS so that the content served are secured.","advice":"","weight":7,"tags":["privacy"],"score":100,"offending":[]},"referrerPolicyHeader":{"id":"referrerPolicyHeader","title":"Set a referrer-policy header to make sure you do not leak user information.","description":"Referrer Policy is a new header that allows a site to control how much information the browser includes with navigations away from a document and should be set by all sites. https://scotthelme.co.uk/a-new-security-header-referrer-policy/.","advice":"","weight":6,"tags":["headers","privacy"],"score":100,"offending":[]},"strictTransportSecurityHeader":{"id":"strictTransportSecurityHeader","title":"Set a strict transport header to make sure the user always use HTTPS.","description":"The HTTP Strict-Transport-Security response header (often abbreviated as HSTS) lets a web site tell browsers that it should only be accessed using HTTPS, instead of using HTTP. https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security.","advice":"","weight":6,"tags":["headers","privacy"],"score":100,"offending":[]},"thirdPartyCookies":{"id":"thirdPartyCookies","title":"Avoid third party cookies that is used to track the user.","description":"Third party cookies are used to track the user. They are automatically blocked in Safari and Firefox.","advice":"","weight":6,"tags":["cookies","privacy"],"score":100,"offending":[]},"thirdPartyPrivacy":{"id":"thirdPartyPrivacy","title":"Do not share user data with third parties.","description":"Using third party requests shares user information with that third party. Please avoid that! The project https://github.com/patrickhulce/third-party-web is used to categorize first/third party requests.","advice":"The page has 0% requests that are 3rd party (0 requests with a size of 0 B).","weight":5,"tags":["privacy"],"score":100,"offending":[]}},"score":100},"score":99,"timings":{"elementTimings":{"header-logo":{"duration":0,"loadTime":616,"naturalHeight":100,"naturalWidth":324,"renderTime":714,"startTime":714,"tagName":"IMG","url":"https://www.sitespeed.io/img/sitespeed-logo-2c.png"},"logo":{"duration":0,"loadTime":620,"naturalHeight":865,"naturalWidth":1000,"renderTime":714,"startTime":714,"tagName":"IMG","url":"https://www.sitespeed.io/img/team.png"}},"fullyLoaded":829,"largestContentfulPaint":{"duration":0,"id":"","loadTime":620,"renderTime":714,"size":216250,"startTime":714,"tagName":"IMG","url":"https://www.sitespeed.io/img/team.png"},"navigationTimings":{"connectEnd":106,"connectStart":37,"domComplete":644,"domContentLoadedEventEnd":644,"domContentLoadedEventStart":644,"domInteractive":616,"domLoading":334,"domainLookupEnd":37,"domainLookupStart":37,"fetchStart":5,"loadEventEnd":644,"loadEventStart":644,"navigationStart":0,"requestStart":106,"responseEnd":361,"responseStart":329,"secureConnectionStart":69},"paintTimings":{"first-contentful-paint":530,"first-paint":530},"userTimings":{"marks":[{"name":"userTimingHeader","startTime":490.3999999985099},{"name":"userTimingFooter","startTime":526.2999999970198}],"measures":[{"duration":35.899999998509884,"name":"exampleMeasurement","startTime":490.3999999985099}]}}},"errors":{},"url":"https://www.sitespeed.io/","version":"8.0.2","thirdPartyWebVersion":"0.24.0","wappalyzerVersion":"6.10.66"}}},{"browser":{"cpuBenchmark":80,"userAgent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36","windowSize":"1366x623"},"pageinfo":{"cumulativeLayoutShift":0,"cumulativeLayoutShiftInfo":[],"documentHeight":4372,"documentSize":{"decodedBodySize":37800,"encodedBodySize":9373,"transferSize":9673},"documentTitle":"Welcome to the wonderful world of Web Performance","documentWidth":1366,"domElements":368,"largestContentfulPaintInfo":[{"className":"","domPath":"body > main > div:eq(0) > div > div:eq(0) > picture > img","duration":0,"id":"","loadTime":648,"renderTime":720,"size":216250,"startTime":720,"tag":"\"sitespeed.io","tagName":"IMG","url":"https://www.sitespeed.io/img/team.png"}],"navigationStartTime":1700795822520,"nextHopProtocol":"h2","resources":{"count":10,"duration":2287.8999999910593,"servedFromCache":0},"responsive":true,"url":"https://www.sitespeed.io/","visualElements":{"heroes":[{"filename":"team.png","height":433,"html":"\"sitespeed.io","name":"LargestImage","width":500,"x":153,"y":50},{"filename":null,"height":173,"html":"

","name":"Heading","width":510,"x":703,"y":66},{"filename":"sitespeed-logo-2c.png","height":50,"html":"\"Sitespeed.io","name":"header-logo","width":162,"x":153,"y":0},{"filename":"team.png","height":433,"html":"\"sitespeed.io","name":"logo","width":500,"x":153,"y":50},{"filename":"team.png","height":433,"html":"\"sitespeed.io","name":"LargestContentfulPaint","width":500,"x":153,"y":50}],"viewport":{"height":623,"width":1366}},"longTask":[{"attribution":[{"containerId":"","containerName":"","containerSrc":"","containerType":"window"}],"duration":123,"name":"unknown","startTime":520.7999999970198}]},"timings":{"elementTimings":{"header-logo":{"duration":0,"loadTime":646,"naturalHeight":100,"naturalWidth":324,"renderTime":720,"startTime":720,"tagName":"IMG","url":"https://www.sitespeed.io/img/sitespeed-logo-2c.png"},"logo":{"duration":0,"loadTime":648,"naturalHeight":865,"naturalWidth":1000,"renderTime":720,"startTime":720,"tagName":"IMG","url":"https://www.sitespeed.io/img/team.png"}},"firstPaint":684,"largestContentfulPaint":{"className":"","domPath":"body > main > div:eq(0) > div > div:eq(0) > picture > img","duration":0,"id":"","loadTime":648,"renderTime":720,"size":216250,"startTime":720,"tag":"\"sitespeed.io","tagName":"IMG","url":"https://www.sitespeed.io/img/team.png"},"loadEventEnd":664,"navigationTiming":{"connectStart":38,"domComplete":664,"domContentLoadedEventEnd":664,"domContentLoadedEventStart":664,"domInteractive":647,"domainLookupEnd":38,"domainLookupStart":38,"duration":664,"fetchStart":4,"loadEventEnd":664,"loadEventStart":664,"redirectEnd":0,"redirectStart":0,"requestStart":124,"responseEnd":378,"responseStart":344,"secureConnectionStart":75,"startTime":0,"unloadEventEnd":0,"unloadEventStart":0,"workerStart":0},"pageTimings":{"backEndTime":344,"domContentLoadedTime":664,"domInteractiveTime":647,"domainLookupTime":0,"frontEndTime":286,"pageDownloadTime":34,"pageLoadTime":664,"redirectionTime":0,"serverConnectionTime":85,"serverResponseTime":254},"paintTiming":{"first-contentful-paint":684,"first-paint":684},"serverTimings":[],"ttfb":344,"userTimings":{"marks":[{"name":"userTimingHeader","startTime":519},{"name":"userTimingFooter","startTime":520.6999999880791}],"measures":[{"duration":1.699999988079071,"name":"exampleMeasurement","startTime":519}]}},"coach":{"coachAdvice":{"advice":{"bestpractice":{"adviceList":{"amp":{"advice":"","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.","id":"amp","offending":[],"score":100,"tags":["bestpractice"],"title":"Avoid using AMP","weight":10},"charset":{"advice":"","description":"The Unicode Standard (UTF-8) covers (almost) all the characters, punctuations, and symbols in the world. Please use that.","id":"charset","offending":[],"score":100,"tags":["bestpractice"],"title":"Declare a charset in your document","weight":2},"cumulativeLayoutShift":{"advice":"There is no Layout Shift on the page.","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.","id":"cumulativeLayoutShift","offending":[],"score":100,"tags":["bestpractice"],"title":"Cumulative Layout Shift","weight":8},"doctype":{"advice":"","description":"The declaration is not an HTML tag; it is an instruction to the web browser about what version of HTML the page is written in.","id":"doctype","offending":[],"score":100,"tags":["bestpractice"],"title":"Declare a doctype in your document","weight":2},"language":{"advice":"","description":"According to the W3C recommendation you should declare the primary language for each Web page with the lang attribute inside the tag https://www.w3.org/International/questions/qa-html-language-declarations#basics.","id":"language","offending":[],"score":100,"tags":["bestpractice"],"title":"Declare the language code for your document","weight":3},"metaDescription":{"advice":"","description":"Use a page description to make the page more relevant to search engines.","id":"metaDescription","offending":[],"score":100,"tags":["bestpractice"],"title":"Meta description","weight":5},"optimizely":{"advice":"","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.","id":"optimizely","offending":[],"score":100,"tags":["bestpractice"],"title":"Only use Optimizely when you need it","weight":2},"pageTitle":{"advice":"","description":"Use a title to make the page more relevant to search engines.","id":"pageTitle","offending":[],"score":100,"tags":["bestpractice"],"title":"Page title","weight":5},"spdy":{"advice":"","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.","id":"spdy","offending":[],"score":100,"tags":["bestpractice"],"title":"EOL for SPDY in Chrome","weight":1},"url":{"advice":"","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.","id":"url","offending":[],"score":100,"tags":["bestpractice"],"title":"Have a good URL format","weight":2},"longHeaders":{"id":"longHeaders","title":"Do not send too long headers","description":"Do not send response headers that are too long.","advice":"","weight":1,"tags":["bestpractice","header"],"score":100,"offending":[]},"manyHeaders":{"id":"manyHeaders","title":"Avoid use too many response headers","description":"Avoid send too many response headers.","advice":"","weight":1,"tags":["bestpractice","headers"],"score":100,"offending":[]},"thirdParty":{"id":"thirdParty","title":"Avoid too many third party requests","description":"Do not load most of your content from third party URLs.","advice":"","weight":7,"tags":["bestpractice"],"score":100,"offending":[]},"unnecessaryHeaders":{"id":"unnecessaryHeaders","title":"Avoid unnecessary headers","description":"Do not send headers that you don't need. We look for p3p, cache-control and max-age, pragma, server and x-frame-options headers. Have a look at Andrew Betts - Headers for Hackers talk as a guide https://www.youtube.com/watch?v=k92ZbrY815c or read https://www.fastly.com/blog/headers-we-dont-want.","advice":"There are 11 responses that sets a server header. ","weight":1,"tags":["bestpractice","header"],"score":89,"offending":["https://www.sitespeed.io/","https://www.sitespeed.io/css/prism-1.15.css","https://www.sitespeed.io/js/clipboard-2.0.4.min.js","https://www.sitespeed.io/img/team.png","https://www.sitespeed.io/img/pippi.png","https://www.sitespeed.io/img/dashboard-front.png","https://www.sitespeed.io/img/public.png","https://www.sitespeed.io/js/prism-1.15.js","https://www.sitespeed.io/img/sitespeed-logo-2c.png","https://www.sitespeed.io/img/black-logo-120.png","https://www.sitespeed.io/img/ico/sitespeed.io.ico"]}},"score":100},"info":{"amp":false,"browser":"Chrome 119.0.0.0","connectionType":"h2","documentHeight":4372,"documentTitle":"Welcome to the wonderful world of Web Performance","documentWidth":1366,"domDepth":{"avg":8,"max":13},"domElements":368,"generator":null,"head":{"css":["https://www.sitespeed.io/css/prism-1.15.css"],"jsasync":[],"jssync":[]},"iframes":0,"localStorageSize":0,"metaDescription":"Sitespeed.io is an open source tool that helps you analyse and optimise your website speed and performance, based on performance best practices.","networkConnectionType":"4g","resourceHints":{"dns-prefetch":[],"preconnect":[],"prefetch":[],"prerender":[]},"responsive":true,"scripts":4,"serializedDomSize":16837,"serviceWorker":false,"sessionStorageSize":0,"userTiming":{"marks":2,"measures":1},"windowSize":"1366x623","pageTransferSize":"210.7 kB","pageContentSize":"257.7 kB","pageRequests":11,"pageDomains":1,"pageContentTypes":{"html":{"transferSize":9843,"contentSize":37800,"headerSize":0,"requests":1},"css":{"transferSize":1250,"contentSize":3553,"headerSize":0,"requests":1},"javascript":{"transferSize":9653,"contentSize":27296,"headerSize":0,"requests":2},"image":{"transferSize":183296,"contentSize":182560,"headerSize":0,"requests":6},"font":{"transferSize":0,"contentSize":0,"headerSize":0,"requests":0},"favicon":{"transferSize":6636,"contentSize":6518,"headerSize":0,"requests":1}},"pageExpireStats":{"min":"0 seconds","median":"6 weeks","max":"6 weeks","total":"1 year","values":"11 seconds"},"thirdParty":{"requestsByCategory":{},"requestsByTool":{}},"technology":[{"name":"Netlify","description":"Netlify providers hosting and server-less backend services for web applications and static websites.","slug":"netlify","categories":[{"id":62,"slug":"paas","groups":[7],"name":"PaaS","priority":8},{"id":31,"slug":"cdn","groups":[7],"name":"CDN","priority":9}],"confidence":100,"version":"","icon":"Netlify.svg","website":"https://www.netlify.com/","pricing":[],"cpe":null},{"name":"HSTS","description":"HTTP Strict Transport Security (HSTS) informs browsers that the site should only be accessed using HTTPS.","slug":"hsts","categories":[{"id":16,"slug":"security","groups":[11],"name":"Security","priority":9}],"confidence":100,"version":"","icon":"default.svg","website":"https://www.rfc-editor.org/rfc/rfc6797#section-6.1","pricing":[],"cpe":null}],"thirdparty":{"thirdPartyTransferSizeBytes":0,"totalThirdPartyRequests":0,"toolsByCategory":{},"byCategory":{},"offending":[]}},"performance":{"adviceList":{"avoidRenderBlocking":{"advice":"There are no render blocking resources.","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.","id":"avoidRenderBlocking","offending":[],"score":100,"tags":["performance"],"title":"Avoid slowing down the critical rendering path","weight":10},"avoidScalingImages":{"advice":"The page has 4 images that are scaled more than 100 pixels. It would be better if those images are sent so the browser don't need to scale them.","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.","id":"avoidScalingImages","offending":["https://www.sitespeed.io/img/sitespeed-logo-2c.png","https://www.sitespeed.io/img/pippi.png","https://www.sitespeed.io/img/dashboard-front.png","https://www.sitespeed.io/img/public.png"],"score":60,"tags":["performance","image"],"title":"Don't scale images in the browser","weight":5},"cssPrint":{"advice":"","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.","id":"cssPrint","offending":[],"score":100,"tags":["performance","css"],"title":"Do not load specific print stylesheets.","weight":1},"firstContentfulPaint":{"advice":"","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), elements, or non-white elements.","id":"firstContentfulPaint","offending":[],"score":100,"tags":["performance"],"title":"Have a fast first contentful paint","weight":7},"googleTagManager":{"advice":"","description":"Google Tag Manager makes it possible for non tech users to add scripts to your page that will downgrade performance.","id":"googleTagManager","offending":[],"score":100,"tags":["performance","js"],"title":"Avoid using Google Tag Manager.","weight":5},"inlineCss":{"advice":"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.","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.","id":"inlineCss","offending":[],"score":95,"tags":["performance","css"],"title":"Inline CSS for faster first render","weight":7},"jquery":{"advice":"","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.","id":"jquery","offending":[],"score":100,"tags":["jQuery","performance"],"title":"Avoid using more than one jQuery version per page","weight":4},"largestContentfulPaint":{"advice":" You can add fetchPriority=\"high\" to the image to increase the load priority in Chrome.","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.","id":"largestContentfulPaint","offending":[],"score":95,"tags":["performance"],"title":"Have a fast largest contentful paint","weight":7},"longTasks":{"advice":"The page has 1 CPU long task with the total of 123 ms. The total blocking time is 0 ms and 1 long task before first contentful paint with total time of 123 ms. 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.","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.","id":"longTasks","offending":["unknown"],"score":80,"tags":["performance","js"],"title":"Avoid CPU Long Tasks","weight":8},"spof":{"advice":"","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.","id":"spof","offending":[],"score":100,"tags":["performance","css","js"],"title":"Avoid Frontend single point of failures","weight":7},"assetsRedirects":{"id":"assetsRedirects","title":"Avoid doing redirects","description":"A redirect is one extra step for the user to download the asset. Avoid that if you want to be fast. Redirects are even more of a showstopper on mobile.","advice":"","weight":2,"tags":["performance"],"score":100,"offending":[]},"cacheHeaders":{"id":"cacheHeaders","title":"Avoid extra requests by setting cache headers","description":"The easiest way to make your page fast is to avoid doing requests to the server. Setting a cache header on your server response will tell the browser that it doesn't need to download the asset again during the configured cache time! Always try to set a cache time if the content doesn't change for every request.","advice":"","weight":30,"tags":["performance","server"],"score":100,"offending":[]},"cacheHeadersLong":{"id":"cacheHeadersLong","title":"Long cache headers is good","description":"Setting a cache header is good. Setting a long cache header (at least 30 days) is even better beacause then it will stay long in the browser cache. But what do you do if that asset change? Rename it and the browser will pick up the new version.","advice":"","weight":3,"tags":["performance","server"],"score":100,"offending":[]},"compressAssets":{"id":"compressAssets","title":"Always compress text content","description":"In the early days of the Internet there were browsers that didn't support compressing (gzipping) text content. They do now. Make sure you compress HTML, JSON, JavaScript, CSS and SVG. It will save bytes for the user; making the page load faster and use less bandwith. ","advice":"","weight":8,"tags":["performance","server"],"score":100,"offending":[]},"connectionKeepAlive":{"id":"connectionKeepAlive","title":"Don't close a connection that is used multiple times","description":"Use keep-alive headers and don't close the connection when we have multiple requests to the same domain. There has been some hacks in the past that suggested closing the connection as fast as possible in order to create new ones, but that shouldn't be applicable anymore.","advice":"","weight":5,"tags":["performance","server"],"score":100,"offending":[]},"cpuTimeSpentInRendering":{"id":"cpuTimeSpentInRendering","title":"Avoid spend too much CPU time to render the page","description":"You need to be able to render the page fast. This metric depends on which computer/device you run on but the limit here is high: Spending more time than 500 ms will alert this advice.","advice":"We can only get CPU spent time if you use Chrome to test the page.","weight":7,"tags":["performance","CSS"],"score":100,"offending":[]},"cpuTimeSpentInScripting":{"id":"cpuTimeSpentInScripting","title":"Avoid executing too much JavaScript","description":"Do not run too much JavaSript, that will slow down the page for your user. This metric depends on which computer/device you run on but the limit here is high: Spending more time than 1000 ms will alert this advice","advice":"We can only get CPU spent time if you use Chrome to test the page.","weight":7,"tags":["performance","JavaScript"],"score":100,"offending":[]},"cssSize":{"id":"cssSize","title":"Total CSS size shouldn't be too big","description":"Delivering a massive amount of CSS to the browser is not the best thing you can do, because it means more work for the browser when parsing the CSS against the HTML and that makes the rendering slower. Try to send only the CSS that is used on that page. And make sure to remove CSS rules when they aren't used anymore.","advice":"","weight":5,"tags":["performance","css"],"score":100,"offending":[{"url":"https://www.sitespeed.io/css/prism-1.15.css","transferSize":1250,"contentSize":3553}]},"documentRedirect":{"id":"documentRedirect","title":"Avoid redirecting the main document","description":"You should never ever redirect the main document, because it will make the page load slower for the user. Well, you should redirect the user if the user tries to use HTTP and there's an HTTPS version of the page. The coach checks for that. :)","advice":"","weight":9,"tags":["performance"],"score":100,"offending":[]},"favicon":{"id":"favicon","title":"The favicon should be small and cacheable","description":"It is easy to make the favicon big but please avoid doing that, because every browser will then perform an unnecessarily large download. And make sure the cache headers are set for a long time for the favicon. It is easy to miss since it's another content type.","advice":"","weight":1,"tags":["performance","favicon"],"score":100,"offending":[]},"fewFonts":{"id":"fewFonts","title":"Avoid too many fonts","description":"How many fonts do you need on a page for the user to get the message? Fonts can slow down the rendering of content, try to avoid loading too many of them because worst case it can make the text invisible until they are loaded (FOIT—flash of invisible text), best case they will flicker the text content when they arrive.","advice":"","weight":2,"tags":["performance","font"],"score":100,"offending":[]},"fewRequestsPerDomain":{"id":"fewRequestsPerDomain","title":"Avoid too many requests per domain [HTTP/1]","description":"Browsers have a limit on how many concurrent requests they can do per domain when using HTTP/1. When you hit the limit, the browser will wait before it can download more assets on that domain. So avoid having too many requests per domain.","advice":"There are almost no limits on HTTP/2 connections with the number of requests, but that is not completely true. It depends on how they are downloaded. Please check your HAR file, does it look OK?","weight":5,"tags":["performance","HTTP/1"],"score":100,"offending":[]},"headerSize":{"id":"headerSize","title":"Response headers should't be too big [HTTP/1]","description":"Avoid a lot of cookies and other stuff that makes your headers big when you use HTTP/1 because the headers are not compressed. You will send extra data to the user.","advice":"The page uses an HTTP/2 connection and the headers are sent compressed, that's good. The current coach version cannot say if the size is good or not.","weight":4,"tags":["performance","mobile"],"score":100,"offending":[]},"imageSize":{"id":"imageSize","title":"Total image size shouldn't be too big","description":"Avoid having too many large images on the page. The images will not affect the first paint of the page, but it will eat bandwidth for the user.","advice":"","weight":5,"tags":["performance","image"],"score":100,"offending":[]},"javascriptSize":{"id":"javascriptSize","title":"Total JavaScript size shouldn't be too big","description":"A lot of JavaScript often means you are downloading more than you need. How complex is the page and what can the user do on the page? Do you use multiple JavaScript frameworks?","advice":"","weight":5,"tags":["performance","javascript"],"score":100,"offending":[]},"mimeTypes":{"id":"mimeTypes","title":"Avoid using incorrect mime types","description":"It's not a great idea to let browsers guess content types (content sniffing), in some cases it can actually be a security risk.","advice":"","weight":0,"tags":["performance","bestpractice"],"score":100,"offending":[]},"optimalCssSize":{"id":"optimalCssSize","title":"Make each CSS response small","description":"Make CSS responses small to fit into the magic number TCP window size of 14.5 KB. The browser can then download the CSS faster and that will make the page start rendering earlier.","advice":"","weight":3,"tags":["performance","css"],"score":100,"offending":[]},"pageSize":{"id":"pageSize","title":"Total page size shouldn't be too big","description":"Avoid having pages that have a transfer size over the wire of more than 2 MB (desktop) and 1 MB (mobile) because that is really big and will hurt performance and will make the page expensive for the user if she/he pays for the bandwidth.","advice":"","weight":3,"tags":["performance","mobile"],"score":100,"offending":[]},"privateAssets":{"id":"privateAssets","title":"Don't use private headers on static content","description":"If you set private headers on content, that means that the content are specific for that user. Static content should be able to be cached and used by everyone. Avoid setting the cache header to private.","advice":"","weight":5,"tags":["performance","server"],"score":100,"offending":[]},"responseOk":{"id":"responseOk","title":"Avoid missing and error requests","description":"Your page should never request assets that return a 400 or 500 error. These requests are never cached. If that happens something is broken. Please fix it.","advice":"","weight":7,"tags":["performance","server"],"score":100,"offending":[]}},"score":98},"privacy":{"adviceList":{"facebook":{"advice":"","description":"You share share private user information with Facebook that your user hasn't agreed on sharing.","id":"facebook","offending":[],"score":100,"tags":["privacy"],"title":"Avoid including Facebook","weight":8},"fingerprint":{"advice":"","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","id":"fingerprint","offending":[],"score":100,"tags":["privacy"],"title":"Do not fingerprint your user.","weight":8},"ga":{"advice":"","description":"Google Analytics share private user information with Google that your user hasn't agreed on sharing.","id":"ga","offending":[],"score":100,"tags":["privacy"],"title":"Avoid using Google Analytics","weight":8},"https":{"advice":"","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/.","id":"https","offending":[],"score":100,"tags":["privacy"],"title":"Serve your content securely","weight":10},"surveillance":{"advice":"","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","id":"surveillance","offending":[],"score":100,"tags":["privacy"],"title":"Avoid using surveillance web sites","weight":10},"youtube":{"advice":"","description":"If you include Youtube videos on your page, you are sharing private user information with Google.","id":"youtube","offending":[],"score":100,"tags":["privacy"],"title":"Avoid including Youtube videos","weight":6},"contentSecurityPolicyHeader":{"id":"contentSecurityPolicyHeader","title":"Use a good Content-Security-Policy header to make sure you you avoid Cross Site Scripting (XSS) attacks.","description":"Content Security Policy is delivered via a HTTP response header, and defines approved sources of content that the browser may load. It can be an effective countermeasure to Cross Site Scripting (XSS) attacks and is also widely supported and usually easily deployed. https://scotthelme.co.uk/content-security-policy-an-introduction/.","advice":"","weight":5,"tags":["privacy","bestpractice","headers"],"score":100,"offending":[]},"googleReCaptcha":{"id":"googleReCaptcha","title":"Avoid using Google reCAPTCHA","description":"You should avoid using Google reCAPTCHA since it will share your users information with Google.","advice":"","weight":9,"tags":["privacy"],"score":100,"offending":[]},"mixedContent":{"id":"mixedContent","title":"Serve all responses on HTTPS (when you are on HTTPS)","description":"You need to make sure that if you are on HTTPS, all responses are on HTTPS so that the content served are secured.","advice":"","weight":7,"tags":["privacy"],"score":100,"offending":[]},"referrerPolicyHeader":{"id":"referrerPolicyHeader","title":"Set a referrer-policy header to make sure you do not leak user information.","description":"Referrer Policy is a new header that allows a site to control how much information the browser includes with navigations away from a document and should be set by all sites. https://scotthelme.co.uk/a-new-security-header-referrer-policy/.","advice":"","weight":6,"tags":["headers","privacy"],"score":100,"offending":[]},"strictTransportSecurityHeader":{"id":"strictTransportSecurityHeader","title":"Set a strict transport header to make sure the user always use HTTPS.","description":"The HTTP Strict-Transport-Security response header (often abbreviated as HSTS) lets a web site tell browsers that it should only be accessed using HTTPS, instead of using HTTP. https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security.","advice":"","weight":6,"tags":["headers","privacy"],"score":100,"offending":[]},"thirdPartyCookies":{"id":"thirdPartyCookies","title":"Avoid third party cookies that is used to track the user.","description":"Third party cookies are used to track the user. They are automatically blocked in Safari and Firefox.","advice":"","weight":6,"tags":["cookies","privacy"],"score":100,"offending":[]},"thirdPartyPrivacy":{"id":"thirdPartyPrivacy","title":"Do not share user data with third parties.","description":"Using third party requests shares user information with that third party. Please avoid that! The project https://github.com/patrickhulce/third-party-web is used to categorize first/third party requests.","advice":"The page has 0% requests that are 3rd party (0 requests with a size of 0 B).","weight":5,"tags":["privacy"],"score":100,"offending":[]}},"score":100},"score":99,"timings":{"elementTimings":{"header-logo":{"duration":0,"loadTime":646,"naturalHeight":100,"naturalWidth":324,"renderTime":720,"startTime":720,"tagName":"IMG","url":"https://www.sitespeed.io/img/sitespeed-logo-2c.png"},"logo":{"duration":0,"loadTime":648,"naturalHeight":865,"naturalWidth":1000,"renderTime":720,"startTime":720,"tagName":"IMG","url":"https://www.sitespeed.io/img/team.png"}},"fullyLoaded":843.7999999970198,"largestContentfulPaint":{"duration":0,"id":"","loadTime":648,"renderTime":720,"size":216250,"startTime":720,"tagName":"IMG","url":"https://www.sitespeed.io/img/team.png"},"navigationTimings":{"connectEnd":123,"connectStart":39,"domComplete":664,"domContentLoadedEventEnd":664,"domContentLoadedEventStart":664,"domInteractive":647,"domLoading":350,"domainLookupEnd":39,"domainLookupStart":38,"fetchStart":5,"loadEventEnd":664,"loadEventStart":664,"navigationStart":0,"requestStart":124,"responseEnd":378,"responseStart":345,"secureConnectionStart":76},"paintTimings":{"first-contentful-paint":684,"first-paint":684},"userTimings":{"marks":[{"name":"userTimingHeader","startTime":519},{"name":"userTimingFooter","startTime":520.6999999880791}],"measures":[{"duration":1.699999988079071,"name":"exampleMeasurement","startTime":519}]}}},"errors":{},"url":"https://www.sitespeed.io/","version":"8.0.2","thirdPartyWebVersion":"0.24.0","wappalyzerVersion":"6.10.66"}}}],"visualMetrics":[{"FirstVisualChange":733,"LastVisualChange":900,"SpeedIndex":854,"VisualProgress":[{"timestamp":0,"percent":0},{"timestamp":733,"percent":27},{"timestamp":900,"percent":100}],"videoRecordingStart":900,"VisualReadiness":167,"VisualComplete85":900,"VisualComplete95":900,"VisualComplete99":900},{"FirstVisualChange":533,"LastVisualChange":733,"SpeedIndex":658,"VisualProgress":[{"timestamp":0,"percent":0},{"timestamp":533,"percent":27},{"timestamp":700,"percent":90},{"timestamp":733,"percent":100}],"videoRecordingStart":900,"VisualReadiness":200,"VisualComplete85":700,"VisualComplete95":733,"VisualComplete99":733},{"FirstVisualChange":700,"LastVisualChange":733,"SpeedIndex":708,"VisualProgress":[{"timestamp":0,"percent":0},{"timestamp":700,"percent":75},{"timestamp":733,"percent":100}],"videoRecordingStart":900,"VisualReadiness":33,"VisualComplete85":733,"VisualComplete95":733,"VisualComplete99":733}],"deltaToTTFB":[{"firstContentfulPaint":295,"largestContentfulPaint":476,"firstVisualChange":311,"lastVisualChange":478},{"firstContentfulPaint":201,"largestContentfulPaint":385,"firstVisualChange":204,"lastVisualChange":404},{"firstContentfulPaint":340,"largestContentfulPaint":376,"firstVisualChange":356,"lastVisualChange":389}],"cpu":[{"longTasks":{"tasks":1,"totalDuration":103,"totalBlockingTime":53,"maxPotentialFid":103,"lastLongTask":725,"beforeFirstPaint":{"tasks":0,"totalDuration":0},"beforeFirstContentfulPaint":{"tasks":0,"totalDuration":0},"beforeLargestContentfulPaint":{"tasks":1,"totalDuration":103},"afterLoadEventEnd":{"tasks":0,"totalDuration":0}}},{"longTasks":{"tasks":1,"totalDuration":85,"totalBlockingTime":0,"maxPotentialFid":0,"lastLongTask":527,"beforeFirstPaint":{"tasks":1,"totalDuration":85},"beforeFirstContentfulPaint":{"tasks":1,"totalDuration":85},"beforeLargestContentfulPaint":{"tasks":1,"totalDuration":85},"afterLoadEventEnd":{"tasks":0,"totalDuration":0}}},{"longTasks":{"tasks":1,"totalDuration":123,"totalBlockingTime":0,"maxPotentialFid":0,"lastLongTask":521,"beforeFirstPaint":{"tasks":1,"totalDuration":123},"beforeFirstContentfulPaint":{"tasks":1,"totalDuration":123},"beforeLargestContentfulPaint":{"tasks":1,"totalDuration":123},"afterLoadEventEnd":{"tasks":0,"totalDuration":0}}}],"googleWebVitals":[{"cumulativeLayoutShift":0,"ttfb":422,"largestContentfulPaint":898,"firstContentfulPaint":717,"firstInputDelay":0,"totalBlockingTime":53},{"cumulativeLayoutShift":0,"ttfb":329,"largestContentfulPaint":714,"firstContentfulPaint":530,"firstInputDelay":0,"totalBlockingTime":0},{"cumulativeLayoutShift":0,"ttfb":344,"largestContentfulPaint":720,"firstContentfulPaint":684,"firstInputDelay":0,"totalBlockingTime":0}],"extras":[{},{},{}],"fullyLoaded":[1001,824,839],"mainDocumentTimings":[{"blocked":33.253,"dns":0.012,"connect":219.24,"send":0.44,"wait":161.071,"receive":35.243,"ssl":187.663,"_queued":1.872},{"blocked":30.075,"dns":0.031,"connect":69.426,"send":0.188,"wait":222.729,"receive":31.476,"ssl":37.34,"_queued":1.422},{"blocked":31.165,"dns":0.026,"connect":84.538,"send":0.183,"wait":220.905,"receive":33.14,"ssl":47.289,"_queued":2.565}],"errors":[[],[],[]],"renderBlocking":[],"server":{"processesAtStart":[947,949,951]},"statistics":{"browser":{"cpuBenchmark":{"median":80,"mean":82,"mdev":1.9052,"rsd":4.007892686887314,"stddev":3,"min":80,"p10":80,"p90":87,"p99":87,"max":87}},"pageinfo":{"cumulativeLayoutShift":{"median":0,"mean":0,"mdev":0,"rsd":0,"stddev":0,"min":0,"p10":0,"p90":0,"p99":0,"max":0},"documentHeight":{"median":4372,"mean":4372,"mdev":0,"rsd":0,"stddev":0,"min":4372,"p10":4372,"p90":4372,"p99":4372,"max":4372},"documentSize":{"decodedBodySize":{"median":37800,"mean":37800,"mdev":0,"rsd":0,"stddev":0,"min":37800,"p10":37800,"p90":37800,"p99":37800,"max":37800},"encodedBodySize":{"median":9375,"mean":9377,"mdev":2.4944,"rsd":0.04607543776195557,"stddev":4,"min":9373,"p10":9373,"p90":9383,"p99":9383,"max":9383},"transferSize":{"median":9675,"mean":9677,"mdev":2.4944,"rsd":0.04464703729398134,"stddev":4,"min":9673,"p10":9673,"p90":9683,"p99":9683,"max":9683}},"documentWidth":{"median":1366,"mean":1366,"mdev":0,"rsd":0,"stddev":0,"min":1366,"p10":1366,"p90":1366,"p99":1366,"max":1366},"domElements":{"median":368,"mean":368,"mdev":0,"rsd":0,"stddev":0,"min":368,"p10":368,"p90":368,"p99":368,"max":368},"largestContentfulPaintInfo":[{"duration":{"median":0,"mean":0,"mdev":0,"rsd":0,"stddev":0,"min":0,"p10":0,"p90":0,"p99":0,"max":0},"loadTime":{"median":648,"mean":665,"mdev":26.4211,"rsd":6.87815723516253,"stddev":46,"min":620,"p10":620,"p90":728,"p99":728,"max":728},"renderTime":{"median":720,"mean":777,"mdev":49.2823,"rsd":10.981051161351099,"stddev":85,"min":714,"p10":714,"p90":898,"p99":898,"max":898},"size":{"median":216250,"mean":216250,"mdev":0,"rsd":0,"stddev":0,"min":216250,"p10":216250,"p90":216250,"p99":216250,"max":216250},"startTime":{"median":720,"mean":777,"mdev":49.2823,"rsd":10.981051161351099,"stddev":85,"min":714,"p10":714,"p90":898,"p99":898,"max":898}}],"navigationStartTime":{"median":1700795793319,"mean":1700795792903,"mdev":17836.64,"rsd":0.0000018164418564220277,"stddev":30894,"min":1700795762871,"p10":1700795762871,"p90":1700795822520,"p99":1700795822520,"max":1700795822520},"resources":{"count":{"median":10,"mean":10,"mdev":0,"rsd":0,"stddev":0,"min":10,"p10":10,"p90":10,"p99":10,"max":10},"duration":{"median":2191,"mean":2194,"mdev":43.7831,"rsd":3.456872823205339,"stddev":76,"min":2102,"p10":2102,"p90":2288,"p99":2288,"max":2288},"servedFromCache":{"median":0,"mean":0,"mdev":0,"rsd":0,"stddev":0,"min":0,"p10":0,"p90":0,"p99":0,"max":0}},"visualElements":{"heroes":[{"height":{"median":433,"mean":433,"mdev":0,"rsd":0,"stddev":0,"min":433,"p10":433,"p90":433,"p99":433,"max":433},"width":{"median":500,"mean":500,"mdev":0,"rsd":0,"stddev":0,"min":500,"p10":500,"p90":500,"p99":500,"max":500},"x":{"median":153,"mean":153,"mdev":0,"rsd":0,"stddev":0,"min":153,"p10":153,"p90":153,"p99":153,"max":153},"y":{"median":50,"mean":50,"mdev":0,"rsd":0,"stddev":0,"min":50,"p10":50,"p90":50,"p99":50,"max":50}},{"height":{"median":173,"mean":173,"mdev":0,"rsd":0,"stddev":0,"min":173,"p10":173,"p90":173,"p99":173,"max":173},"width":{"median":510,"mean":510,"mdev":0,"rsd":0,"stddev":0,"min":510,"p10":510,"p90":510,"p99":510,"max":510},"x":{"median":703,"mean":703,"mdev":0,"rsd":0,"stddev":0,"min":703,"p10":703,"p90":703,"p99":703,"max":703},"y":{"median":66,"mean":66,"mdev":0,"rsd":0,"stddev":0,"min":66,"p10":66,"p90":66,"p99":66,"max":66}},{"height":{"median":50,"mean":50,"mdev":0,"rsd":0,"stddev":0,"min":50,"p10":50,"p90":50,"p99":50,"max":50},"width":{"median":162,"mean":162,"mdev":0,"rsd":0,"stddev":0,"min":162,"p10":162,"p90":162,"p99":162,"max":162},"x":{"median":153,"mean":153,"mdev":0,"rsd":0,"stddev":0,"min":153,"p10":153,"p90":153,"p99":153,"max":153},"y":{"median":0,"mean":0,"mdev":0,"rsd":0,"stddev":0,"min":0,"p10":0,"p90":0,"p99":0,"max":0}},{"height":{"median":433,"mean":433,"mdev":0,"rsd":0,"stddev":0,"min":433,"p10":433,"p90":433,"p99":433,"max":433},"width":{"median":500,"mean":500,"mdev":0,"rsd":0,"stddev":0,"min":500,"p10":500,"p90":500,"p99":500,"max":500},"x":{"median":153,"mean":153,"mdev":0,"rsd":0,"stddev":0,"min":153,"p10":153,"p90":153,"p99":153,"max":153},"y":{"median":50,"mean":50,"mdev":0,"rsd":0,"stddev":0,"min":50,"p10":50,"p90":50,"p99":50,"max":50}},{"height":{"median":433,"mean":433,"mdev":0,"rsd":0,"stddev":0,"min":433,"p10":433,"p90":433,"p99":433,"max":433},"width":{"median":500,"mean":500,"mdev":0,"rsd":0,"stddev":0,"min":500,"p10":500,"p90":500,"p99":500,"max":500},"x":{"median":153,"mean":153,"mdev":0,"rsd":0,"stddev":0,"min":153,"p10":153,"p90":153,"p99":153,"max":153},"y":{"median":50,"mean":50,"mdev":0,"rsd":0,"stddev":0,"min":50,"p10":50,"p90":50,"p99":50,"max":50}}],"viewport":{"height":{"median":623,"mean":623,"mdev":0,"rsd":0,"stddev":0,"min":623,"p10":623,"p90":623,"p99":623,"max":623},"width":{"median":1366,"mean":1366,"mdev":0,"rsd":0,"stddev":0,"min":1366,"p10":1366,"p90":1366,"p99":1366,"max":1366}}},"longTask":[{"duration":{"median":103,"mean":104,"mdev":8.9608,"rsd":14.971635661508444,"stddev":16,"min":85,"p10":85,"p90":123,"p99":123,"max":123},"startTime":{"median":527,"mean":591,"mdev":54.7662,"rsd":16.05040502806413,"stddev":95,"min":521,"p10":521,"p90":725,"p99":725,"max":725}}]},"timings":{"elementTimings":{"header-logo":{"duration":{"median":0,"mean":0,"mdev":0,"rsd":0,"stddev":0,"min":0,"p10":0,"p90":0,"p99":0,"max":0},"loadTime":{"median":646,"mean":642,"mdev":11.2184,"rsd":3.0281748866056466,"stddev":19,"min":616,"p10":616,"p90":663,"p99":663,"max":663},"naturalHeight":{"median":100,"mean":100,"mdev":0,"rsd":0,"stddev":0,"min":100,"p10":100,"p90":100,"p99":100,"max":100},"naturalWidth":{"median":324,"mean":324,"mdev":0,"rsd":0,"stddev":0,"min":324,"p10":324,"p90":324,"p99":324,"max":324},"renderTime":{"median":717,"mean":717,"mdev":1.4142,"rsd":0.3416303685890067,"stddev":2,"min":714,"p10":714,"p90":720,"p99":720,"max":720},"startTime":{"median":717,"mean":717,"mdev":1.4142,"rsd":0.3416303685890067,"stddev":2,"min":714,"p10":714,"p90":720,"p99":720,"max":720}},"logo":{"duration":{"median":0,"mean":0,"mdev":0,"rsd":0,"stddev":0,"min":0,"p10":0,"p90":0,"p99":0,"max":0},"loadTime":{"median":648,"mean":665,"mdev":26.4211,"rsd":6.87815723516253,"stddev":46,"min":620,"p10":620,"p90":728,"p99":728,"max":728},"naturalHeight":{"median":865,"mean":865,"mdev":0,"rsd":0,"stddev":0,"min":865,"p10":865,"p90":865,"p99":865,"max":865},"naturalWidth":{"median":1000,"mean":1000,"mdev":0,"rsd":0,"stddev":0,"min":1000,"p10":1000,"p90":1000,"p99":1000,"max":1000},"renderTime":{"median":717,"mean":717,"mdev":1.4142,"rsd":0.3416303685890067,"stddev":2,"min":714,"p10":714,"p90":720,"p99":720,"max":720},"startTime":{"median":717,"mean":717,"mdev":1.4142,"rsd":0.3416303685890067,"stddev":2,"min":714,"p10":714,"p90":720,"p99":720,"max":720}}},"firstPaint":{"median":684,"mean":644,"mdev":47.0516,"rsd":12.661171335050316,"stddev":81,"min":530,"p10":530,"p90":717,"p99":717,"max":717},"largestContentfulPaint":{"duration":{"median":0,"mean":0,"mdev":0,"rsd":0,"stddev":0,"min":0,"p10":0,"p90":0,"p99":0,"max":0},"loadTime":{"median":648,"mean":665,"mdev":26.4211,"rsd":6.87815723516253,"stddev":46,"min":620,"p10":620,"p90":728,"p99":728,"max":728},"renderTime":{"median":720,"mean":777,"mdev":49.2823,"rsd":10.981051161351099,"stddev":85,"min":714,"p10":714,"p90":898,"p99":898,"max":898},"size":{"median":216250,"mean":216250,"mdev":0,"rsd":0,"stddev":0,"min":216250,"p10":216250,"p90":216250,"p99":216250,"max":216250},"startTime":{"median":720,"mean":777,"mdev":49.2823,"rsd":10.981051161351099,"stddev":85,"min":714,"p10":714,"p90":898,"p99":898,"max":898}},"loadEventEnd":{"median":664,"mean":715,"mdev":49.3296,"rsd":11.955411086819442,"stddev":85,"min":645,"p10":645,"p90":835,"p99":835,"max":835},"navigationTiming":{"connectStart":{"median":38,"mean":39,"mdev":0.9813,"rsd":4.3957064772351595,"stddev":2,"min":37,"p10":37,"p90":41,"p99":41,"max":41},"domComplete":{"median":664,"mean":714,"mdev":49.0585,"rsd":11.895271690670423,"stddev":85,"min":645,"p10":645,"p90":834,"p99":834,"max":834},"domContentLoadedEventEnd":{"median":664,"mean":714,"mdev":49.2161,"rsd":11.939040011712812,"stddev":85,"min":644,"p10":644,"p90":834,"p99":834,"max":834},"domContentLoadedEventStart":{"median":664,"mean":714,"mdev":49.2161,"rsd":11.939040011712812,"stddev":85,"min":644,"p10":644,"p90":834,"p99":834,"max":834},"domInteractive":{"median":647,"mean":697,"mdev":53.8111,"rsd":13.365699966332123,"stddev":93,"min":617,"p10":617,"p90":828,"p99":828,"max":828},"domainLookupEnd":{"median":38,"mean":39,"mdev":0.9813,"rsd":4.3957064772351595,"stddev":2,"min":37,"p10":37,"p90":41,"p99":41,"max":41},"domainLookupStart":{"median":38,"mean":39,"mdev":0.9813,"rsd":4.3957064772351595,"stddev":2,"min":37,"p10":37,"p90":41,"p99":41,"max":41},"duration":{"median":664,"mean":715,"mdev":49.3296,"rsd":11.955411086819442,"stddev":85,"min":645,"p10":645,"p90":835,"p99":835,"max":835},"fetchStart":{"median":5,"mean":5,"mdev":0.4714,"rsd":16.329931618554518,"stddev":1,"min":4,"p10":4,"p90":6,"p99":6,"max":6},"loadEventEnd":{"median":664,"mean":715,"mdev":49.3296,"rsd":11.955411086819442,"stddev":85,"min":645,"p10":645,"p90":835,"p99":835,"max":835},"loadEventStart":{"median":664,"mean":715,"mdev":49.3296,"rsd":11.955411086819442,"stddev":85,"min":645,"p10":645,"p90":835,"p99":835,"max":835},"redirectEnd":{"median":0,"mean":0,"mdev":0,"rsd":0,"stddev":0,"min":0,"p10":0,"p90":0,"p99":0,"max":0},"redirectStart":{"median":0,"mean":0,"mdev":0,"rsd":0,"stddev":0,"min":0,"p10":0,"p90":0,"p99":0,"max":0},"requestStart":{"median":124,"mean":164,"mdev":39.8023,"rsd":42.036333584949105,"stddev":69,"min":107,"p10":107,"p90":261,"p99":261,"max":261},"responseEnd":{"median":378,"mean":399,"mdev":24.4177,"rsd":10.599656980422958,"stddev":42,"min":361,"p10":361,"p90":458,"p99":458,"max":458},"responseStart":{"median":344,"mean":365,"mdev":23.5372,"rsd":11.169214855144936,"stddev":41,"min":329,"p10":329,"p90":422,"p99":422,"max":422},"secureConnectionStart":{"median":72,"mean":72,"mdev":1.4142,"rsd":3.4020690871988584,"stddev":2,"min":69,"p10":69,"p90":75,"p99":75,"max":75},"startTime":{"median":0,"mean":0,"mdev":0,"rsd":0,"stddev":0,"min":0,"p10":0,"p90":0,"p99":0,"max":0},"unloadEventEnd":{"median":0,"mean":0,"mdev":0,"rsd":0,"stddev":0,"min":0,"p10":0,"p90":0,"p99":0,"max":0},"unloadEventStart":{"median":0,"mean":0,"mdev":0,"rsd":0,"stddev":0,"min":0,"p10":0,"p90":0,"p99":0,"max":0},"workerStart":{"median":0,"mean":0,"mdev":0,"rsd":0,"stddev":0,"min":0,"p10":0,"p90":0,"p99":0,"max":0}},"pageTimings":{"backEndTime":{"median":344,"mean":365,"mdev":23.5372,"rsd":11.169214855144936,"stddev":41,"min":329,"p10":329,"p90":422,"p99":422,"max":422},"domContentLoadedTime":{"median":664,"mean":714,"mdev":49.2161,"rsd":11.939040011712812,"stddev":85,"min":644,"p10":644,"p90":834,"p99":834,"max":834},"domInteractiveTime":{"median":647,"mean":697,"mdev":53.8111,"rsd":13.365699966332123,"stddev":93,"min":617,"p10":617,"p90":828,"p99":828,"max":828},"domainLookupTime":{"median":0,"mean":0,"mdev":0,"rsd":0,"stddev":0,"min":0,"p10":0,"p90":0,"p99":0,"max":0},"frontEndTime":{"median":286,"mean":315,"mdev":24.7715,"rsd":13.60642106528887,"stddev":43,"min":284,"p10":284,"p90":376,"p99":376,"max":376},"pageDownloadTime":{"median":34,"mean":34,"mdev":1.1863,"rsd":5.984867964047551,"stddev":2,"min":32,"p10":32,"p90":37,"p99":37,"max":37},"pageLoadTime":{"median":664,"mean":715,"mdev":49.3296,"rsd":11.955411086819442,"stddev":85,"min":645,"p10":645,"p90":835,"p99":835,"max":835},"redirectionTime":{"median":0,"mean":0,"mdev":0,"rsd":0,"stddev":0,"min":0,"p10":0,"p90":0,"p99":0,"max":0},"serverConnectionTime":{"median":85,"mean":125,"mdev":38.6734,"rsd":53.73067667386262,"stddev":67,"min":70,"p10":70,"p90":219,"p99":219,"max":219},"serverResponseTime":{"median":254,"mean":235,"mdev":15.5134,"rsd":11.434067100037788,"stddev":27,"min":197,"p10":197,"p90":254,"p99":254,"max":254}},"paintTiming":{"first-contentful-paint":{"median":684,"mean":644,"mdev":47.0516,"rsd":12.661171335050316,"stddev":81,"min":530,"p10":530,"p90":717,"p99":717,"max":717},"first-paint":{"median":684,"mean":644,"mdev":47.0516,"rsd":12.661171335050316,"stddev":81,"min":530,"p10":530,"p90":717,"p99":717,"max":717}},"ttfb":{"median":344,"mean":365,"mdev":23.5372,"rsd":11.169214855144936,"stddev":41,"min":329,"p10":329,"p90":422,"p99":422,"max":422},"userTimings":{"marks":{"userTimingHeader":{"median":519,"mean":577,"mdev":59.3893,"rsd":17.828637391784035,"stddev":103,"min":490,"p10":490,"p90":722,"p99":722,"max":722},"userTimingFooter":{"median":526,"mean":590,"mdev":54.7212,"rsd":16.050784987782126,"stddev":95,"min":521,"p10":521,"p90":725,"p99":725,"max":725}},"measures":{"exampleMeasurement":{"median":3,"mean":14,"mdev":9.1363,"rsd":116.9299793537966,"stddev":16,"min":2,"p10":2,"p90":36,"p99":36,"max":36}}},"fullyLoaded":{"median":839,"mean":888,"mdev":46.2673,"rsd":9.02447995930143,"stddev":80,"min":824,"p10":824,"p90":1001,"p99":1001,"max":1001},"mainDocumentTimings":{"blocked":{"median":31,"mean":31,"mdev":0.7613,"rsd":4.186231403877241,"stddev":1,"min":30,"p10":30,"p90":33,"p99":33,"max":33},"dns":{"median":0.026,"mean":0.023,"mdev":0.0046,"rsd":34.96329878786908,"stddev":0.008,"min":0.012,"p10":0.012,"p90":0.031,"p99":0.031,"max":0.031},"connect":{"median":85,"mean":124,"mdev":38.8812,"rsd":54.13467154189463,"stddev":67,"min":69,"p10":69,"p90":219,"p99":219,"max":219},"send":{"median":0.188,"mean":0.2703,"mdev":0.0693,"rsd":44.385874617461106,"stddev":0.12,"min":0.183,"p10":0.183,"p90":0.44,"p99":0.44,"max":0.44},"wait":{"median":221,"mean":202,"mdev":16.5386,"rsd":14.21136878489337,"stddev":29,"min":161,"p10":161,"p90":223,"p99":223,"max":223},"receive":{"median":33,"mean":33,"mdev":0.8899,"rsd":4.6305743085163265,"stddev":2,"min":31,"p10":31,"p90":35,"p99":35,"max":35},"ssl":{"median":47,"mean":91,"mdev":39.6283,"rsd":75.62273553252145,"stddev":69,"min":37,"p10":37,"p90":188,"p99":188,"max":188},"_queued":{"median":2,"mean":2,"mdev":0.2714,"rsd":24.072184808964057,"stddev":0,"min":1,"p10":1,"p90":3,"p99":3,"max":3}}},"coach":{"coachAdvice":{"advice":{"bestpractice":{"adviceList":{"amp":{"score":{"median":100,"mean":100,"mdev":0,"rsd":0,"stddev":0,"min":100,"p10":100,"p90":100,"p99":100,"max":100},"weight":{"median":10,"mean":10,"mdev":0,"rsd":0,"stddev":0,"min":10,"p10":10,"p90":10,"p99":10,"max":10}},"charset":{"score":{"median":100,"mean":100,"mdev":0,"rsd":0,"stddev":0,"min":100,"p10":100,"p90":100,"p99":100,"max":100},"weight":{"median":2,"mean":2,"mdev":0,"rsd":0,"stddev":0,"min":2,"p10":2,"p90":2,"p99":2,"max":2}},"cumulativeLayoutShift":{"score":{"median":100,"mean":100,"mdev":0,"rsd":0,"stddev":0,"min":100,"p10":100,"p90":100,"p99":100,"max":100},"weight":{"median":8,"mean":8,"mdev":0,"rsd":0,"stddev":0,"min":8,"p10":8,"p90":8,"p99":8,"max":8}},"doctype":{"score":{"median":100,"mean":100,"mdev":0,"rsd":0,"stddev":0,"min":100,"p10":100,"p90":100,"p99":100,"max":100},"weight":{"median":2,"mean":2,"mdev":0,"rsd":0,"stddev":0,"min":2,"p10":2,"p90":2,"p99":2,"max":2}},"language":{"score":{"median":100,"mean":100,"mdev":0,"rsd":0,"stddev":0,"min":100,"p10":100,"p90":100,"p99":100,"max":100},"weight":{"median":3,"mean":3,"mdev":0,"rsd":0,"stddev":0,"min":3,"p10":3,"p90":3,"p99":3,"max":3}},"metaDescription":{"score":{"median":100,"mean":100,"mdev":0,"rsd":0,"stddev":0,"min":100,"p10":100,"p90":100,"p99":100,"max":100},"weight":{"median":5,"mean":5,"mdev":0,"rsd":0,"stddev":0,"min":5,"p10":5,"p90":5,"p99":5,"max":5}},"optimizely":{"score":{"median":100,"mean":100,"mdev":0,"rsd":0,"stddev":0,"min":100,"p10":100,"p90":100,"p99":100,"max":100},"weight":{"median":2,"mean":2,"mdev":0,"rsd":0,"stddev":0,"min":2,"p10":2,"p90":2,"p99":2,"max":2}},"pageTitle":{"score":{"median":100,"mean":100,"mdev":0,"rsd":0,"stddev":0,"min":100,"p10":100,"p90":100,"p99":100,"max":100},"weight":{"median":5,"mean":5,"mdev":0,"rsd":0,"stddev":0,"min":5,"p10":5,"p90":5,"p99":5,"max":5}},"spdy":{"score":{"median":100,"mean":100,"mdev":0,"rsd":0,"stddev":0,"min":100,"p10":100,"p90":100,"p99":100,"max":100},"weight":{"median":1,"mean":1,"mdev":0,"rsd":0,"stddev":0,"min":1,"p10":1,"p90":1,"p99":1,"max":1}},"url":{"score":{"median":100,"mean":100,"mdev":0,"rsd":0,"stddev":0,"min":100,"p10":100,"p90":100,"p99":100,"max":100},"weight":{"median":2,"mean":2,"mdev":0,"rsd":0,"stddev":0,"min":2,"p10":2,"p90":2,"p99":2,"max":2}}},"score":{"median":100,"mean":100,"mdev":0,"rsd":0,"stddev":0,"min":100,"p10":100,"p90":100,"p99":100,"max":100}},"info":{"documentHeight":{"median":4372,"mean":4372,"mdev":0,"rsd":0,"stddev":0,"min":4372,"p10":4372,"p90":4372,"p99":4372,"max":4372},"documentWidth":{"median":1366,"mean":1366,"mdev":0,"rsd":0,"stddev":0,"min":1366,"p10":1366,"p90":1366,"p99":1366,"max":1366},"domDepth":{"avg":{"median":8,"mean":8,"mdev":0,"rsd":0,"stddev":0,"min":8,"p10":8,"p90":8,"p99":8,"max":8},"max":{"median":13,"mean":13,"mdev":0,"rsd":0,"stddev":0,"min":13,"p10":13,"p90":13,"p99":13,"max":13}},"domElements":{"median":368,"mean":368,"mdev":0,"rsd":0,"stddev":0,"min":368,"p10":368,"p90":368,"p99":368,"max":368},"iframes":{"median":0,"mean":0,"mdev":0,"rsd":0,"stddev":0,"min":0,"p10":0,"p90":0,"p99":0,"max":0},"localStorageSize":{"median":0,"mean":0,"mdev":0,"rsd":0,"stddev":0,"min":0,"p10":0,"p90":0,"p99":0,"max":0},"scripts":{"median":4,"mean":4,"mdev":0,"rsd":0,"stddev":0,"min":4,"p10":4,"p90":4,"p99":4,"max":4},"serializedDomSize":{"median":16837,"mean":16837,"mdev":0,"rsd":0,"stddev":0,"min":16837,"p10":16837,"p90":16837,"p99":16837,"max":16837},"sessionStorageSize":{"median":0,"mean":0,"mdev":0,"rsd":0,"stddev":0,"min":0,"p10":0,"p90":0,"p99":0,"max":0},"userTiming":{"marks":{"median":2,"mean":2,"mdev":0,"rsd":0,"stddev":0,"min":2,"p10":2,"p90":2,"p99":2,"max":2},"measures":{"median":1,"mean":1,"mdev":0,"rsd":0,"stddev":0,"min":1,"p10":1,"p90":1,"p99":1,"max":1}}},"performance":{"adviceList":{"avoidRenderBlocking":{"score":{"median":100,"mean":100,"mdev":0,"rsd":0,"stddev":0,"min":100,"p10":100,"p90":100,"p99":100,"max":100},"weight":{"median":10,"mean":10,"mdev":0,"rsd":0,"stddev":0,"min":10,"p10":10,"p90":10,"p99":10,"max":10}},"avoidScalingImages":{"score":{"median":60,"mean":60,"mdev":0,"rsd":0,"stddev":0,"min":60,"p10":60,"p90":60,"p99":60,"max":60},"weight":{"median":5,"mean":5,"mdev":0,"rsd":0,"stddev":0,"min":5,"p10":5,"p90":5,"p99":5,"max":5}},"cssPrint":{"score":{"median":100,"mean":100,"mdev":0,"rsd":0,"stddev":0,"min":100,"p10":100,"p90":100,"p99":100,"max":100},"weight":{"median":1,"mean":1,"mdev":0,"rsd":0,"stddev":0,"min":1,"p10":1,"p90":1,"p99":1,"max":1}},"firstContentfulPaint":{"score":{"median":100,"mean":100,"mdev":0,"rsd":0,"stddev":0,"min":100,"p10":100,"p90":100,"p99":100,"max":100},"weight":{"median":7,"mean":7,"mdev":0,"rsd":0,"stddev":0,"min":7,"p10":7,"p90":7,"p99":7,"max":7}},"googleTagManager":{"score":{"median":100,"mean":100,"mdev":0,"rsd":0,"stddev":0,"min":100,"p10":100,"p90":100,"p99":100,"max":100},"weight":{"median":5,"mean":5,"mdev":0,"rsd":0,"stddev":0,"min":5,"p10":5,"p90":5,"p99":5,"max":5}},"inlineCss":{"score":{"median":95,"mean":95,"mdev":0,"rsd":0,"stddev":0,"min":95,"p10":95,"p90":95,"p99":95,"max":95},"weight":{"median":7,"mean":7,"mdev":0,"rsd":0,"stddev":0,"min":7,"p10":7,"p90":7,"p99":7,"max":7}},"jquery":{"score":{"median":100,"mean":100,"mdev":0,"rsd":0,"stddev":0,"min":100,"p10":100,"p90":100,"p99":100,"max":100},"weight":{"median":4,"mean":4,"mdev":0,"rsd":0,"stddev":0,"min":4,"p10":4,"p90":4,"p99":4,"max":4}},"largestContentfulPaint":{"score":{"median":95,"mean":95,"mdev":0,"rsd":0,"stddev":0,"min":95,"p10":95,"p90":95,"p99":95,"max":95},"weight":{"median":7,"mean":7,"mdev":0,"rsd":0,"stddev":0,"min":7,"p10":7,"p90":7,"p99":7,"max":7}},"longTasks":{"score":{"median":80,"mean":80,"mdev":0,"rsd":0,"stddev":0,"min":80,"p10":80,"p90":80,"p99":80,"max":80},"weight":{"median":8,"mean":8,"mdev":0,"rsd":0,"stddev":0,"min":8,"p10":8,"p90":8,"p99":8,"max":8}},"spof":{"score":{"median":100,"mean":100,"mdev":0,"rsd":0,"stddev":0,"min":100,"p10":100,"p90":100,"p99":100,"max":100},"weight":{"median":7,"mean":7,"mdev":0,"rsd":0,"stddev":0,"min":7,"p10":7,"p90":7,"p99":7,"max":7}}},"score":{"median":93,"mean":93,"mdev":0,"rsd":0,"stddev":0,"min":93,"p10":93,"p90":93,"p99":93,"max":93}},"privacy":{"adviceList":{"facebook":{"score":{"median":100,"mean":100,"mdev":0,"rsd":0,"stddev":0,"min":100,"p10":100,"p90":100,"p99":100,"max":100},"weight":{"median":8,"mean":8,"mdev":0,"rsd":0,"stddev":0,"min":8,"p10":8,"p90":8,"p99":8,"max":8}},"fingerprint":{"score":{"median":100,"mean":100,"mdev":0,"rsd":0,"stddev":0,"min":100,"p10":100,"p90":100,"p99":100,"max":100},"weight":{"median":8,"mean":8,"mdev":0,"rsd":0,"stddev":0,"min":8,"p10":8,"p90":8,"p99":8,"max":8}},"ga":{"score":{"median":100,"mean":100,"mdev":0,"rsd":0,"stddev":0,"min":100,"p10":100,"p90":100,"p99":100,"max":100},"weight":{"median":8,"mean":8,"mdev":0,"rsd":0,"stddev":0,"min":8,"p10":8,"p90":8,"p99":8,"max":8}},"https":{"score":{"median":100,"mean":100,"mdev":0,"rsd":0,"stddev":0,"min":100,"p10":100,"p90":100,"p99":100,"max":100},"weight":{"median":10,"mean":10,"mdev":0,"rsd":0,"stddev":0,"min":10,"p10":10,"p90":10,"p99":10,"max":10}},"surveillance":{"score":{"median":100,"mean":100,"mdev":0,"rsd":0,"stddev":0,"min":100,"p10":100,"p90":100,"p99":100,"max":100},"weight":{"median":10,"mean":10,"mdev":0,"rsd":0,"stddev":0,"min":10,"p10":10,"p90":10,"p99":10,"max":10}},"youtube":{"score":{"median":100,"mean":100,"mdev":0,"rsd":0,"stddev":0,"min":100,"p10":100,"p90":100,"p99":100,"max":100},"weight":{"median":6,"mean":6,"mdev":0,"rsd":0,"stddev":0,"min":6,"p10":6,"p90":6,"p99":6,"max":6}}},"score":{"median":100,"mean":100,"mdev":0,"rsd":0,"stddev":0,"min":100,"p10":100,"p90":100,"p99":100,"max":100}},"score":{"median":97,"mean":97,"mdev":0,"rsd":0,"stddev":0,"min":97,"p10":97,"p90":97,"p99":97,"max":97},"timings":{"elementTimings":{"header-logo":{"duration":{"median":0,"mean":0,"mdev":0,"rsd":0,"stddev":0,"min":0,"p10":0,"p90":0,"p99":0,"max":0},"loadTime":{"median":646,"mean":642,"mdev":11.2184,"rsd":3.0281748866056466,"stddev":19,"min":616,"p10":616,"p90":663,"p99":663,"max":663},"naturalHeight":{"median":100,"mean":100,"mdev":0,"rsd":0,"stddev":0,"min":100,"p10":100,"p90":100,"p99":100,"max":100},"naturalWidth":{"median":324,"mean":324,"mdev":0,"rsd":0,"stddev":0,"min":324,"p10":324,"p90":324,"p99":324,"max":324},"renderTime":{"median":717,"mean":717,"mdev":1.4142,"rsd":0.3416303685890067,"stddev":2,"min":714,"p10":714,"p90":720,"p99":720,"max":720},"startTime":{"median":717,"mean":717,"mdev":1.4142,"rsd":0.3416303685890067,"stddev":2,"min":714,"p10":714,"p90":720,"p99":720,"max":720}},"logo":{"duration":{"median":0,"mean":0,"mdev":0,"rsd":0,"stddev":0,"min":0,"p10":0,"p90":0,"p99":0,"max":0},"loadTime":{"median":648,"mean":665,"mdev":26.4211,"rsd":6.87815723516253,"stddev":46,"min":620,"p10":620,"p90":728,"p99":728,"max":728},"naturalHeight":{"median":865,"mean":865,"mdev":0,"rsd":0,"stddev":0,"min":865,"p10":865,"p90":865,"p99":865,"max":865},"naturalWidth":{"median":1000,"mean":1000,"mdev":0,"rsd":0,"stddev":0,"min":1000,"p10":1000,"p90":1000,"p99":1000,"max":1000},"renderTime":{"median":717,"mean":717,"mdev":1.4142,"rsd":0.3416303685890067,"stddev":2,"min":714,"p10":714,"p90":720,"p99":720,"max":720},"startTime":{"median":717,"mean":717,"mdev":1.4142,"rsd":0.3416303685890067,"stddev":2,"min":714,"p10":714,"p90":720,"p99":720,"max":720}}},"fullyLoaded":{"median":844,"mean":893,"mdev":46.5894,"rsd":9.03338972485402,"stddev":81,"min":829,"p10":829,"p90":1007,"p99":1007,"max":1007},"largestContentfulPaint":{"duration":{"median":0,"mean":0,"mdev":0,"rsd":0,"stddev":0,"min":0,"p10":0,"p90":0,"p99":0,"max":0},"loadTime":{"median":648,"mean":665,"mdev":26.4211,"rsd":6.87815723516253,"stddev":46,"min":620,"p10":620,"p90":728,"p99":728,"max":728},"renderTime":{"median":720,"mean":777,"mdev":49.2823,"rsd":10.981051161351099,"stddev":85,"min":714,"p10":714,"p90":898,"p99":898,"max":898},"size":{"median":216250,"mean":216250,"mdev":0,"rsd":0,"stddev":0,"min":216250,"p10":216250,"p90":216250,"p99":216250,"max":216250},"startTime":{"median":720,"mean":777,"mdev":49.2823,"rsd":10.981051161351099,"stddev":85,"min":714,"p10":714,"p90":898,"p99":898,"max":898}},"navigationTimings":{"connectEnd":{"median":123,"mean":163,"mdev":39.8023,"rsd":42.29422520203468,"stddev":69,"min":106,"p10":106,"p90":260,"p99":260,"max":260},"connectStart":{"median":39,"mean":39,"mdev":0.9428,"rsd":4.187161953475518,"stddev":2,"min":37,"p10":37,"p90":41,"p99":41,"max":41},"domComplete":{"median":664,"mean":714,"mdev":49.487,"rsd":11.999159315235751,"stddev":86,"min":644,"p10":644,"p90":835,"p99":835,"max":835},"domContentLoadedEventEnd":{"median":664,"mean":714,"mdev":49.2161,"rsd":11.939040011712812,"stddev":85,"min":644,"p10":644,"p90":834,"p99":834,"max":834},"domContentLoadedEventStart":{"median":664,"mean":714,"mdev":49.2161,"rsd":11.939040011712812,"stddev":85,"min":644,"p10":644,"p90":834,"p99":834,"max":834},"domInteractive":{"median":647,"mean":697,"mdev":54.247,"rsd":13.473989445528888,"stddev":94,"min":616,"p10":616,"p90":829,"p99":829,"max":829},"domLoading":{"median":350,"mean":372,"mdev":24.5145,"rsd":11.424333391161323,"stddev":42,"min":334,"p10":334,"p90":431,"p99":431,"max":431},"domainLookupEnd":{"median":39,"mean":39,"mdev":0.9428,"rsd":4.187161953475518,"stddev":2,"min":37,"p10":37,"p90":41,"p99":41,"max":41},"domainLookupStart":{"median":38,"mean":39,"mdev":0.9813,"rsd":4.3957064772351595,"stddev":2,"min":37,"p10":37,"p90":41,"p99":41,"max":41},"fetchStart":{"median":5,"mean":5,"mdev":0.2722,"rsd":8.838834764831844,"stddev":0,"min":5,"p10":5,"p90":6,"p99":6,"max":6},"loadEventEnd":{"median":664,"mean":714,"mdev":49.487,"rsd":11.999159315235751,"stddev":86,"min":644,"p10":644,"p90":835,"p99":835,"max":835},"loadEventStart":{"median":664,"mean":714,"mdev":49.487,"rsd":11.999159315235751,"stddev":86,"min":644,"p10":644,"p90":835,"p99":835,"max":835},"navigationStart":{"median":0,"mean":0,"mdev":0,"rsd":0,"stddev":0,"min":0,"p10":0,"p90":0,"p99":0,"max":0},"requestStart":{"median":124,"mean":164,"mdev":40.2327,"rsd":42.49085704923011,"stddev":70,"min":106,"p10":106,"p90":262,"p99":262,"max":262},"responseEnd":{"median":378,"mean":399,"mdev":24.4177,"rsd":10.599656980422958,"stddev":42,"min":361,"p10":361,"p90":458,"p99":458,"max":458},"responseStart":{"median":345,"mean":365,"mdev":23.4394,"rsd":11.11267423190151,"stddev":41,"min":329,"p10":329,"p90":422,"p99":422,"max":422},"secureConnectionStart":{"median":72,"mean":72,"mdev":1.6555,"rsd":3.9642051921855423,"stddev":3,"min":69,"p10":69,"p90":76,"p99":76,"max":76}},"paintTimings":{"first-contentful-paint":{"median":684,"mean":644,"mdev":47.0516,"rsd":12.661171335050316,"stddev":81,"min":530,"p10":530,"p90":717,"p99":717,"max":717},"first-paint":{"median":684,"mean":644,"mdev":47.0516,"rsd":12.661171335050316,"stddev":81,"min":530,"p10":530,"p90":717,"p99":717,"max":717}},"userTimings":{"marks":{"userTimingHeader":{"median":519,"mean":577,"mdev":59.3893,"rsd":17.828637391784035,"stddev":103,"min":490,"p10":490,"p90":722,"p99":722,"max":722},"userTimingFooter":{"median":526,"mean":590,"mdev":54.7212,"rsd":16.050784987782126,"stddev":95,"min":521,"p10":521,"p90":725,"p99":725,"max":725}},"measures":{"exampleMeasurement":{"median":3,"mean":14,"mdev":9.1363,"rsd":116.9299793537966,"stddev":16,"min":2,"p10":2,"p90":36,"p99":36,"max":36}}}}}}},"cdp":{"performance":{"AudioHandlers":{"median":0,"mean":0,"mdev":0,"rsd":0,"stddev":0,"min":0,"p10":0,"p90":0,"p99":0,"max":0},"AudioWorkletProcessors":{"median":0,"mean":0,"mdev":0,"rsd":0,"stddev":0,"min":0,"p10":0,"p90":0,"p99":0,"max":0},"Documents":{"median":4,"mean":4,"mdev":0,"rsd":0,"stddev":0,"min":4,"p10":4,"p90":4,"p99":4,"max":4},"Frames":{"median":1,"mean":1,"mdev":0,"rsd":0,"stddev":0,"min":1,"p10":1,"p90":1,"p99":1,"max":1},"JSEventListeners":{"median":4,"mean":4,"mdev":0,"rsd":0,"stddev":0,"min":4,"p10":4,"p90":4,"p99":4,"max":4},"LayoutObjects":{"median":645,"mean":645,"mdev":0,"rsd":0,"stddev":0,"min":645,"p10":645,"p90":645,"p99":645,"max":645},"MediaKeySessions":{"median":0,"mean":0,"mdev":0,"rsd":0,"stddev":0,"min":0,"p10":0,"p90":0,"p99":0,"max":0},"MediaKeys":{"median":0,"mean":0,"mdev":0,"rsd":0,"stddev":0,"min":0,"p10":0,"p90":0,"p99":0,"max":0},"Nodes":{"median":702,"mean":702,"mdev":0,"rsd":0,"stddev":0,"min":702,"p10":702,"p90":702,"p99":702,"max":702},"Resources":{"median":10,"mean":10,"mdev":0,"rsd":0,"stddev":0,"min":10,"p10":10,"p90":10,"p99":10,"max":10},"ContextLifecycleStateObservers":{"median":5,"mean":5,"mdev":0,"rsd":0,"stddev":0,"min":5,"p10":5,"p90":5,"p99":5,"max":5},"V8PerContextDatas":{"median":3,"mean":3,"mdev":0,"rsd":0,"stddev":0,"min":3,"p10":3,"p90":3,"p99":3,"max":3},"WorkerGlobalScopes":{"median":0,"mean":0,"mdev":0,"rsd":0,"stddev":0,"min":0,"p10":0,"p90":0,"p99":0,"max":0},"UACSSResources":{"median":0,"mean":0,"mdev":0,"rsd":0,"stddev":0,"min":0,"p10":0,"p90":0,"p99":0,"max":0},"RTCPeerConnections":{"median":0,"mean":0,"mdev":0,"rsd":0,"stddev":0,"min":0,"p10":0,"p90":0,"p99":0,"max":0},"ResourceFetchers":{"median":4,"mean":4,"mdev":0,"rsd":0,"stddev":0,"min":4,"p10":4,"p90":4,"p99":4,"max":4},"AdSubframes":{"median":0,"mean":0,"mdev":0,"rsd":0,"stddev":0,"min":0,"p10":0,"p90":0,"p99":0,"max":0},"DetachedScriptStates":{"median":2,"mean":2,"mdev":0,"rsd":0,"stddev":0,"min":2,"p10":2,"p90":2,"p99":2,"max":2},"ArrayBufferContents":{"median":0,"mean":0,"mdev":0,"rsd":0,"stddev":0,"min":0,"p10":0,"p90":0,"p99":0,"max":0},"LayoutCount":{"median":6,"mean":6,"mdev":0,"rsd":0,"stddev":0,"min":6,"p10":6,"p90":6,"p99":6,"max":6},"RecalcStyleCount":{"median":5,"mean":5,"mdev":0.2722,"rsd":10.101525445522107,"stddev":0,"min":4,"p10":4,"p90":5,"p99":5,"max":5},"LayoutDuration":{"median":111,"mean":112,"mdev":4.1699,"rsd":6.459019356917102,"stddev":7,"min":103,"p10":103,"p90":121,"p99":121,"max":121},"RecalcStyleDuration":{"median":4,"mean":5,"mdev":0.3831,"rsd":14.633255383104721,"stddev":1,"min":4,"p10":4,"p90":5,"p99":5,"max":5},"DevToolsCommandDuration":{"median":22,"mean":23,"mdev":1.6138,"rsd":11.982386505179681,"stddev":3,"min":21,"p10":21,"p90":27,"p99":27,"max":27},"ScriptDuration":{"median":22,"mean":24,"mdev":2.7787,"rsd":19.663793951730586,"stddev":5,"min":20,"p10":20,"p90":31,"p99":31,"max":31},"V8CompileDuration":{"median":0.415,"mean":0.394,"mdev":0.0244,"rsd":10.734170393880161,"stddev":0.0423,"min":0.335,"p10":0.335,"p90":0.432,"p99":0.432,"max":0.432},"TaskDuration":{"median":242,"mean":243,"mdev":10.8903,"rsd":7.771198909183249,"stddev":19,"min":220,"p10":220,"p90":266,"p99":266,"max":266},"TaskOtherDuration":{"median":81,"mean":78,"mdev":6.1143,"rsd":13.547677981516356,"stddev":11,"min":64,"p10":64,"p90":90,"p99":90,"max":90},"ThreadTime":{"median":0.2027,"mean":0.197,"mdev":0.0054,"rsd":4.741696117352908,"stddev":0.0093,"min":0.1839,"p10":0.1839,"p90":0.2045,"p99":0.2045,"max":0.2045},"ProcessTime":{"median":0.422,"mean":0.4164,"mdev":0.0112,"rsd":4.64509386629612,"stddev":0.0193,"min":0.3904,"p10":0.3904,"p90":0.4368,"p99":0.4368,"max":0.4368},"JSHeapUsedSize":{"median":2027704,"mean":2038441,"mdev":11856.781,"rsd":1.0074632360234168,"stddev":20537,"min":2020440,"p10":2020440,"p90":2067180,"p99":2067180,"max":2067180},"JSHeapTotalSize":{"median":3055616,"mean":2968235,"mdev":71346.5599,"rsd":4.163278196498532,"stddev":123576,"min":2793472,"p10":2793472,"p90":3055616,"p99":3055616,"max":3055616},"FirstMeaningfulPaint":{"median":684,"mean":751,"mdev":59.924,"rsd":13.8119275888877,"stddev":104,"min":672,"p10":672,"p90":898,"p99":898,"max":898}}},"visualMetrics":{"FirstVisualChange":{"median":700,"mean":655,"mdev":50.5444,"rsd":13.358933423624492,"stddev":88,"min":533,"p10":533,"p90":733,"p99":733,"max":733},"LastVisualChange":{"median":733,"mean":789,"mdev":45.4516,"rsd":9.981980765693445,"stddev":79,"min":733,"p10":733,"p90":900,"p99":900,"max":900},"SpeedIndex":{"median":708,"mean":740,"mdev":48.0093,"rsd":11.2370911789533,"stddev":83,"min":658,"p10":658,"p90":854,"p99":854,"max":854},"videoRecordingStart":{"median":900,"mean":900,"mdev":0,"rsd":0,"stddev":0,"min":900,"p10":900,"p90":900,"p99":900,"max":900},"VisualReadiness":{"median":167,"mean":133,"mdev":41.6929,"rsd":54.16064069044974,"stddev":72,"min":33,"p10":33,"p90":200,"p99":200,"max":200},"VisualComplete85":{"median":733,"mean":778,"mdev":50.5444,"rsd":11.257463828052188,"stddev":88,"min":700,"p10":700,"p90":900,"p99":900,"max":900},"VisualComplete95":{"median":733,"mean":789,"mdev":45.4516,"rsd":9.981980765693445,"stddev":79,"min":733,"p10":733,"p90":900,"p99":900,"max":900},"VisualComplete99":{"median":733,"mean":789,"mdev":45.4516,"rsd":9.981980765693445,"stddev":79,"min":733,"p10":733,"p90":900,"p99":900,"max":900}},"cpu":{"longTasks":{"durations":{"median":103,"mean":104,"mdev":8.9608,"rsd":14.971635661508444,"stddev":16,"min":85,"p10":85,"p90":123,"p99":123,"max":123},"tasks":{"median":1,"mean":1,"mdev":0,"rsd":0,"stddev":0,"min":1,"p10":1,"p90":1,"p99":1,"max":1},"totalDuration":{"median":103,"mean":104,"mdev":8.9608,"rsd":14.971635661508444,"stddev":16,"min":85,"p10":85,"p90":123,"p99":123,"max":123},"totalBlockingTime":{"median":0,"mean":18,"mdev":14.4248,"rsd":141.42135623730948,"stddev":25,"min":0,"p10":0,"p90":53,"p99":53,"max":53},"maxPotentialFid":{"median":0,"mean":34,"mdev":28.033,"rsd":141.42135623730948,"stddev":49,"min":0,"p10":0,"p90":103,"p99":103,"max":103},"lastLongTask":{"median":527,"mean":591,"mdev":54.7235,"rsd":16.03789592023389,"stddev":95,"min":521,"p10":521,"p90":725,"p99":725,"max":725},"beforeFirstPaint":{"tasks":{"median":1,"mean":1,"mdev":0.2722,"rsd":70.71067811865476,"stddev":0,"min":0,"p10":0,"p90":1,"p99":1,"max":1},"totalDuration":{"median":85,"mean":69,"mdev":29.6885,"rsd":74.16634809230608,"stddev":51,"min":0,"p10":0,"p90":123,"p99":123,"max":123}},"beforeFirstContentfulPaint":{"tasks":{"median":1,"mean":1,"mdev":0.2722,"rsd":70.71067811865476,"stddev":0,"min":0,"p10":0,"p90":1,"p99":1,"max":1},"totalDuration":{"median":85,"mean":69,"mdev":29.6885,"rsd":74.16634809230608,"stddev":51,"min":0,"p10":0,"p90":123,"p99":123,"max":123}},"beforeLargestContentfulPaint":{"tasks":{"median":1,"mean":1,"mdev":0,"rsd":0,"stddev":0,"min":1,"p10":1,"p90":1,"p99":1,"max":1},"totalDuration":{"median":103,"mean":104,"mdev":8.9608,"rsd":14.971635661508444,"stddev":16,"min":85,"p10":85,"p90":123,"p99":123,"max":123}},"afterLoadEventEnd":{"tasks":{"median":0,"mean":0,"mdev":0,"rsd":0,"stddev":0,"min":0,"p10":0,"p90":0,"p99":0,"max":0},"totalDuration":{"median":0,"mean":0,"mdev":0,"rsd":0,"stddev":0,"min":0,"p10":0,"p90":0,"p99":0,"max":0}}}},"googleWebVitals":{"cumulativeLayoutShift":{"median":0,"mean":0,"mdev":0,"rsd":0,"stddev":0,"min":0,"p10":0,"p90":0,"p99":0,"max":0},"ttfb":{"median":344,"mean":365,"mdev":23.5372,"rsd":11.169214855144936,"stddev":41,"min":329,"p10":329,"p90":422,"p99":422,"max":422},"largestContentfulPaint":{"median":720,"mean":777,"mdev":49.2823,"rsd":10.981051161351099,"stddev":85,"min":714,"p10":714,"p90":898,"p99":898,"max":898},"firstContentfulPaint":{"median":684,"mean":644,"mdev":47.0516,"rsd":12.661171335050316,"stddev":81,"min":530,"p10":530,"p90":717,"p99":717,"max":717},"firstInputDelay":{"median":0,"mean":0,"mdev":0,"rsd":0,"stddev":0,"min":0,"p10":0,"p90":0,"p99":0,"max":0},"totalBlockingTime":{"median":0,"mean":18,"mdev":14.4248,"rsd":141.42135623730948,"stddev":25,"min":0,"p10":0,"p90":53,"p99":53,"max":53}},"deltaToTFFB":{"firstContentfulPaint":{"median":295,"mean":279,"mdev":33.4343,"rsd":20.781061611268882,"stddev":58,"min":201,"p10":201,"p90":340,"p99":340,"max":340},"largestContentfulPaint":{"median":385,"mean":412,"mdev":26.0782,"rsd":10.95444279795537,"stddev":45,"min":376,"p10":376,"p90":476,"p99":476,"max":476},"firstVisualChange":{"median":311,"mean":290,"mdev":36.8068,"rsd":21.957951565213584,"stddev":64,"min":204,"p10":204,"p90":356,"p99":356,"max":356},"lastVisualChange":{"median":404,"mean":424,"mdev":22.4615,"rsd":9.182794964888393,"stddev":39,"min":389,"p10":389,"p90":478,"p99":478,"max":478}},"errors":{"median":0,"mean":0,"min":0,"p90":0,"max":0}}} \ No newline at end of file