diff --git a/.gitignore b/.gitignore index 8ffc0ef..89b6854 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ node_modules tmp .DS_Store npm-debug.log +yarn-error.log .idea gsheets.config.js diff --git a/.travis.yml b/.travis.yml index 5a7399b..e3109e3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,25 +1,25 @@ language: node_js matrix: include: - - node_js: "6" - - node_js: "7" - env: RUN_RECIPES=1 - allow_failures: - - node_js: "7" + - node_js: "8" + - node_js: "9" env: RUN_RECIPES=1 dist: trusty cache: yarn: true directories: - node_modules -before_install: - - npm install -g --no-progress yarn@v0.22.0 install: - - yarn install --no-progress + # if our e2e tests fail in the future it might be that we are not compatible + # with the latest puppeteer api so we probably need to run on chromimum + # @see https://github.com/GoogleChrome/lighthouse/pull/4640/files#r171425004 + - export PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1 + - yarn before_script: - export DISPLAY=:99.0 - - export LIGHTHOUSE_CHROMIUM_PATH="$(pwd)/chrome-linux/chrome" + # see comment above about puppeteer + - export CHROME_PATH="$(which google-chrome-stable)" - sh -e /etc/init.d/xvfb start - - sleep 3 # wait for xvfb to boot + - yarn build addons: chrome: stable diff --git a/bin/cli.js b/bin/cli.js index 97405c7..cac822d 100755 --- a/bin/cli.js +++ b/bin/cli.js @@ -3,7 +3,7 @@ // Licensed under the Apache License, Version 2.0. See LICENSE 'use strict'; -/* eslint-disable no-console */ +/* eslint-disable no-logger */ const sysPath = require('path'); const fs = require('fs'); const yargs = require('yargs'); @@ -11,6 +11,9 @@ const yargs = require('yargs'); const PWMetrics = require('../lib/index'); const {getConfigFromFile} = require('../lib/utils/fs'); const {getMessageWithPrefix, getMessage} = require('../lib/utils/messages'); +const {Logger} = require('../lib/utils/logger'); +const logger = Logger.getInstance(); + let config; const cliFlags = yargs @@ -91,7 +94,7 @@ const writeToDisk = function(fileName, data) { const path = sysPath.join(process.cwd(), fileName); fs.writeFile(path, data, err => { if (err) reject(err); - console.log(getMessageWithPrefix('SUCCESS', 'SAVED_TO_JSON', path)); + logger.log(getMessageWithPrefix('SUCCESS', 'SAVED_TO_JSON', path)); resolve(); }); }); @@ -104,15 +107,16 @@ pwMetrics.start() // serialize accordingly data = JSON.stringify(data, null, 2) + '\n'; // output to file. - if (options.flags.outputPath != 'stdout') + if (options.flags.outputPath != 'stdout') { return writeToDisk(options.flags.outputPath, data); - // output to stdout - else if (data) + // output to stdout + } else if (data) { process.stdout.write(data); + } } }).then(() => { process.exit(0); }).catch(err => { - console.error(err); + logger.error(err); process.exit(1); }); diff --git a/lib/chart/chart.ts b/lib/chart/chart.ts index a2b6bc6..5015154 100644 --- a/lib/chart/chart.ts +++ b/lib/chart/chart.ts @@ -2,10 +2,10 @@ const wunderbar = require('@gribnoysup/wunderbar'); const eol = require('os').EOL; import {Timing, ChartOptions} from '../../types/types'; -const Logger = require('../utils/logger'); +import {Logger} from '../utils/logger'; const logger = Logger.getInstance(); -const drawChart = (timings: Timing[], options: ChartOptions) => { +export const drawChart = (timings: Timing[], options: ChartOptions) => { const {lmargin, width, xlabel, xmin, xmax} = options; const normalizedTimings = timings.map(value => { @@ -53,5 +53,3 @@ const drawChart = (timings: Timing[], options: ChartOptions) => { logger.log([chartTop, chart, chartBottom, chartScale].join(eol)); logger.log(''); }; - -module.exports = drawChart; diff --git a/lib/drive/gdrive.ts b/lib/drive/gdrive.ts index 499f563..efd7bae 100644 --- a/lib/drive/gdrive.ts +++ b/lib/drive/gdrive.ts @@ -5,9 +5,9 @@ const google = require('googleapis'); const promisify = require('micro-promisify'); import { Oauth2Client, AuthorizeCredentials, DriveResponse } from '../../types/types'; +import { Logger } from '../utils/logger'; const GoogleOauth = require('../oauth/google-oauth'); const messages = require('../utils/messages'); -const Logger = require('../utils/logger'); const logger = Logger.getInstance(); class GDrive { diff --git a/lib/expectations.ts b/lib/expectations.ts index 48048ef..cb2d4b6 100644 --- a/lib/expectations.ts +++ b/lib/expectations.ts @@ -1,12 +1,13 @@ // Copyright 2016 Google Inc. All Rights Reserved. // Licensed under the Apache License, Version 2.0. See LICENSE -import { Timing, ExpectationMetrics, NormalizedExpectationMetrics } from '../types/types'; -const { getAssertionMessage, getMessageWithPrefix } = require('./utils/messages'); -const Logger = require('./utils/logger'); +import {Logger} from './utils/logger'; +import {getAssertionMessage, getMessageWithPrefix} from './utils/messages'; +import {Timing, ExpectationMetrics, NormalizedExpectationMetrics} from '../types/types'; + const logger = Logger.getInstance(); -function validateMetrics(metrics: ExpectationMetrics) { +export const validateMetrics = (metrics: ExpectationMetrics) => { const metricsKeys = Object.keys(metrics); if (!metrics || !metricsKeys.length) { @@ -20,9 +21,9 @@ function validateMetrics(metrics: ExpectationMetrics) { process.exit(1); } }); -} +}; -function normalizeMetrics(metrics: ExpectationMetrics): NormalizedExpectationMetrics { +export const normalizeExpectationMetrics = (metrics: ExpectationMetrics): NormalizedExpectationMetrics => { let normalizedMetrics: NormalizedExpectationMetrics = {}; Object.keys(metrics).forEach(key => { normalizedMetrics[key] = { @@ -31,9 +32,9 @@ function normalizeMetrics(metrics: ExpectationMetrics): NormalizedExpectationMet }; }); return normalizedMetrics; -} +}; -function checkExpectations(metricsData: Timing[], expectationMetrics: NormalizedExpectationMetrics) { +export const checkExpectations = (metricsData: Timing[], expectationMetrics: NormalizedExpectationMetrics) => { metricsData.forEach(metric => { const metricName = metric.id; const expectationValue = expectationMetrics[metricName]; @@ -52,10 +53,4 @@ function checkExpectations(metricsData: Timing[], expectationMetrics: Normalized logger.log(msg); } }); -} - -module.exports = { - validateMetrics: validateMetrics, - normalizeMetrics: normalizeMetrics, - checkExpectations: checkExpectations }; diff --git a/lib/index.ts b/lib/index.ts index 1771586..7c66743 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -1,29 +1,24 @@ // Copyright 2016 Google Inc. All Rights Reserved. // Licensed under the Apache License, Version 2.0. See LICENSE -import {launch, LaunchedChrome} from 'chrome-launcher'; -const lighthouse = require('lighthouse'); -const parseChromeFlags = require('lighthouse/lighthouse-cli/run').parseChromeFlags; -const perfConfig: any = require('./lh-config'); const opn = require('opn'); const path = require('path'); -const Sheets = require('./sheets/index'); -const Chart = require('./chart/chart'); -const metrics = require('./metrics'); -const expectations = require('./expectations'); -const {upload} = require('./upload'); -const messages = require('./utils/messages'); -const drawChart = require('./chart/chart'); -const Logger = require('./utils/logger'); +import {METRICS} from './metrics/metrics'; +import {Logger} from './utils/logger'; +import {LHRunner} from './lh-runner'; +import {Sheets} from './sheets'; +import {adaptMetricsData} from './metrics/metrics-adapter'; +import {validateMetrics, normalizeExpectationMetrics, checkExpectations} from './expectations'; +import {upload} from './upload'; +import {getMessage, getMessageWithPrefix} from './utils/messages'; +import {drawChart} from './chart/chart'; import { MainOptions, FeatureFlags, AuthorizeCredentials, - LighthouseResults, MetricsResults, - TermWritableStream, PWMetricsResults, SheetsConfig, ExpectationMetrics, @@ -31,8 +26,7 @@ import { Timing } from '../types/types'; -const MAX_LIGHTHOUSE_TRIES = 2; -const getTimelineViewerUrl = (id: string) => `https://chromedevtools.github.io/timeline-viewer/?loadTimelineFromURL=https://drive.google.com/file/d//${id}/view?usp=drivesdk` +const getTimelineViewerUrl = (id: string) => `https://chromedevtools.github.io/timeline-viewer/?loadTimelineFromURL=https://drive.google.com/file/d//${id}/view?usp=drivesdk`; class PWMetrics { flags: FeatureFlags = { @@ -47,35 +41,29 @@ class PWMetrics { }; runs: number; sheets: SheetsConfig; - expectations: ExpectationMetrics | NormalizedExpectationMetrics; + normalizedExpectations: NormalizedExpectationMetrics; clientSecret: AuthorizeCredentials; - tryLighthouseCounter: number; - launcher: LaunchedChrome; - parsedChromeFlags: Array; logger: any; constructor(public url: string, opts: MainOptions) { this.flags = Object.assign({}, this.flags, opts.flags); this.runs = this.flags.runs; this.sheets = opts.sheets; - this.expectations = opts.expectations; this.clientSecret = opts.clientSecret; - this.tryLighthouseCounter = 0; + const expectations: ExpectationMetrics = opts.expectations; // normalize path if provided if (this.flags.chromePath) { - this.flags.chromePath = path.normalize(this.flags.chromePath); + this.flags.chromePath = path.normalize(this.flags.chromePath); } if (this.flags.expectations) { - if (this.expectations) { - expectations.validateMetrics(this.expectations); - this.expectations = expectations.normalizeMetrics(this.expectations); - } else throw new Error(messages.getMessageWithPrefix('ERROR', 'NO_EXPECTATIONS_FOUND')); + if (expectations) { + validateMetrics(expectations); + this.normalizedExpectations = normalizeExpectationMetrics(expectations); + } else throw new Error(getMessageWithPrefix('ERROR', 'NO_EXPECTATIONS_FOUND')); } - this.parsedChromeFlags = parseChromeFlags(this.flags.chromeFlags); - this.logger = Logger.getInstance({showOutput: this.flags.showOutput}); } @@ -83,44 +71,42 @@ class PWMetrics { const runs = Array.apply(null, {length: +this.runs}).map(Number.call, Number); let metricsResults: MetricsResults[] = []; - let resultHasExpectationErrors = false; - for (let runIndex of runs) { try { - const currentMetricResult: MetricsResults = await this.run(); - if (!resultHasExpectationErrors && this.flags.expectations) { - resultHasExpectationErrors = this.resultHasExpectationErrors(currentMetricResult); - } - metricsResults[runIndex] = currentMetricResult; - this.logger.log(messages.getMessageWithPrefix('SUCCESS', 'SUCCESS_RUN', runIndex, runs.length)); + const lhRunner = new LHRunner(this.url, this.flags); + const lhTrace = await lhRunner.run(); + metricsResults[runIndex] = await this.recordLighthouseTrace(lhTrace); + this.logger.log(getMessageWithPrefix('SUCCESS', 'SUCCESS_RUN', runIndex, runs.length)); } catch (error) { metricsResults[runIndex] = error; - this.logger.error(messages.getMessageWithPrefix('ERROR', 'FAILED_RUN', runIndex, runs.length, error.message)); + this.logger.error(getMessageWithPrefix('ERROR', 'FAILED_RUN', runIndex, runs.length, error.message)); } } - let results: PWMetricsResults = { runs: metricsResults.filter(r => !(r instanceof Error)) }; - if (results.runs.length > 0) { - if (this.runs > 1 && !this.flags.submit) { - results.median = this.findMedianRun(results.runs); - this.logger.log(messages.getMessage('MEDIAN_RUN')); - this.displayOutput(results.median); - } else if (this.flags.submit) { - const sheets = new Sheets(this.sheets, this.clientSecret); - await sheets.appendResults(results.runs); - } + const results: PWMetricsResults = {runs: metricsResults.filter(r => !(r instanceof Error))}; + if (this.runs > 1 && !this.flags.submit) { + results.median = this.findMedianRun(results.runs); + this.logger.log(getMessage('MEDIAN_RUN')); + this.displayOutput(results.median); + } else if (this.flags.submit) { + const sheets = new Sheets(this.sheets, this.clientSecret); + await sheets.appendResults(results.runs); } - if (resultHasExpectationErrors && this.flags.expectations) { - throw new Error(messages.getMessage('HAS_EXPECTATION_ERRORS')); + if (this.flags.expectations) { + const resultsToCompare = this.runs > 1 ? results.median.timings : results[0].timings; + if (this.resultHasExpectationErrors(resultsToCompare)) { + checkExpectations(resultsToCompare, this.normalizedExpectations); + this.logger.error(getMessage('HAS_EXPECTATION_ERRORS')); + } } return results; } - resultHasExpectationErrors(metrics: MetricsResults): boolean { - return metrics.timings.some((timing: Timing) => { - const expectation = this.expectations[timing.id]; + resultHasExpectationErrors(timings: Timing[]): boolean { + return timings.some((timing: Timing) => { + const expectation = this.normalizedExpectations[timing.id]; if (!expectation) { return false; } @@ -129,90 +115,9 @@ class PWMetrics { }); } - async run(): Promise { - try { - let lhResults: LighthouseResults; - await this.launchChrome(); - - if (process.env.CI) { - // handling CRI_TIMEOUT issue - https://github.com/GoogleChrome/lighthouse/issues/833 - this.tryLighthouseCounter = 0; - lhResults = await this.runLighthouseOnCI().then((lhResults:LighthouseResults) => { - // fix for https://github.com/paulirish/pwmetrics/issues/63 - return new Promise(resolve => { - this.logger.log(messages.getMessage('WAITING')); - setTimeout(_ => { - return resolve(lhResults); - }, 2000); - }); - }); - } else { - lhResults = await lighthouse(this.url, this.flags, perfConfig); - } - - const metricsResults: MetricsResults = await this.recordLighthouseTrace(lhResults); - await this.killLauncher(); - - return metricsResults; - } catch (error) { - await this.killLauncher(); - throw error; - } - } - - async killLauncher() { - if (typeof this.launcher !== 'undefined') { - await this.launcher!.kill(); - } - } - - async runLighthouseOnCI(): Promise { + async recordLighthouseTrace(data: LH.RunnerResult): Promise { try { - return await lighthouse(this.url, this.flags, perfConfig); - } catch(error) { - if (error.code === 'CRI_TIMEOUT' && this.tryLighthouseCounter <= MAX_LIGHTHOUSE_TRIES) { - return await this.retryLighthouseOnCI(); - } - - if (this.tryLighthouseCounter > MAX_LIGHTHOUSE_TRIES) { - throw new Error(messages.getMessage('CRI_TIMEOUT_REJECT')); - } - } - } - - async retryLighthouseOnCI(): Promise { - this.tryLighthouseCounter++; - this.logger.log(messages.getMessage('CRI_TIMEOUT_RELAUNCH')); - - try { - return await this.runLighthouseOnCI(); - } catch(error) { - this.logger.error(error.message); - this.logger.error(messages.getMessage('CLOSING_CHROME')); - await this.killLauncher(); - } - } - - async launchChrome(): Promise { - try { - this.logger.log(messages.getMessage('LAUNCHING_CHROME')); - this.launcher = await launch({ - port: this.flags.port, - chromeFlags: this.parsedChromeFlags, - chromePath: this.flags.chromePath - }); - this.flags.port = this.launcher.port; - return this.launcher; - } catch(error) { - this.logger.error(error); - await this.killLauncher(); - return error; - } - } - - async recordLighthouseTrace(data: LighthouseResults): Promise { - try { - const preparedData = metrics.prepareData(data); + const preparedData = adaptMetricsData(data.lhr); if (this.flags.upload) { const driveResponse = await upload(data, this.clientSecret); @@ -223,10 +128,6 @@ class PWMetrics { this.displayOutput(preparedData); } - if (this.flags.expectations) { - expectations.checkExpectations(preparedData.timings, this.expectations); - } - return preparedData; } catch (error) { throw error; @@ -247,20 +148,20 @@ class PWMetrics { timings = timings.filter(r => { // filter out metrics that failed to record if (r.timing === undefined || isNaN(r.timing)) { - this.logger.log(messages.getMessageWithPrefix('ERROR', 'METRIC_IS_UNAVAILABLE', r.title)); + this.logger.error(getMessageWithPrefix('ERROR', 'METRIC_IS_UNAVAILABLE', r.title)); return false; + } else { + return true; } - // don't chart hidden metrics, but include in json - return !metrics.hiddenMetrics.includes(r.id); }); const fullWidthInMs = Math.max(...timings.map(result => result.timing)); const maxLabelWidth = Math.max(...timings.map(result => result.title.length)); - const stdout = (process.stdout); + const terminalWidth = process.stdout.columns || 90; drawChart(timings, { // 90% of terminal width to give some right margin - width: stdout.columns * 0.9 - maxLabelWidth, + width: terminalWidth * 0.9 - maxLabelWidth, xlabel: 'Time (ms) since navigation start', xmin: 0, @@ -273,12 +174,12 @@ class PWMetrics { } findMedianRun(results: MetricsResults[]): MetricsResults { - const ttfiValues = results.map(r => r.timings.find(timing => timing.id === metrics.ids.TTFI).timing); - const medianTTFI = this.median(ttfiValues); + const TTFCPUIDLEValues = results.map(r => r.timings.find(timing => timing.id === METRICS.TTFCPUIDLE).timing); + const medianTTFCPUIDLE = this.median(TTFCPUIDLEValues); // in the case of duplicate runs having the exact same TTFI, we naively pick the first // @fixme, but any for now... - return results.find((result: any) => result.timings.find((timing:any) => - timing.id === metrics.ids.TTFI && timing.timing === medianTTFI + return results.find((result: any) => result.timings.find((timing: any) => + timing.id === METRICS.TTFCPUIDLE && timing.timing === medianTTFCPUIDLE ) ); } diff --git a/lib/lh-config.ts b/lib/lh-config.ts deleted file mode 100644 index 85f8cd2..0000000 --- a/lib/lh-config.ts +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2016 Google Inc. All Rights Reserved. -// Licensed under the Apache License, Version 2.0. See LICENSE - -module.exports = { - passes: [{ - recordTrace: true, - pauseBeforeTraceEndMs: 5000, - pauseAfterNetworkQuietMs: 2500, - pauseAfterLoadMs: 5250, - networkQuietThresholdMs: 5250, - cpuQuietThresholdMs: 5250, - useThrottling: true, - gatherers: [] - }], - - audits: [ - 'first-meaningful-paint', - 'speed-index-metric', - 'estimated-input-latency', - 'first-interactive', - 'consistently-interactive' - ] -}; diff --git a/lib/lh-runner.ts b/lib/lh-runner.ts new file mode 100644 index 0000000..dba9c93 --- /dev/null +++ b/lib/lh-runner.ts @@ -0,0 +1,104 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// Licensed under the Apache License, Version 2.0. See LICENSE + +const lighthouse = require('lighthouse/lighthouse-core'); +const parseChromeFlags = require('lighthouse/lighthouse-cli/run').parseChromeFlags; +import {launch, LaunchedChrome} from 'chrome-launcher'; +import {Logger} from './utils/logger'; +import {FeatureFlags} from '../types/types'; +import {getMessage} from './utils/messages'; + +const perfConfig: any = require('./perf-config'); +const MAX_LIGHTHOUSE_TRIES = 2; + +export class LHRunner { + launcher: LaunchedChrome; + tryLighthouseCounter: number; + logger: any; + + //@todo improve FeatureFlags -> LHFlags + constructor(public url: string, public flags: FeatureFlags) { + this.tryLighthouseCounter = 0; + this.logger = Logger.getInstance({showOutput: this.flags.showOutput}); + } + + async run(): Promise { + try { + let lhResults: LH.RunnerResult; + await this.launchChrome(); + + if (process.env.CI) { + // handling CRI_TIMEOUT issue - https://github.com/GoogleChrome/lighthouse/issues/833 + this.tryLighthouseCounter = 0; + lhResults = await this.runLighthouseOnCI().then((lhResults: LH.RunnerResult) => { + // fix for https://github.com/paulirish/pwmetrics/issues/63 + return new Promise(resolve => { + this.logger.log(getMessage('WAITING')); + setTimeout(_ => { + return resolve(lhResults); + }, 2000); + }); + }); + } else { + lhResults = await lighthouse(this.url, this.flags, perfConfig); + } + + await this.killLauncher(); + + return lhResults; + } catch (error) { + await this.killLauncher(); + throw error; + } + } + + async killLauncher() { + if (typeof this.launcher !== 'undefined') { + await this.launcher!.kill(); + } + } + + async runLighthouseOnCI(): Promise { + try { + return await lighthouse(this.url, this.flags, perfConfig); + } catch (error) { + if (error.code === 'CRI_TIMEOUT' && this.tryLighthouseCounter <= MAX_LIGHTHOUSE_TRIES) { + return await this.retryLighthouseOnCI(); + } + + if (this.tryLighthouseCounter > MAX_LIGHTHOUSE_TRIES) { + throw new Error(getMessage('CRI_TIMEOUT_REJECT')); + } + } + } + + async retryLighthouseOnCI(): Promise { + this.tryLighthouseCounter++; + this.logger.log(getMessage('CRI_TIMEOUT_RELAUNCH')); + + try { + return await this.runLighthouseOnCI(); + } catch (error) { + this.logger.error(error.message); + this.logger.error(getMessage('CLOSING_CHROME')); + await this.killLauncher(); + } + } + + async launchChrome(): Promise { + try { + this.logger.log(getMessage('LAUNCHING_CHROME')); + this.launcher = await launch({ + port: this.flags.port, + chromeFlags: parseChromeFlags(this.flags.chromeFlags), + chromePath: this.flags.chromePath + }); + this.flags.port = this.launcher.port; + return this.launcher; + } catch (error) { + this.logger.error(error); + await this.killLauncher(); + return error; + } + } +} diff --git a/lib/metrics.ts b/lib/metrics.ts deleted file mode 100644 index 6ee3a13..0000000 --- a/lib/metrics.ts +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2016 Google Inc. All Rights Reserved. -// Licensed under the Apache License, Version 2.0. See LICENSE - - -import {MetricsResults, MetricsDefinition, Timing, Timestamp, LighthouseResults, LighthouseAudits} from '../types/types'; - -const metricsDefinitions: MetricsDefinition[] = require('lighthouse/lighthouse-core/lib/traces/pwmetrics-events.js').metricsDefinitions; -const Logger = require('./utils/logger'); -const logger = Logger.getInstance(); - -const metricsIds = { - NAVSTART: 'navstart', - TTFCP: 'ttfcp', - TTFMP: 'ttfmp', - PSI: 'psi', - FV: 'fv', - VC85: 'vc85', - VC100: 'vc100', - TTI: 'tti', - TTFI: 'ttfi', - TTCI: 'ttci', - EndOfATrace: 'eot', - OnLoad: 'onload' -}; - -module.exports = { - hiddenMetrics: [ - metricsIds.FV, - metricsIds.VC100, - metricsIds.VC85, - metricsIds.EndOfATrace, - metricsIds.OnLoad, - metricsIds.TTI, - metricsIds.NAVSTART - ], - ids: metricsIds, - prepareData -}; - -const checkAudits = (audits: LighthouseAudits) => Object.keys(audits).forEach(key => { - const debugString = audits[key].debugString; - if (audits[key].debugString) - logger.log(`${debugString} Audit key: ${key}`); -}); - -function prepareData(res: LighthouseResults): MetricsResults { - const audits = res.audits; - - checkAudits(audits); - - const colorP0 = 'yellow'; - const colorP2 = 'green'; - const colorVisual = 'blue'; - - const timings: Timing[] = []; - const navStart = metricsDefinitions.find(def => def.id === metricsIds.NAVSTART); - const timestamps: Timestamp[] = [{ - title: navStart.name, - id: navStart.id, - timestamp: navStart.getTs(audits) - }]; - - metricsDefinitions - // exclude navStart as its not a timing - .filter(def => def.id !== metricsIds.NAVSTART) - // exclude experimental metrics - .filter(def => def.id !== metricsIds.TTI - && def.id !== metricsIds.OnLoad - && def.id !== metricsIds.EndOfATrace) - .forEach(metric => { - const resolvedMetric: Timing = { - title: metric.name, - id: metric.id, - timestamp: metric.getTs(audits), - timing: (metric.getTs(audits) - navStart.getTs(audits)) / 1000, - color: colorVisual - }; - - switch (metric.id) { - case metricsIds.TTFCP: - case metricsIds.TTFMP: - resolvedMetric.color = colorP2; - break; - case metricsIds.TTFI: - case metricsIds.TTCI: - resolvedMetric.color = colorP0; - break; - } - - timings.push(resolvedMetric); - }); - - return { - timings, - timestamps, - generatedTime: res.generatedTime, - lighthouseVersion: res.lighthouseVersion, - initialUrl: res.initialUrl, - url: res.url - }; -} diff --git a/lib/metrics/metrics-adapter.ts b/lib/metrics/metrics-adapter.ts new file mode 100644 index 0000000..25b8447 --- /dev/null +++ b/lib/metrics/metrics-adapter.ts @@ -0,0 +1,76 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// Licensed under the Apache License, Version 2.0. See LICENSE + +import {MetricsResults, Timing} from '../../types/types'; +import {getMessage} from '../utils/messages'; +import {Logger} from '../utils/logger'; +import {METRICS} from './metrics'; + +const logger = Logger.getInstance(); + +const checkMetrics = (metrics: Record) => { + const errorMessage = metrics.errorMessage; + const explanation = metrics.details.explanation; + if (errorMessage) + logger.log(`${errorMessage} \n ${explanation}`); +}; + +const getMetricTitle = (metricId) => { + try { + return getMessage(metricId); + } catch (e) { + return ''; + } +}; + +export const adaptMetricsData = (res: LH.Result): MetricsResults => { + const auditResults:Record = res.audits; + + // has to be Record + const metricsAudit:any = auditResults.metrics; + if (!metricsAudit || !metricsAudit.details || !metricsAudit.details.items) return; + + const metricsValues = metricsAudit.details.items[0]; + + checkMetrics(metricsAudit); + + const colorP0 = 'yellow'; + const colorP2 = 'green'; + const colorVisual = 'blue'; + + const timings: Timing[] = []; + + // @todo improve to Object.entries + Object.keys(metricsValues).forEach(metricKey => { + if (!Object.values(METRICS).includes(metricKey)) return; + + const metricTitle = getMetricTitle(metricKey); + const resolvedMetric: Timing = { + title: metricTitle, + id: metricKey, + timing: metricsValues[metricKey], + color: colorVisual + }; + + switch (metricKey) { + case METRICS.TTFCP: + case METRICS.TTFMP: + resolvedMetric.color = colorP2; + break; + case METRICS.TTFCPUIDLE: + case METRICS.TTI: + resolvedMetric.color = colorP0; + break; + } + + timings.push(resolvedMetric); + }); + + return { + timings, + generatedTime: res.fetchTime, + lighthouseVersion: res.lighthouseVersion, + requestedUrl: res.requestedUrl, + finalUrl: res.finalUrl, + }; +}; diff --git a/lib/metrics/metrics.ts b/lib/metrics/metrics.ts new file mode 100644 index 0000000..2ed4eb5 --- /dev/null +++ b/lib/metrics/metrics.ts @@ -0,0 +1,12 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// Licensed under the Apache License, Version 2.0. See LICENSE + +export const METRICS = { + TTFCP: 'firstContentfulPaint', + TTFMP: 'firstMeaningfulPaint', + TTFCPUIDLE: 'firstCPUIdle', + TTI: 'interactive', + SI: 'speedIndex', + // @todo add in further improvements + // VISUALLY_COMPLETE: 'observedLastVisualChange', +}; diff --git a/lib/oauth/google-oauth.ts b/lib/oauth/google-oauth.ts index b65d258..f0765fe 100644 --- a/lib/oauth/google-oauth.ts +++ b/lib/oauth/google-oauth.ts @@ -10,7 +10,7 @@ const readlineSync = require('readline-sync'); const { getMessage } = require('../utils/messages'); import { AuthorizeCredentials, Oauth2Client } from '../../types/types'; -const Logger = require('../utils/logger'); +import {Logger} from '../utils/logger'; const logger = Logger.getInstance(); /* improve the bad polyfill that devtools-frontend did */ diff --git a/lib/perf-config.ts b/lib/perf-config.ts new file mode 100644 index 0000000..3212b49 --- /dev/null +++ b/lib/perf-config.ts @@ -0,0 +1,6 @@ +module.exports = { + extends: 'lighthouse:default', + settings: { + onlyAudits: ['metrics'], + }, +}; diff --git a/lib/sheets/gsheets.ts b/lib/sheets/gsheets.ts index ad46c4f..4bd536f 100644 --- a/lib/sheets/gsheets.ts +++ b/lib/sheets/gsheets.ts @@ -7,7 +7,7 @@ const promisify = require('micro-promisify'); const { getMessage } = require('../utils/messages'); import { Oauth2Client, GSheetsAppendResultsOptions, GSheetsValuesToAppend } from '../../types/types'; -const Logger = require('../utils/logger'); +import { Logger } from '../utils/logger'; const logger = Logger.getInstance(); async function getRange(auth: Oauth2Client, range: number, spreadsheetId: string): Promise> { @@ -51,7 +51,7 @@ async function appendResults(auth: Oauth2Client, valuesToAppend: Array = await getRange(auth, response.updates.updatedRange, options.spreadsheetId); logger.log(getMessage('G_SHEETS_APPENDED', formatValues(rangeValues))); } catch(error) { - log.error(getMessage('G_SHEETS_API_ERROR', error)); + logger.error(getMessage('G_SHEETS_API_ERROR', error)); throw new Error(error); } } diff --git a/lib/sheets/index.ts b/lib/sheets/index.ts index 263779e..7e3007c 100644 --- a/lib/sheets/index.ts +++ b/lib/sheets/index.ts @@ -8,13 +8,13 @@ import * as gsheets from './gsheets'; // @todo add 'import' after moving all stuff to typescript const { getMessage } = require('../utils/messages'); -const metricsIds = require('../metrics').ids; +const { METRICS } = require('../metrics/metrics'); const SHEET_TYPES = { 'GOOGLE_SHEETS': 'GOOGLE_SHEETS' }; -class Sheets { +export class Sheets { constructor(public config: SheetsConfig, public clientSecret: AuthorizeCredentials) { this.validateOptions(config, clientSecret); } @@ -53,16 +53,13 @@ class Sheets { // order matters valuesToAppend.push([ data.lighthouseVersion, - data.url, + data.requestedUrl, `${dateObj.toLocaleDateString()} ${dateObj.toLocaleTimeString()}`, - getTiming(metricsIds.TTFCP), - getTiming(metricsIds.TTFMP), - getTiming(metricsIds.PSI), - getTiming(metricsIds.FV), - getTiming(metricsIds.VC100), - getTiming(metricsIds.TTFI), - getTiming(metricsIds.TTCI), - getTiming(metricsIds.VC85) + getTiming(METRICS.TTFCP), + getTiming(METRICS.TTFMP), + getTiming(METRICS.SI), + getTiming(METRICS.TTFCPUIDLE), + getTiming(METRICS.TTI), ]); }); @@ -75,5 +72,3 @@ class Sheets { } } } - -module.exports = Sheets; diff --git a/lib/upload.ts b/lib/upload.ts index 717c05e..e4699ea 100644 --- a/lib/upload.ts +++ b/lib/upload.ts @@ -3,12 +3,12 @@ const {prepareAssets} = require('lighthouse/lighthouse-core/lib/asset-saver'); -import {AuthorizeCredentials, LighthouseResults, PreparedAssets, DriveResponse} from '../types/types'; +import {AuthorizeCredentials, PreparedAssets, DriveResponse} from '../types/types'; const GDrive = require('./drive/gdrive'); -const upload = async function(metricsData: LighthouseResults, clientSecret: AuthorizeCredentials): Promise { +export const upload = async function(metricsData: LH.RunnerResult, clientSecret: AuthorizeCredentials): Promise { try { - const assets: PreparedAssets[] = await prepareAssets(metricsData.artifacts, metricsData.audits); + const assets: PreparedAssets[] = await prepareAssets(metricsData.artifacts, metricsData.lhr.audits); const trace = assets.map(data => { return data.traceData; }); @@ -19,7 +19,3 @@ const upload = async function(metricsData: LighthouseResults, clientSecret: Auth throw error; } }; - -module.exports = { - upload -}; diff --git a/lib/utils/logger.ts b/lib/utils/logger.ts index 78b091d..4f19417 100644 --- a/lib/utils/logger.ts +++ b/lib/utils/logger.ts @@ -1,9 +1,9 @@ import { LoggerOptions} from '../../types/types'; -class Logger { +export class Logger { static options: LoggerOptions = { showOutput: true - } + }; private static instance: Logger; constructor() {} @@ -26,5 +26,3 @@ class Logger { } } } - -module.exports = Logger; \ No newline at end of file diff --git a/lib/utils/messages.ts b/lib/utils/messages.ts index c099d86..8671fea 100644 --- a/lib/utils/messages.ts +++ b/lib/utils/messages.ts @@ -1,5 +1,6 @@ // Copyright 2016 Google Inc. All Rights Reserved. // Licensed under the Apache License, Version 2.0. See LICENSE +import {METRICS} from '../metrics/metrics'; const GREEN = '\x1B[32m'; const YELLOW = '\x1b[33m'; @@ -12,7 +13,14 @@ const redify = (str: string) => `${RED}${str}${RESET}`; const yellowify = (str: string) => `${YELLOW}${str}${RESET}`; const boldify = (str: string) => `${BOLD}${str}${RESET}`; -const getMessage = function (messageType: string, ...args: any[]) { +const GREEN_CHECK = greenify('✓'); +const YELLOW_FLAG = yellowify('⚑'); +const RED_X = redify('✘'); +const getErrorPrefix = () => ` ${RED_X} Error: ${RED}`; +const getWarningPrefix = () => ` ${YELLOW_FLAG} Warning: ${YELLOW}`; +const getSuccessPrefix = () => ` ${GREEN_CHECK} Success: ${GREEN}`; + +export const getMessage = function (messageType: string, ...args: any[]) { switch (messageType) { case 'NO_URL': return 'No url entered.'; @@ -44,24 +52,16 @@ const getMessage = function (messageType: string, ...args: any[]) { return `No matching message prefix: ${args[0]}`; case 'METRIC_IS_UNAVAILABLE': return `Sorry, ${args[0]} metric is unavailable`; - case 'ttfcp': + case METRICS.TTFCP: return 'First Contentful Paint'; - case 'ttfmp': + case METRICS.TTFMP: return 'First Meaningful Paint'; - case 'psi': - return 'Perceptual Speed Index'; - case 'fv': - return 'First Visual Change'; - case 'vc': - return 'Visually Complete 100%'; - case 'tti': + case METRICS.SI: + return 'Speed Index'; + case METRICS.TTFCPUIDLE: + return 'First CPU Idle'; + case METRICS.TTI: return 'Time to Interactive'; - case 'ttfi': - return 'First Interactive (vBeta)'; - case 'ttci': - return 'Time to Consistently Interactive (vBeta)'; - case 'vc85': - return 'Visually Complete 85%'; case 'SUCCESS_RUN': return `Run ${args[0] + 1} of ${args[1]} finished successfully`; case 'FAILED_RUN': @@ -89,7 +89,10 @@ const getMessage = function (messageType: string, ...args: any[]) { } }; -const getAssertionMessage = function (assertionLevel: string, messageType: string, expectedValue: number, actualValue: number) { +export const getAssertionMessage = function (assertionLevel: string, + messageType: string, + expectedValue: number, + actualValue: number) { const message = getMessageWithPrefix(assertionLevel, messageType); const colorizer = assertionLevel === 'ERROR' ? redify : yellowify; @@ -98,7 +101,9 @@ const getAssertionMessage = function (assertionLevel: string, messageType: strin return `${message} Expected ${expectedStr}, but found ${actualStr}.`; }; -const getMessageWithPrefix = function (assertionLevel: string, messageType: string, ...args: any[]) { +export const getMessageWithPrefix = function (assertionLevel: string, + messageType: string, + ...args: any[]) { let prefix; const message = getMessage(messageType, ...args); @@ -118,16 +123,3 @@ const getMessageWithPrefix = function (assertionLevel: string, messageType: stri return `${prefix}${message}.${RESET}`; }; - -const GREEN_CHECK = greenify('✓'); -const YELLOW_FLAG = yellowify('⚑'); -const RED_X = redify('✘'); -const getErrorPrefix = () => ` ${RED_X} Error: ${RED}`; -const getWarningPrefix = () => ` ${YELLOW_FLAG} Warning: ${YELLOW}`; -const getSuccessPrefix = () => ` ${GREEN_CHECK} Success: ${GREEN}`; - -module.exports = { - getMessage, - getAssertionMessage, - getMessageWithPrefix -}; diff --git a/package.json b/package.json index 4b3180b..a1157e2 100644 --- a/package.json +++ b/package.json @@ -17,26 +17,26 @@ "author": "Paul Irish", "license": "Apache-2.0", "dependencies": { - "@gribnoysup/wunderbar": "^2.2.0", - "@types/node": "^6.0.45", + "@gribnoysup/wunderbar": "^2.2.1", + "@types/node": "*", "chrome-launcher": "^0.10.2", "google-auth-library": "^0.10.0", "googleapis": "^16.0.0", - "lighthouse": "^2.9.4", + "lighthouse": "^3.1.1", "micro-promisify": "^0.1.1", "readline-sync": "^1.4.6", "yargs": "^6.6.0" }, "devDependencies": { "chai": "^3.5.0", + "devtools-protocol": "^0.0.589586", "eslint": "^3.12.0", "eslint-config-google": "^0.7.1", "gulp": "^3.9.1", - "gulp-connect": "^5.0.0", "mocha": "^3.2.0", "sinon": "^1.17.7", "sinon-chai": "^2.8.0", - "typescript": "^2.0.3" + "typescript": "3.0.1" }, "repository": { "type": "git", @@ -52,6 +52,6 @@ }, "homepage": "https://github.com/paulirish/pwmetrics#readme", "engines": { - "node": ">= 6" + "node": ">=8.9" } } diff --git a/readme.md b/readme.md index 6671ada..97ac464 100644 --- a/readme.md +++ b/readme.md @@ -1,10 +1,10 @@ -

pwmetrics

+

PWMetrics

Progressive web metrics at your fingertipz. 💅

-

CLI tool and lib to gather performance metrics via Lighthouse. IN BETA.

+

CLI tool and lib to gather performance metrics via Lighthouse. ![image](https://cloud.githubusercontent.com/assets/39191/19417867/7aead922-93af-11e6-88ec-917dad6e89d2.png) @@ -107,6 +107,8 @@ module.exports = { `pwmetrics-config.js` ```js +const METRICS = require('pwmetrics/lib/metrics/metrics'); + module.exports = { url: 'http://example.com/', flags: { // AKA feature flags @@ -126,32 +128,23 @@ module.exports = { // these expectations values are examples, for your cases set your own // it's not required to use all metrics, you can use just a few of them // Read _Available metrics_ where all keys are defined - ttfcp: { + [METRICS.TTFCP]: { warn: '>=1500', error: '>=2000' }, - ttfmp: { + [METRICS.TTFMP]: { warn: '>=2000', error: '>=3000' }, - fv: { - ... - }, - psi: { + [METRICS.TTI]: { ... }, - vc85: { + [METRICS.TTFCPUIDLE]: { ... }, - vs100: { + [METRICS.SI]: { ... }, - ttfi: { - ... - }, - ttci: { - ... - } }, sheets: { type: 'GOOGLE_SHEETS', // sheets service type. Available types: GOOGLE_SHEETS @@ -219,7 +212,7 @@ Submit results to Google Sheets *Instructions:* -- Copy [this spreadsheet](https://docs.google.com/spreadsheets/d/14DXR9x267fOftf7sYFuUlT3djChSl6PNuPBvUD4h9Rw/edit). +- Copy [this spreadsheet](https://docs.google.com/spreadsheets/d/17jgt_uKxm4WvROmKMfSDzhdCAstNvyaiDP_k2XqzgD0). - Copy the ID of the spreadsheet into the config as value of `sheets.options.spreadsheetId` property. - Setup Google Developer project and get credentials. ([everything in step 1 here](https://developers.google.com/sheets/api/quickstart/nodejs#step_1_turn_on_the_api_name)) - Take a `client_secret` and put it into the config as value of `clientSecret` property. @@ -311,14 +304,18 @@ module.exports = { #### Available metrics: - - `ttfcp` - First Contentful Paint - - `ttfmp` - First Meaningful Paint - - `psi` - Perceptual Speed Index - - `fv` - First Visual Change - - `vc` - Visually Complete 100% - - `ttfi` - First Interactive (vBeta) - - `ttci` - Time to Consistently Interactive (vBeta) - - `vc85` - Visually Complete 85% +All metrics now are stored in separate constant object located in `pwmetrics/lib/metrics/metrics`; + +```js +// Metrics.js +{ + TTFCP: 'first-contentful-paint', + TTFMP: 'first-meaningful-paint', + TTFCPUIDLE: 'first-cpu-idle', + TTI: 'interactive', + SI: 'speed-index', +} +``` Read article [Performance metrics. What’s this all about?](https://medium.com/@denar90/performance-metrics-whats-this-all-about-1128461ad6b) which is decoding this metrics. diff --git a/recipes/gulp/gulpfile.js b/recipes/gulp/gulpfile.js index 4d4eec1..ecbedff 100644 --- a/recipes/gulp/gulpfile.js +++ b/recipes/gulp/gulpfile.js @@ -4,47 +4,30 @@ /* eslint-disable no-console */ const gulp = require('gulp'); -const connect = require('gulp-connect'); const PWMetrics = require('../../lib/'); -const PORT = 8080; - -/** - * Start server - */ -const startServer = function() { - return connect.server({ - root: '../public', - livereload: true, - port: PORT - }); -}; - -/** - * Stop server - */ -const stopServer = function() { - connect.serverClose(); -}; +const {METRICS} = require('../../lib/metrics/metrics'); /** * Run pwmetrics */ const runPwmetrics = function() { - const url = `http://localhost:${PORT}/index.html`; + const url = 'https://www.engadget.com/'; return new PWMetrics(url, { flags: { - expectations: true + runs: 3, + expectations: true, + chromeFlags: '--headless --enable-logging --no-sandbox', }, expectations: { - ttfmp: { + [METRICS.TTFMP]: { warn: '>=1000', error: '>=2000' }, - tti: { - warn: '>=2000', - error: '>=3000' + [METRICS.TTI]: { + warn: '>=5000', + error: '>=8000' }, - ttfcp: { + [METRICS.TTFCPUIDLE]: { warn: '>=1500', error: '>=2000' } @@ -57,8 +40,7 @@ const runPwmetrics = function() { * @param {Object} results - Pwmetrics results obtained through Lighthouse */ const handleOk = function(results) { - stopServer(); - console.log(results); + console.log(JSON.stringify(results, null, 2)); process.exit(0); }; @@ -66,13 +48,11 @@ const handleOk = function(results) { * Handle error */ const handleError = function(e) { - stopServer(); console.error(e); // eslint-disable-line no-console process.exit(1); }; gulp.task('pwmetrics', function() { - startServer(); return runPwmetrics() .then(handleOk) .catch(handleError); diff --git a/recipes/public/index.html b/recipes/public/index.html deleted file mode 100644 index 38db8d2..0000000 --- a/recipes/public/index.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - -

Slow page

- - - - - diff --git a/test-runner.sh b/test-runner.sh index cf7bedc..e4f8a61 100755 --- a/test-runner.sh +++ b/test-runner.sh @@ -4,7 +4,7 @@ if [[ $RUN_RECIPES = "1" ]]; then yarn run gulp-example; else npm run build && - if [[ $(node -v) =~ ^v([7-9]|\d\d+).* ]]; then + if [[ $(node -v) =~ ^v([8-9]|\d\d+).* ]]; then ./node_modules/.bin/mocha --require test/setup/common.js fi fi diff --git a/test/expectations.js b/test/expectations.js index 074bfd4..3a733de 100644 --- a/test/expectations.js +++ b/test/expectations.js @@ -2,10 +2,12 @@ // Licensed under the Apache License, Version 2.0. See LICENSE 'use strict'; +const {Logger} = require('../lib/utils/logger'); const expectations = require('../lib/expectations'); -const timings = require('./fixtures/metrics-results.json').timings; -const normalizedExpectations = require('./fixtures/mocks').normalizedExpectations; +const {timings} = require('./fixtures/metrics-results.json'); +const {normalizedExpectations} = require('./fixtures/mocks'); const expectationsData = require('./fixtures/run-expectations').expectations; +const logger = Logger.getInstance(); /* eslint-env mocha */ /* eslint-disable no-unused-expressions, no-console */ @@ -14,21 +16,21 @@ describe('Expectations', () => { let logSpy; beforeEach(() => { - logSpy = sinon.spy(console, 'log'); + logSpy = sinon.spy(logger, 'log'); }); afterEach(() => { - console.log.restore(); + logger.log.restore(); }); it('should normalize expectation', () => { - const result = expectations.normalizeMetrics(expectationsData); + const result = expectations.normalizeExpectationMetrics(expectationsData); expect(result).to.have.been.deep.equal(normalizedExpectations); }); it('should show expectation messages', () => { - const normExpectations = expectations.normalizeMetrics(expectationsData); + const normExpectations = expectations.normalizeExpectationMetrics(expectationsData); expectations.checkExpectations(timings, normExpectations); - expect(logSpy).to.have.been.calledTwice; + expect(logSpy).to.have.been.called; }); }); }); diff --git a/test/fixtures/events.json b/test/fixtures/events.json index 2076a0c..06ce8c6 100644 --- a/test/fixtures/events.json +++ b/test/fixtures/events.json @@ -1,549 +1,148 @@ { - "lighthouseVersion": "2.0.0-alpha.7", - "generatedTime": "2017-05-17T11:50:08.096Z", - "initialUrl": "http://example.com", - "url": "http://example.com/", + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3534.0 Safari/537.36", + "lighthouseVersion": "3.0.3", + "fetchTime": "2018-08-27T20:53:51.206Z", + "requestedUrl": "http://paulirish.com/", + "finalUrl": "https://www.paulirish.com/", + "runWarnings": [], "audits": { - "first-meaningful-paint": { - "score": 100, - "displayValue": "838.3ms", - "rawValue": 838.3, - "optimalValue": "< 1,600 ms", - "extendedInfo": { - "value": { - "timestamps": { - "navStart": 82750019541, - "fCP": 82750857804, - "fMP": 82750857814, - "onLoad": 82750693281, - "endOfTrace": 82757534802 - }, "timings": {"navStart": 0, "fCP": 838.263, "fMP": 838.273, "onLoad": 673.74, "endOfTrace": 7515.261} - }, "formatter": "null" - }, - "scoringMode": "numeric", - "name": "first-meaningful-paint", - "category": "Performance", - "description": "First meaningful paint", - "helpText": "First meaningful paint measures when the primary content of a page is visible. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint)." - }, - "speed-index-metric": { - "score": 100, - "displayValue": "854", - "rawValue": 854, - "optimalValue": "< 1,250", - "extendedInfo": { - "formatter": "speedline", - "value": { - "timings": { - "firstVisualChange": 854, - "visuallyReady": 854.0590000003576, - "visuallyComplete": 854, - "speedIndex": 854.0590000003576, - "perceptualSpeedIndex": 854.0590000003576 - }, - "timestamps": { - "firstVisualChange": 82750873541, - "visuallyReady": 82750873600, - "visuallyComplete": 82750873541, - "speedIndex": 82750873600, - "perceptualSpeedIndex": 82750873600 - }, - "frames": [{"timestamp": 82750019.541, "progress": 0}, {"timestamp": 82750873.6, "progress": 100}] - } - }, - "scoringMode": "numeric", - "name": "speed-index-metric", - "category": "Performance", - "description": "Perceptual Speed Index", - "helpText": "Speed Index shows how quickly the contents of a page are visibly populated. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/speed-index)." - }, - "screenshot-thumbnails": { - "score": 100, - "displayValue": "true", - "rawValue": true, - "scoringMode": "binary", - "informative": true, - "name": "screenshot-thumbnails", - "category": "Images", - "description": "Screenshot Thumbnails", - "helpText": "This is what the load of your site looked like.", - "details": { - "type": "filmstrip", - "scale": 854, - "items": [{ - "timing": 85, - "timestamp": 82750104941, - "data": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRQBAwQEBQQFCQUFCRQNCw0UFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFP/AABEIAGoAPAMBEQACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+gEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoLEQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4+Tl5ufo6ery8/T19vf4+fr/2gAMAwEAAhEDEQA/AP1ToAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoA//Z" - }, { - "timing": 171, - "timestamp": 82750190340.99998, - "data": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRQBAwQEBQQFCQUFCRQNCw0UFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFP/AABEIAGoAPAMBEQACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+gEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoLEQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4+Tl5ufo6ery8/T19vf4+fr/2gAMAwEAAhEDEQA/AP1ToAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoA//Z" - }, { - "timing": 256, - "timestamp": 82750275741, - "data": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRQBAwQEBQQFCQUFCRQNCw0UFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFP/AABEIAGoAPAMBEQACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+gEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoLEQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4+Tl5ufo6ery8/T19vf4+fr/2gAMAwEAAhEDEQA/AP1ToAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoA//Z" - }, { - "timing": 342, - "timestamp": 82750361140.99998, - "data": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRQBAwQEBQQFCQUFCRQNCw0UFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFP/AABEIAGoAPAMBEQACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+gEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoLEQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4+Tl5ufo6ery8/T19vf4+fr/2gAMAwEAAhEDEQA/AP1ToAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoA//Z" - }, { - "timing": 427, - "timestamp": 82750446541, - "data": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRQBAwQEBQQFCQUFCRQNCw0UFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFP/AABEIAGoAPAMBEQACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+gEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoLEQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4+Tl5ufo6ery8/T19vf4+fr/2gAMAwEAAhEDEQA/AP1ToAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoA//Z" - }, { - "timing": 512, - "timestamp": 82750531941, - "data": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRQBAwQEBQQFCQUFCRQNCw0UFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFP/AABEIAGoAPAMBEQACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+gEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoLEQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4+Tl5ufo6ery8/T19vf4+fr/2gAMAwEAAhEDEQA/AP1ToAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoA//Z" - }, { - "timing": 598, - "timestamp": 82750617340.99998, - "data": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRQBAwQEBQQFCQUFCRQNCw0UFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFP/AABEIAGoAPAMBEQACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+gEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoLEQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4+Tl5ufo6ery8/T19vf4+fr/2gAMAwEAAhEDEQA/AP1ToAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoA//Z" - }, { - "timing": 683, - "timestamp": 82750702741, - "data": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRQBAwQEBQQFCQUFCRQNCw0UFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFP/AABEIAGoAPAMBEQACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+gEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoLEQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4+Tl5ufo6ery8/T19vf4+fr/2gAMAwEAAhEDEQA/AP1ToAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoA//Z" - }, { - "timing": 769, - "timestamp": 82750788140.99998, - "data": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRQBAwQEBQQFCQUFCRQNCw0UFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFP/AABEIAGoAPAMBEQACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+gEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoLEQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4+Tl5ufo6ery8/T19vf4+fr/2gAMAwEAAhEDEQA/AP1ToAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoA//Z" - }, { - "timing": 854, - "timestamp": 82750873541, - "data": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRQBAwQEBQQFCQUFCRQNCw0UFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFP/AABEIAGoAPAMBEQACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+gEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoLEQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4+Tl5ufo6ery8/T19vf4+fr/2gAMAwEAAhEDEQA/AP0zvfiH4V03xjYeEbzxNo9r4rv4TcWehT38SX1zEA5MkcBbe6/upOQCP3bf3TQBvk460AVLLV7DUZ76C0vbe6msJhb3ccMqu1vKY0lCSAH5GMcsb4ODtkQ9GBIBV8L+LdD8caHa614c1rT9f0a63fZ9R0u6jubebaxVtkiEq2GVgcHggjtQBpmVAQN65OcDPWgBwOaAFoAKAPHvir+z/wDBr43+JtTsPG/h/R/EPiW80i1tp4pblk1CLT4rmSSExlHWWGMzPJuePb5mNrlgoAAMv4lfsU/CD4uQeMJdf8NG51bxVHafbdb+1yveRyWsJhtZoHkZhE6IcfKuJP8AloJASCAdT4B/Z4+HXw31e+1fw54fitLzUdWm1+SQ3M08a380bxy3EKO7JAzxyuh8oKCpC4wqgAGXrvwF+DPxB0vxR4l1XQNF12x8X6THHquuTXBlW+sAxuI3Fxv4RdyusiMNoig2kCGLYAafiX9m34ceMdB8Y6Lq/hxL3TfF1za3etw/ap0+1SWwhFv8yuGRUFvDhEKr8vTk5APRLvUbTT7Wa5urmG2toFLyzTSBEjUdSzHgD60ANudWsbOe2gnvIIZ7mb7NBFJKqtLLsaTy1BOWbYjPgc7VJ6AmgC3QB438T/D3ie68aapqnhlb7Tb/AP4RqW0t9V07SdKneSUrclImkuZlldlkMLxxkRwBt3mO4dvKBnLar8OrzUPiLceJL7wpf+J7jS4muNOkuNI8Oqs1yl+bm2FvcOxuI3jjmmiBfaNjSSBhKwZpgtubcTOgPw+8Y2mixpYavPpFnpukmH+zNE8PaZDcXVzEtwkP2RpJXhhi3GGWOGUHaUgDSgecpoCr4V+EFzofg+1s4NPfSb6CZJ7p9P8AD+i239pWEUtwE0maJS6bPIlaJWRkx5gbeuZVItdtAJ9N8EeNtYvdfTUNQubG+vbO5trbXbvQ9LkNuyL5Fky7JGZxG63N6sckZX/iYhCylGSgDN8c+FvGh8NaZoOqadqvjoLG9vJJ4f0bRbe1Z1zJDM8WoTuEWN2tjGqBiJLMswZWUUmlrcak47G7F4E8V+I/Gmk6jceKZLzwtZ6pcXEun3vhu1SUyI15CqI8yK8UQRoo/OVZHmVVaNo43Yu09BavU9P8I6ReeH/CujaXqGo/2xf2VnDbXGo/ZktvtUiIFaXyowEj3EFtijaucDgUAc94v0ue78V6ZcQeB9M19orSX/icX1xHFJasJYJI4UzG7kNJHHKSMBTbq3LBAdYKDWsrP06EtvojDtfCui+HtOiOnfB22h/saV7XT7PTrfTo8W4ukkV7fMiKgLwW9xsYphkQ/fQUKMOsul9n9w7vsdppuvavday9tdeHLmysWiikivjcwuAzKxeORA2VZCoGV3qd6kN97anGKWkr/f8A5Ar9jfrMYUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQB//Z" - }] - } - }, - "estimated-input-latency": { - "score": 100, - "displayValue": "16ms", - "rawValue": 16, - "optimalValue": "< 50 ms", - "extendedInfo": { - "value": [{"percentile": 0.5, "time": 16}, {"percentile": 0.75, "time": 16}, { - "percentile": 0.9, - "time": 16 - }, {"percentile": 0.99, "time": 16}, {"percentile": 1, "time": 23.484999999996944}], "formatter": "null" - }, - "scoringMode": "numeric", - "name": "estimated-input-latency", - "category": "Performance", - "description": "Estimated Input Latency", - "helpText": "The score above is an estimate of how long your app takes to respond to user input, in milliseconds. There is a 90% probability that a user encounters this amount of latency, or less. 10% of the time a user can expect additional latency. If your score is higher than Lighthouse's target score, users may perceive your app as laggy. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency)." - }, - "first-interactive": { - "score": 100, - "displayValue": "840ms", - "rawValue": 839.9300000063181, - "extendedInfo": {"value": {"timeInMs": 839.9300000063181, "timestamp": 82750859471}, "formatter": "null"}, - "scoringMode": "numeric", - "name": "first-interactive", - "category": "Performance", - "description": "First Interactive (beta)", - "helpText": "The first point at which necessary scripts of the page have loaded and the CPU is idle enough to handle most user input." - }, - "consistently-interactive": { - "score": 100, - "displayValue": "840ms", - "rawValue": 839.93, - "extendedInfo": { - "value": { - "cpuQuietPeriod": {"start": 82750859.471, "end": 82757534.802}, - "networkQuietPeriod": {"start": 0, "end": 82757534.802}, - "cpuQuietPeriods": [{"start": 82750859.471, "end": 82757534.802}], - "networkQuietPeriods": [{"start": 0, "end": 82757534.802}], - "timestamp": 82750859471, - "timeInMs": 839.93 - }, "formatter": "null" - }, - "scoringMode": "numeric", - "name": "consistently-interactive", - "category": "Performance", - "description": "Consistently Interactive (beta)", - "helpText": "The point at which most network resources have finished loading and the CPU is idle for a prolonged period." - }, - "user-timings": { - "score": true, - "displayValue": "0", - "rawValue": true, - "extendedInfo": {"formatter": "user-timings", "value": []}, - "scoringMode": "binary", - "informative": true, - "name": "user-timings", - "category": "Performance", - "description": "User Timing marks and measures", - "helpText": "Consider instrumenting your app with the User Timing API to create custom, real-world measurements of key user experiences. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/user-timing).", - "details": { - "type": "table", - "header": "View Details", - "itemHeaders": [{"type": "text", "itemType": "text", "text": "Name"}, { - "type": "text", - "itemType": "text", - "text": "Type" - }, {"type": "text", "itemType": "text", "text": "Time"}], - "items": [] - } - }, - "critical-request-chains": { - "score": true, - "displayValue": "0", - "rawValue": true, - "optimalValue": 0, - "extendedInfo": { - "formatter": "critical-request-chains", - "value": { - "chains": { - "21506.1": { - "request": { - "url": "http://example.com/", - "startTime": 82750.024719, - "endTime": 82750.65861, - "responseReceivedTime": 82750.657165, - "transferSize": 957 - }, "children": {} - }, - "21506.2": { - "request": { - "url": "http://example.com/favicon.ico", - "startTime": 82750.865118, - "endTime": 82751.437639, - "responseReceivedTime": 82751.436082, - "transferSize": 943 - }, "children": {} - } - }, "longestChain": {"duration": 1412.9200000024866, "length": 1, "transferSize": 943} - } - }, - "scoringMode": "binary", - "informative": true, - "name": "critical-request-chains", - "category": "Performance", - "description": "Critical Request Chains", - "helpText": "The Critical Request Chains below show you what resources are required for first render of this page. Improve page load by reducing the length of chains, reducing the download size of resources, or deferring the download of unnecessary resources. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/critical-request-chains).", + "metrics": { + "id": "metrics", + "title": "Metrics", + "description": "Collects all available metrics.", + "score": null, + "scoreDisplayMode": "informative", + "rawValue": 4179.649, "details": { - "type": "criticalrequestchain", - "header": {"type": "text", "text": "View critical network waterfall:"}, - "chains": { - "21506.1": { - "request": { - "url": "http://example.com/", - "startTime": 82750.024719, - "endTime": 82750.65861, - "responseReceivedTime": 82750.657165, - "transferSize": 957 - }, "children": {} - }, - "21506.2": { - "request": { - "url": "http://example.com/favicon.ico", - "startTime": 82750.865118, - "endTime": 82751.437639, - "responseReceivedTime": 82751.436082, - "transferSize": 943 - }, "children": {} + "items": [ + { + "firstContentfulPaint": 4180, + "firstMeaningfulPaint": 4180, + "firstCPUIdle": 4180, + "interactive": 4180, + "speedIndex": 4329, + "estimatedInputLatency": 13, + "observedNavigationStart": 0, + "observedNavigationStartTs": 49414590783, + "observedFirstPaint": 1005, + "observedFirstPaintTs": 49415595415, + "observedFirstContentfulPaint": 1005, + "observedFirstContentfulPaintTs": 49415595415, + "observedFirstMeaningfulPaint": 1005, + "observedFirstMeaningfulPaintTs": 49415595415, + "observedTraceEnd": 4796, + "observedTraceEndTs": 49419386628, + "observedLoad": 3731, + "observedLoadTs": 49418322041, + "observedDomContentLoaded": 2861, + "observedDomContentLoadedTs": 49417451887, + "observedFirstVisualChange": 958, + "observedFirstVisualChangeTs": 49415548783, + "observedLastVisualChange": 3475, + "observedLastVisualChangeTs": 49418065783, + "observedSpeedIndex": 1330, + "observedSpeedIndexTs": 49415921212 } - }, - "longestChain": {"duration": 1412.9200000024866, "length": 1, "transferSize": 943} - } - }, - "total-byte-weight": { - "score": 100, - "displayValue": "Total size was 2 KB", - "rawValue": 1900, - "optimalValue": "< 1,600 KB", - "extendedInfo": { - "formatter": "table", - "value": { - "results": [{ - "url": "/", - "totalBytes": 957, - "totalKb": "1 KB", - "totalMs": "0ms" - }, {"url": "/favicon.ico", "totalBytes": 943, "totalKb": "1 KB", "totalMs": "0ms"}], - "tableHeadings": {"url": "URL", "totalKb": "Total Size", "totalMs": "Transfer Time"} - } - }, - "scoringMode": "numeric", - "name": "total-byte-weight", - "category": "Network", - "description": "Avoids enormous network payloads", - "helpText": "Network transfer size [costs users real dollars](https://whatdoesmysitecost.com/) and is [highly correlated](http://httparchive.org/interesting.php#onLoad) with long load times. Try to find ways to reduce the size of required files.", - "details": { - "type": "table", - "header": "View Details", - "itemHeaders": [{"type": "text", "itemType": "url", "text": "URL"}, { - "type": "text", - "itemType": "text", - "text": "Total Size" - }, {"type": "text", "itemType": "text", "text": "Transfer Time"}], - "items": [[{"type": "url", "text": "/"}, {"type": "text", "text": "1 KB"}, { - "type": "text", - "text": "0ms" - }], [{"type": "url", "text": "/favicon.ico"}, {"type": "text", "text": "1 KB"}, {"type": "text", "text": "0ms"}]] - } - }, - "offscreen-images": { - "score": 100, - "displayValue": "", - "rawValue": 0, - "extendedInfo": { - "formatter": "table", - "value": { - "wastedMs": 0, - "wastedKb": 0, - "results": [], - "tableHeadings": {"preview": "", "url": "URL", "totalKb": "Original", "potentialSavings": "Potential Savings"} - } - }, - "scoringMode": "binary", - "informative": true, - "name": "offscreen-images", - "category": "Images", - "description": "Offscreen images", - "helpText": "Images that are not above the fold should be lazily loaded after the page is interactive. Consider using the [IntersectionObserver](https://developers.google.com/web/updates/2016/04/intersectionobserver) API.", - "details": { - "type": "table", - "header": "View Details", - "itemHeaders": [{"type": "text", "itemType": "thumbnail", "text": ""}, { - "type": "text", - "itemType": "url", - "text": "URL" - }, {"type": "text", "itemType": "text", "text": "Original"}, { - "type": "text", - "itemType": "text", - "text": "Potential Savings" - }], - "items": [] - } - }, - "uses-webp-images": { - "score": 100, - "displayValue": "", - "rawValue": 0, - "extendedInfo": { - "formatter": "table", - "value": { - "wastedMs": 0, - "wastedKb": 0, - "results": [], - "tableHeadings": {"preview": "", "url": "URL", "totalKb": "Original", "potentialSavings": "Potential Savings"} - } - }, - "scoringMode": "binary", - "informative": true, - "name": "uses-webp-images", - "category": "Images", - "description": "Serve images as WebP", - "helpText": "[WebP](https://developers.google.com/speed/webp/) images take less time to download and save cellular data. [Learn more about image optimization](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/image-optimization).", - "details": { - "type": "table", - "header": "View Details", - "itemHeaders": [{"type": "text", "itemType": "thumbnail", "text": ""}, { - "type": "text", - "itemType": "url", - "text": "URL" - }, {"type": "text", "itemType": "text", "text": "Original"}, { - "type": "text", - "itemType": "text", - "text": "Potential Savings" - }], - "items": [] + ] } - }, - "uses-optimized-images": { - "score": 100, - "displayValue": "", - "rawValue": 0, - "extendedInfo": { - "formatter": "table", - "value": { - "wastedMs": 0, - "wastedKb": 0, - "results": [], - "tableHeadings": {"preview": "", "url": "URL", "totalKb": "Original", "potentialSavings": "Potential Savings"} - } - }, - "scoringMode": "binary", - "informative": true, - "name": "uses-optimized-images", - "category": "Images", - "description": "Optimize images", - "helpText": "Optimized images take less time to download and save cellular data. The identified images could have smaller file sizes when compressed as JPEG (q=85). [Learn more about image optimization](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/image-optimization).", - "details": { - "type": "table", - "header": "View Details", - "itemHeaders": [{"type": "text", "itemType": "thumbnail", "text": ""}, { - "type": "text", - "itemType": "url", - "text": "URL" - }, {"type": "text", "itemType": "text", "text": "Original"}, { - "type": "text", - "itemType": "text", - "text": "Potential Savings" - }], - "items": [] - } - }, - "uses-request-compression": { - "score": 100, - "displayValue": "", - "rawValue": 0, - "extendedInfo": { - "formatter": "table", - "value": { - "wastedMs": 0, - "wastedKb": 0, - "results": [], - "tableHeadings": {"url": "Uncompressed resource URL", "totalKb": "Original", "potentialSavings": "GZIP Savings"} - } - }, - "scoringMode": "binary", - "informative": true, - "name": "uses-request-compression", - "category": "Performance", - "description": "Enable text compression", - "helpText": "Text-based responses should be served with compression (gzip, deflate or brotli) to minimize total network bytes. [Learn more](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/optimize-encoding-and-transfer).", - "details": { - "type": "table", - "header": "View Details", - "itemHeaders": [{"type": "text", "itemType": "url", "text": "Uncompressed resource URL"}, { - "type": "text", - "itemType": "text", - "text": "Original" - }, {"type": "text", "itemType": "text", "text": "GZIP Savings"}], - "items": [] - } - }, - "uses-responsive-images": { - "score": 100, - "displayValue": "", - "rawValue": 0, - "extendedInfo": { - "formatter": "table", - "value": { - "wastedMs": 0, - "wastedKb": 0, - "results": [], - "tableHeadings": {"preview": "", "url": "URL", "totalKb": "Original", "potentialSavings": "Potential Savings"} - } - }, - "scoringMode": "binary", - "informative": true, - "name": "uses-responsive-images", - "category": "Images", - "description": "Properly size images", - "helpText": "Serve images that are appropriately-sized to save cellular data and improve load time. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/oversized-images).", - "details": { - "type": "table", - "header": "View Details", - "itemHeaders": [{"type": "text", "itemType": "thumbnail", "text": ""}, { - "type": "text", - "itemType": "url", - "text": "URL" - }, {"type": "text", "itemType": "text", "text": "Original"}, { - "type": "text", - "itemType": "text", - "text": "Potential Savings" - }], - "items": [] - } - }, - "dom-size": { - "score": 100, - "displayValue": "13 nodes", - "rawValue": 13, - "optimalValue": "< 1,500 nodes", - "extendedInfo": { - "formatter": "cards", - "value": [{"title": "Total DOM Nodes", "value": "13", "target": "< 1,500 nodes"}, { - "title": "DOM Depth", - "value": "5", - "snippet": "html >\n body >\n div >\n p >\n a", - "target": "< 32" - }, { - "title": "Maximum Children", - "value": "5", - "snippet": "Element with most children:\nhead", - "target": "< 60 nodes" - }] - }, - "scoringMode": "numeric", - "name": "dom-size", - "category": "Performance", - "description": "Avoids an excessive DOM size", - "helpText": "Browser engineers recommend pages contain fewer than ~1,500 DOM nodes. The sweet spot is a tree depth < 32 elements and fewer than 60 children/parent element. A large DOM can increase memory, cause longer [style calculations](https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations), and produce costly [layout reflows](https://developers.google.com/speed/articles/reflow). [Learn more](https://developers.google.com/web/fundamentals/performance/rendering/).", - "details": { - "type": "cards", - "header": {"type": "text", "text": "View details"}, - "items": [{"title": "Total DOM Nodes", "value": "13", "target": "< 1,500 nodes"}, { - "title": "DOM Depth", - "value": "5", - "snippet": "html >\n body >\n div >\n p >\n a", - "target": "< 32" - }, { - "title": "Maximum Children", - "value": "5", - "snippet": "Element with most children:\nhead", - "target": "< 60 nodes" - }] - } - }, - "link-blocking-first-paint": { - "score": 100, - "displayValue": "", - "rawValue": 0, - "extendedInfo": { - "formatter": "table", - "value": { - "wastedMs": 0, - "results": [], - "tableHeadings": {"url": "URL", "totalKb": "Size (KB)", "totalMs": "Delayed Paint By (ms)"} - } - }, - "scoringMode": "binary", - "informative": true, - "name": "link-blocking-first-paint", - "category": "Performance", - "description": "Reduce render-blocking stylesheets", - "helpText": "Link elements are blocking the first paint of your page. Consider inlining critical links and deferring non-critical ones. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources).", - "details": { - "type": "table", - "header": "View Details", - "itemHeaders": [{"type": "text", "itemType": "url", "text": "URL"}, { - "type": "text", - "itemType": "text", - "text": "Size (KB)" - }, {"type": "text", "itemType": "text", "text": "Delayed Paint By (ms)"}], - "items": [] - } - }, - "script-blocking-first-paint": { - "score": 100, - "displayValue": "", - "rawValue": 0, - "extendedInfo": { - "formatter": "table", - "value": { - "wastedMs": 0, - "results": [], - "tableHeadings": {"url": "URL", "totalKb": "Size (KB)", "totalMs": "Delayed Paint By (ms)"} + } + }, + "configSettings": { + "output": "json", + "maxWaitForLoad": 45000, + "throttlingMethod": "simulate", + "throttling": { + "rttMs": 150, + "throughputKbps": 1638.4, + "requestLatencyMs": 562.5, + "downloadThroughputKbps": 1474.5600000000002, + "uploadThroughputKbps": 675, + "cpuSlowdownMultiplier": 4 + }, + "auditMode": false, + "gatherMode": false, + "disableStorageReset": false, + "disableDeviceEmulation": false, + "blockedUrlPatterns": null, + "additionalTraceCategories": null, + "extraHeaders": null, + "onlyAudits": [ + "metrics" + ], + "onlyCategories": null, + "skipAudits": null + }, + "categories": { + "performance": { + "title": "Performance", + "auditRefs": [ + { + "id": "metrics", + "weight": 0 } - }, - "scoringMode": "binary", - "informative": true, - "name": "script-blocking-first-paint", - "category": "Performance", - "description": "Reduce render-blocking scripts", - "helpText": "Script elements are blocking the first paint of your page. Consider inlining critical scripts and deferring non-critical ones. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources).", - "details": { - "type": "table", - "header": "View Details", - "itemHeaders": [{"type": "text", "itemType": "url", "text": "URL"}, { - "type": "text", - "itemType": "text", - "text": "Size (KB)" - }, {"type": "text", "itemType": "text", "text": "Delayed Paint By (ms)"}], - "items": [] - } + ], + "id": "performance", + "score": 0 + } + }, + "categoryGroups": { + "metrics": { + "title": "Metrics" + }, + "load-opportunities": { + "title": "Opportunities", + "description": "These are opportunities to speed up your application by optimizing the following resources." + }, + "diagnostics": { + "title": "Diagnostics", + "description": "More information about the performance of your application." + }, + "a11y-color-contrast": { + "title": "Color Contrast Is Satisfactory", + "description": "These are opportunities to improve the legibility of your content." + }, + "a11y-describe-contents": { + "title": "Elements Describe Contents Well", + "description": "These are opportunities to make your content easier to understand for a user of assistive technology, like a screen reader." + }, + "a11y-well-structured": { + "title": "Elements Are Well Structured", + "description": "These are opportunities to make sure your HTML is appropriately structured." + }, + "a11y-aria": { + "title": "ARIA Attributes Follow Best Practices", + "description": "These are opportunities to improve the usage of ARIA in your application which may enhance the experience for users of assistive technology, like a screen reader." + }, + "a11y-correct-attributes": { + "title": "Elements Use Attributes Correctly", + "description": "These are opportunities to improve the configuration of your HTML elements." + }, + "a11y-element-names": { + "title": "Elements Have Discernible Names", + "description": "These are opportunities to improve the semantics of the controls in your application. This may enhance the experience for users of assistive technology, like a screen reader." + }, + "a11y-language": { + "title": "Page Specifies Valid Language", + "description": "These are opportunities to improve the interpretation of your content by users in different locales." + }, + "a11y-meta": { + "title": "Meta Tags Used Properly", + "description": "These are opportunities to improve the user experience of your site." + }, + "seo-mobile": { + "title": "Mobile Friendly", + "description": "Make sure your pages are mobile friendly so users don’t have to pinch or zoom in order to read the content pages. [Learn more](https://developers.google.com/search/mobile-sites/)." + }, + "seo-content": { + "title": "Content Best Practices", + "description": "Format your HTML in a way that enables crawlers to better understand your app’s content." + }, + "seo-crawl": { + "title": "Crawling and Indexing", + "description": "To appear in search results, crawlers need access to your app." } + }, + "timing": { + "total": 6607 } } diff --git a/test/fixtures/metrics-results.json b/test/fixtures/metrics-results.json index c6a78c7..9d3c495 100644 --- a/test/fixtures/metrics-results.json +++ b/test/fixtures/metrics-results.json @@ -1,56 +1,38 @@ { - "timings": [{ - "title": "First Contentful Paint", - "id": "ttfcp", - "timestamp": 82750857804, - "timing": 838.263, - "color": "green" - }, { - "title": "First Meaningful Paint", - "id": "ttfmp", - "timestamp": 82750857814, - "timing": 838.273, - "color": "green" - }, { - "title": "Perceptual Speed Index", - "id": "psi", - "timestamp": 82750873600, - "timing": 854.059, - "color": "blue" - }, { - "title": "First Visual Change", - "id": "fv", - "timestamp": 82750873541, - "timing": 854, - "color": "blue" - }, { - "title": "Visually Complete 85%", - "id": "vc85", - "timestamp": 82750873600, - "timing": 854.059, - "color": "blue" - }, { - "title": "Visually Complete 100%", - "id": "vc100", - "timestamp": 82750873541, - "timing": 854, - "color": "blue" - }, { - "title": "First Interactive (vBeta)", - "id": "ttfi", - "timestamp": 82750859471, - "timing": 839.93, - "color": "yellow" - }, { - "title": "Time to Consistently Interactive (vBeta)", - "id": "ttci", - "timestamp": 82750859471, - "timing": 839.93, - "color": "yellow" - }], - "timestamps": [{"title": "Navigation Start", "id": "navstart", "timestamp": 82750019541}], - "generatedTime": "2017-05-17T11:50:08.096Z", - "lighthouseVersion": "2.0.0-alpha.7", - "initialUrl": "http://example.com", - "url": "http://example.com/" + "timings": [ + { + "title": "First Contentful Paint", + "id": "firstContentfulPaint", + "timing": 4180, + "color": "green" + }, + { + "title": "First Meaningful Paint", + "id": "firstMeaningfulPaint", + "timing": 4180, + "color": "green" + }, + { + "title": "First CPU Idle", + "id": "firstCPUIdle", + "timing": 4180, + "color": "yellow" + }, + { + "title": "Time to Interactive", + "id": "interactive", + "timing": 4180, + "color": "yellow" + }, + { + "title": "Speed Index", + "id": "speedIndex", + "timing": 4329, + "color": "blue" + } + ], + "generatedTime": "2018-08-27T20:53:51.206Z", + "lighthouseVersion": "3.0.3", + "requestedUrl": "http://paulirish.com/", + "finalUrl": "https://www.paulirish.com/" } diff --git a/test/fixtures/mocks.js b/test/fixtures/mocks.js index 31e7fdf..5f0f1ec 100644 --- a/test/fixtures/mocks.js +++ b/test/fixtures/mocks.js @@ -1,7 +1,7 @@ 'use strict'; const lighthouseVersion = require('lighthouse/package.json').version; - +const {METRICS} = require('../../lib/metrics/metrics'); const url = 'http://example.com/'; exports.metricsResult = { @@ -17,170 +17,116 @@ exports.failedMetricResult = new Error('Failed run'); exports.metricsResults = [ { - 'timings': [{ - 'title': 'First Contentful Paint', - 'id': 'ttfcp', - 'timestamp': 38340021362, - 'timing': 1006.643, - 'color': 'green' - }, { - 'title': 'First Meaningful Paint', - 'id': 'ttfmp', - 'timestamp': 38340021379, - 'timing': 1006.66, - 'color': 'green' - }, { - 'title': 'Perceptual Speed Index', - 'id': 'psi', - 'timestamp': 38340062085, - 'timing': 1047.366, - 'color': 'blue' - }, { - 'title': 'First Visual Change', - 'id': 'fv', - 'timestamp': 38340061719, - 'timing': 1047, - 'color': 'blue' - }, { - 'title': 'Visually Complete 85%', - 'id': 'vc85', - 'timestamp': 38340062085, - 'timing': 1047.366, - 'color': 'blue' - }, { - 'title': 'Visually Complete 100%', - 'id': 'vc100', - 'timestamp': 38340061719, - 'timing': 1047, - 'color': 'blue' - }, { - 'title': 'First Interactive (vBeta)', - 'id': 'ttfi', - 'timestamp': 38340021379, - 'timing': 1006.66, - 'color': 'yellow' - }, { - 'title': 'Time to Consistently Interactive (vBeta)', - 'id': 'ttci', - 'timestamp': 38340021379, - 'timing': 1006.66, - 'color': 'yellow' - }], - 'timestamps': [{'title': 'Navigation Start', 'id': 'navstart', 'timestamp': 38339014719}], - 'generatedTime': '2017-06-19T20:39:08.057Z', - 'lighthouseVersion': '2.1.0', - 'initialUrl': 'http://example.com', - 'url': 'http://example.com/' + 'timings': [ + { + 'title': 'First Contentful Paint', + 'id': 'firstContentfulPaint', + 'timing': 1059.9194, + 'color': 'green' + }, + { + 'title': 'First Meaningful Paint', + 'id': 'firstMeaningfulPaint', + 'timing': 1575.1898999999999, + 'color': 'green' + }, + { + 'title': 'Speed Index', + 'id': 'speedIndex', + 'timing': 4329, + 'color': 'blue' + }, + { + 'title': 'First CPU Idle', + 'id': 'firstCPUIdle', + 'timing': 4180, + 'color': 'yellow' + }, + { + 'title': 'Time to Interactive', + 'id': 'interactive', + 'timing': 4180, + 'color': 'yellow' + } + ], + 'generatedTime': '2018-06-08T19:36:07.375Z', + 'lighthouseVersion': '3.0.0-beta.0', + 'requestedUrl': 'https://www.paulirish.com/', + 'finalUrl': 'https://www.paulirish.com/' }, { - 'timings': [{ - 'title': 'First Contentful Paint', - 'id': 'ttfcp', - 'timestamp': 38351240693, - 'timing': 894.788, - 'color': 'green' - }, { - 'title': 'First Meaningful Paint', - 'id': 'ttfmp', - 'timestamp': 38351240870, - 'timing': 894.965, - 'color': 'green' - }, { - 'title': 'Perceptual Speed Index', - 'id': 'psi', - 'timestamp': 38351260183, - 'timing': 914.278, - 'color': 'blue' - }, { - 'title': 'First Visual Change', - 'id': 'fv', - 'timestamp': 38351259905, - 'timing': 914, - 'color': 'blue' - }, { - 'title': 'Visually Complete 85%', - 'id': 'vc85', - 'timestamp': 38351260183, - 'timing': 914.278, - 'color': 'blue' - }, { - 'title': 'Visually Complete 100%', - 'id': 'vc100', - 'timestamp': 38351259905, - 'timing': 914, - 'color': 'blue' - }, { - 'title': 'First Interactive (vBeta)', - 'id': 'ttfi', - 'timestamp': 38351240870, - 'timing': 894.965, - 'color': 'yellow' - }, { - 'title': 'Time to Consistently Interactive (vBeta)', - 'id': 'ttci', - 'timestamp': 38351240870, - 'timing': 894.965, - 'color': 'yellow' - }], - 'timestamps': [{'title': 'Navigation Start', 'id': 'navstart', 'timestamp': 38350345905}], - 'generatedTime': '2017-06-19T20:39:19.070Z', - 'lighthouseVersion': '2.1.0', - 'initialUrl': 'http://example.com', - 'url': 'http://example.com/' + 'timings': [ + { + 'title': 'First Contentful Paint', + 'id': 'firstContentfulPaint', + 'timing': 1059.9194, + 'color': 'green' + }, + { + 'title': 'First Meaningful Paint', + 'id': 'firstMeaningfulPaint', + 'timing': 1575.1898999999999, + 'color': 'green' + }, + { + 'title': 'Speed Index', + 'id': 'speedIndex', + 'timing': 4329, + 'color': 'blue' + }, + { + 'title': 'First CPU Idle', + 'id': 'firstCPUIdle', + 'timing': 4180, + 'color': 'yellow' + }, + { + 'title': 'Time to Interactive', + 'id': 'interactive', + 'timing': 4180, + 'color': 'yellow' + } + ], + 'generatedTime': '2018-06-08T19:36:07.375Z', + 'lighthouseVersion': '3.0.0-beta.0', + 'requestedUrl': 'https://www.paulirish.com/', + 'finalUrl': 'https://www.paulirish.com/' }, { - 'timings': [{ - 'title': 'First Contentful Paint', - 'id': 'ttfcp', - 'timestamp': 38362423762, - 'timing': 903.559, - 'color': 'green' - }, { - 'title': 'First Meaningful Paint', - 'id': 'ttfmp', - 'timestamp': 38362423774, - 'timing': 903.571, - 'color': 'green' - }, { - 'title': 'Perceptual Speed Index', - 'id': 'psi', - 'timestamp': 38362441101, - 'timing': 920.898, - 'color': 'blue' - }, { - 'title': 'First Visual Change', - 'id': 'fv', - 'timestamp': 38362440203, - 'timing': 920, - 'color': 'blue' - }, { - 'title': 'Visually Complete 85%', - 'id': 'vc85', - 'timestamp': 38362441101, - 'timing': 920.898, - 'color': 'blue' - }, { - 'title': 'Visually Complete 100%', - 'id': 'vc100', - 'timestamp': 38362440203, - 'timing': 920, - 'color': 'blue' - }, { - 'title': 'First Interactive (vBeta)', - 'id': 'ttfi', - 'timestamp': 38362423774, - 'timing': 903.571, - 'color': 'yellow' - }, { - 'title': 'Time to Consistently Interactive (vBeta)', - 'id': 'ttci', - 'timestamp': 38362423774, - 'timing': 903.571, - 'color': 'yellow' - }], - 'timestamps': [{'title': 'Navigation Start', 'id': 'navstart', 'timestamp': 38361520203}], - 'generatedTime': '2017-06-19T20:39:30.261Z', - 'lighthouseVersion': '2.1.0', - 'initialUrl': 'http://example.com', - 'url': 'http://example.com/' + 'timings': [ + { + 'title': 'First Contentful Paint', + 'id': 'firstContentfulPaint', + 'timing': 1059.9194, + 'color': 'green' + }, + { + 'title': 'First Meaningful Paint', + 'id': 'firstMeaningfulPaint', + 'timing': 1575.1898999999999, + 'color': 'green' + }, + { + 'title': 'Speed Index', + 'id': 'speedIndex', + 'timing': 4329, + 'color': 'blue' + }, + { + 'title': 'First CPU Idle', + 'id': 'firstCPUIdle', + 'timing': 4180, + 'color': 'yellow' + }, + { + 'title': 'Time to Interactive', + 'id': 'interactive', + 'timing': 4180, + 'color': 'yellow' + } + ], + 'generatedTime': '2018-06-08T19:36:07.375Z', + 'lighthouseVersion': '3.0.0-beta.0', + 'requestedUrl': 'https://www.paulirish.com/', + 'finalUrl': 'https://www.paulirish.com/' } ]; @@ -197,24 +143,20 @@ module.exports.googleOauthToken = { }; module.exports.normalizedExpectations = { - ttfmp: { + [METRICS.TTFMP]: { warn: 500, error: 1000 }, - tti: { + [METRICS.TTI]: { warn: 3000, error: 5000, }, - ttfcp: { + [METRICS.TTFCP]: { warn: 500, error: 1000, }, - psi: { + [METRICS.SI]: { warn: 3000, error: 6000, }, - vc85: { - warn: 3000, - error: 5000, - } }; diff --git a/test/fixtures/run-expectations.js b/test/fixtures/run-expectations.js index 1b0f72e..9b5831f 100644 --- a/test/fixtures/run-expectations.js +++ b/test/fixtures/run-expectations.js @@ -1,4 +1,5 @@ 'use strict'; +const {METRICS} = require('../../lib/metrics/metrics'); module.exports = { url: 'https://example.com/', @@ -7,25 +8,21 @@ module.exports = { runs: 2, }, expectations: { - ttfmp: { + [METRICS.TTFMP]: { warn: '>=500', error: '>=1000' }, - tti: { + [METRICS.TTI]: { warn: '>=3000', error: '>=5000', }, - ttfcp: { + [METRICS.TTFCP]: { warn: '>=500', error: '>=1000', }, - psi: { + [METRICS.SI]: { warn: '>=3000', error: '>=6000', }, - vc85: { - warn: '>=3000', - error: '>=5000', - } }, }; diff --git a/test/fixtures/run-options.js b/test/fixtures/run-options.js index 873ee9b..811c142 100644 --- a/test/fixtures/run-options.js +++ b/test/fixtures/run-options.js @@ -1,5 +1,5 @@ 'use strict'; - +const {METRICS} = require('../../lib/metrics/metrics'); const url = 'http://example.com/'; exports.publicVariables = { @@ -36,6 +36,9 @@ exports.startWithMoreThenOneRun = { exports.publicVariablesWithExpectations = { url: url, + flags: { + expectations: true + }, opts: { expectations: {} } @@ -49,7 +52,7 @@ exports.startWithOneRunWithExpectations = { expectations: true }, expectations: { - ttfcp: { + [METRICS.TTFCP]: { warn: '>=1500', error: '>=3000', } diff --git a/test/index.js b/test/index.js index 92f6fcf..819ece8 100644 --- a/test/index.js +++ b/test/index.js @@ -24,122 +24,6 @@ describe('PWMetrics', () => { const pwMetrics = new PWMetrics(runOptions.publicVariables.url, opts); expect(pwMetrics.runs).to.be.equal(2); }); - - it('should parse chromeFlags', () => { - const opts = Object.assign({}, runOptions.startWithChromeFlags.opts); - const pwMetrics = new PWMetrics(runOptions.startWithChromeFlags.url, opts); - expect(pwMetrics.parsedChromeFlags).to.be.deep.equal(['--no-sandbox', '--disable-setuid-sandbox']); - }); - - describe('expectations', () => { - it('should set expectations', () => { - const pwMetrics = new PWMetrics( - runOptions.publicVariables.url, - runOptions.publicVariablesWithExpectations.opts - ); - expect(pwMetrics.expectations).to.be.equal(runOptions.publicVariablesWithExpectations.opts.expectations); - }); - }); - }); - - describe('start method', () => { - let pwMetrics; - let runStub; - let findMedianRunStub; - let displayOutputStub; - let runResult; - - describe('with one run', () => { - beforeEach(() => { - pwMetrics = new PWMetrics(runOptions.startWithOneRun.url, runOptions.startWithOneRun.opts); - runStub = sinon.stub(pwMetrics, 'run', () => Promise.resolve({timings: []})); - findMedianRunStub = sinon.stub(pwMetrics, 'findMedianRun'); - displayOutputStub = sinon.stub(pwMetrics, 'displayOutput'); - }); - - it('should calculate results', () => { - const expected = {runs: [{timings: []}]}; - - return pwMetrics.start().then(data => { - expect(data).to.be.deep.equal(expected); - }); - }); - - it('should call "run" method', () => { - return pwMetrics.start().then(() => { - expect(runStub).to.have.been.calledOnce; - }); - }); - - it('should not call methods for calculating median results', () => { - return pwMetrics.start().then(_ => { - expect(findMedianRunStub).to.not.have.been.called; - expect(displayOutputStub).to.not.have.been.called; - }); - }); - - afterEach(() => { - runStub.restore(); - findMedianRunStub.restore(); - displayOutputStub.restore(); - }); - }); - - describe('with more then one run', () => { - beforeEach(() => { - const medianResult = dataMocks.metricsResult; - runResult = dataMocks.metricsResult; - - pwMetrics = new PWMetrics(runOptions.startWithOneRun.url, runOptions.startWithMoreThenOneRun.opts); - runStub = sinon.stub(pwMetrics, 'run', () => Promise.resolve(runResult)); - findMedianRunStub = sinon.stub(pwMetrics, 'findMedianRun', () => medianResult); - displayOutputStub = sinon.stub(pwMetrics, 'displayOutput'); - }); - - it('should call "run" method', () => { - return pwMetrics.start().then(_ => { - expect(runStub).to.have.been.calledTwice; - }); - }); - - it('should call method for calculating median results', () => { - return pwMetrics.start().then(_ => { - expect(findMedianRunStub).to.have.been.calledOnce; - expect(displayOutputStub).to.have.been.calledOnce; - }); - }); - }); - - describe('with only failed runs', () => { - beforeEach(() => { - const medianResult = dataMocks.metricsResult; - runResult = dataMocks.failedMetricResult; - - pwMetrics = new PWMetrics(runOptions.startWithOneRun.url, runOptions.startWithMoreThenOneRun.opts); - runStub = sinon.stub(pwMetrics, 'run', () => Promise.reject(runResult)); - findMedianRunStub = sinon.stub(pwMetrics, 'findMedianRun', () => medianResult); - }); - - it('should not call findMedianRun', () => { - return pwMetrics.start().then(_ => { - expect(findMedianRunStub).to.not.have.been.called; - }); - }); - }); - - describe('with one run with expectations', () => { - beforeEach(() => { - const {opts} = runOptions.startWithOneRunWithExpectations; - pwMetrics = new PWMetrics(runOptions.startWithOneRunWithExpectations.url, opts); - runStub = sinon.stub(pwMetrics, 'run', () => Promise.resolve({timings: []})); - }); - - it('should call method for calculating median results', () => { - return pwMetrics.start().catch(error => { - expect(error.message).to.contain('Expectation with errors.'); - }); - }); - }); }); describe('findMedianRun method', () => { diff --git a/test/metrics.js b/test/metrics.js index 5bc0055..dd23ab2 100644 --- a/test/metrics.js +++ b/test/metrics.js @@ -2,7 +2,7 @@ // Licensed under the Apache License, Version 2.0. See LICENSE 'use strict'; -const metrics = require('../lib/metrics'); +const {adaptMetricsData} = require('../lib/metrics/metrics-adapter'); const events = require('./fixtures/events.json'); const metricsResults = require('./fixtures/metrics-results.json'); @@ -21,14 +21,15 @@ describe('Metrics', () => { describe('prepareData', () => { it('should prepare data', () => { - expect(metrics.prepareData(events)).to.be.deep.equal(metricsResults); + expect(adaptMetricsData(events)).to.be.deep.equal(metricsResults); }); it('should log error if audit has debugString', () => { - const eventsWithDebugString = Object.assign({}, events); - eventsWithDebugString.audits['first-meaningful-paint'].debugString = 'Cannot read property \'ts\' of undefined'; - metrics.prepareData(events); - expect(logSpy).to.be.calledWith('Cannot read property \'ts\' of undefined Audit key: first-meaningful-paint'); + const {audits} = events; + audits.metrics.errorMessage = 'Cannot read property \'ts\' of undefined'; + audits.metrics.details.explanation = 'Explanation of error'; + adaptMetricsData(events); + expect(logSpy).to.be.calledWith('Cannot read property \'ts\' of undefined \n Explanation of error'); }); }); }); diff --git a/test/sheets.js b/test/sheets.js index 1c2accc..f67fa41 100644 --- a/test/sheets.js +++ b/test/sheets.js @@ -2,7 +2,7 @@ // Licensed under the Apache License, Version 2.0. See LICENSE 'use strict'; -const Sheets = require('../lib/sheets'); +const Sheets = require('../lib/sheets').Sheets; const {getMessage} = require('../lib/utils/messages'); const runOptions = require('./fixtures/run-options'); diff --git a/tsconfig.json b/tsconfig.json index 404f6f7..44c620f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,16 +1,18 @@ { "compilerOptions": { "module": "commonjs", - "target": "ES2016", - "noImplicitAny": true, + "target": "es2017", "inlineSourceMap": true, "noEmitOnError": false, - "allowJs": true + "allowJs": true, + "diagnostics": true }, - "exclude": [ - "node_modules" + "typeRoots": [ + "@types", + "node_modules/lighthouse/typings" ], "include": [ - "lib/**/*.ts" + "lib/**/*.ts", + "node_modules/lighthouse/typings/*.d.ts" ] } diff --git a/types/types.ts b/types/types.ts index 8dc69db..6bc64b4 100644 --- a/types/types.ts +++ b/types/types.ts @@ -1,31 +1,7 @@ // Copyright 2016 Google Inc. All Rights Reserved. // Licensed under the Apache License, Version 2.0. See LICENSE -interface LighthouseAudits { - [key: string]: { - rawValue: boolean | number; - displayValue: string; - debugString?: string; - score: boolean | number; - scoringMode: string; - error?: boolean; - description: string; - name: string; - helpText?: string; - extendedInfo?: { value: string }; - } -} - -interface LighthouseResults { - url: string; - audits: LighthouseAudits; - lighthouseVersion: string; - artifacts?: Object; - initialUrl: string; - generatedTime: string; -} - -interface SheetsConfig { +export interface SheetsConfig { type: string; options: { spreadsheetId: string; @@ -34,14 +10,14 @@ interface SheetsConfig { }; } -interface MainOptions { +export interface MainOptions { flags?: FeatureFlags; sheets?: SheetsConfig; expectations?: ExpectationMetrics; clientSecret?: AuthorizeCredentials; } -interface FeatureFlags { +export interface FeatureFlags { runs: number; submit: Boolean; upload: Boolean; @@ -54,41 +30,27 @@ interface FeatureFlags { showOutput: Boolean; } -interface MetricsResults { - timestamps: Timestamp[]; +export interface MetricsResults { timings: Timing[]; generatedTime: string; lighthouseVersion: string; - url: string; - initialUrl: string; + requestedUrl: string; + finalUrl: string; } -interface PWMetricsResults { +export interface PWMetricsResults { runs: MetricsResults[]; median?: MetricsResults; } -interface MetricsDefinition { - name: string; - id: string; - getTs(audits: LighthouseAudits): number; -} - -interface Timestamp { - title: string; - id: string; - timestamp: number; -} - -interface Timing { +export interface Timing { title: string, id: string; - timestamp: number; timing: number; color: string; } -interface AuthorizeCredentials { +export interface AuthorizeCredentials { installed: { client_secret: number; client_id: number; @@ -96,90 +58,62 @@ interface AuthorizeCredentials { } } -interface Oauth2Client { +export interface Oauth2Client { generateAuthUrl: Function; getToken: Function; credentials: any; } -interface GSheetsValuesToAppend { +export interface GSheetsValuesToAppend { 0: string; // lighthouseVersion 1: string; // url 2: string; // time 3: number; // TTFCP timing 4: number; // TTFMP timing - 5: number; // PSI timing - 6: number; // FV timing - 7: number; // VC100 timing - 8: number; // TTI timing - 9: number; // VC85 timing + 5: number; // SI timing + 6: number; // TTFCPUIDLE timing + 7: number; // TTI timing } -interface GSheetsAppendResultsOptions { +export interface GSheetsAppendResultsOptions { spreadsheetId: string; tableName: string; } -interface ExpectationMetrics { +export interface ExpectationMetrics { [key: string]: { warn: string; error: string; } } -interface NormalizedExpectationMetrics { +export interface NormalizedExpectationMetrics { [key: string]: { warn: number; error: number; } } -interface DriveResponse { +export interface DriveResponse { id: string } -interface PreparedAssets { +export interface PreparedAssets { traceData: Array } -//@todo after closing https://github.com/DefinitelyTyped/DefinitelyTyped/issues/13508 -interface TermWritableStream extends NodeJS.WritableStream { - columns: number; - rows: number; -} - -interface ChartOptions { +export interface ChartOptions { width: number; xlabel: string; xmin: number; xmax: number; lmargin: number; -}; +} -interface LoggerOptions { +export interface LoggerOptions { showOutput: Boolean; } -export { - Timing, - Timestamp, - SheetsConfig, - AuthorizeCredentials, - Oauth2Client, - MetricsDefinition, - MetricsResults, - LighthouseResults, - LighthouseAudits, - GSheetsValuesToAppend, - GSheetsAppendResultsOptions, - DriveResponse, - ExpectationMetrics, - NormalizedExpectationMetrics, - PreparedAssets, - MainOptions, - FeatureFlags, - TermWritableStream, - PWMetricsResults, - ChartOptions, - LoggerOptions -}; +export interface LHFlags extends LH.Flags { + chromePath: string; +} diff --git a/yarn.lock b/yarn.lock index 3cfe9d4..b9975d4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,9 +2,9 @@ # yarn lockfile v1 -"@gribnoysup/wunderbar@^2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@gribnoysup/wunderbar/-/wunderbar-2.2.0.tgz#f66e9ce67368dfc9e88c6abb13da9dc4913a1fec" +"@gribnoysup/wunderbar@^2.2.1": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@gribnoysup/wunderbar/-/wunderbar-2.2.1.tgz#a72c76b24a7dc3bb4498dd21ca62a6cda36e4818" dependencies: chalk "^2.3.2" mri "^1.1.0" @@ -20,9 +20,9 @@ version "0.3.29" resolved "https://registry.yarnpkg.com/@types/mkdirp/-/mkdirp-0.3.29.tgz#7f2ad7ec55f914482fc9b1ec4bb1ae6028d46066" -"@types/node@^6.0.45": - version "6.0.63" - resolved "https://registry.yarnpkg.com/@types/node/-/node-6.0.63.tgz#e08acbbd5946e0e95990b1c76f3ce5b7882a48eb" +"@types/node@*": + version "10.3.2" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.3.2.tgz#3840ec6c12556fdda6e0e6d036df853101d732a4" "@types/node@^9.3.0": version "9.4.6" @@ -32,20 +32,6 @@ version "0.0.28" resolved "https://registry.yarnpkg.com/@types/rimraf/-/rimraf-0.0.28.tgz#5562519bc7963caca8abf7f128cae3b594d41d06" -accepts@~1.2.12, accepts@~1.2.13: - version "1.2.13" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.2.13.tgz#e5f1f3928c6d95fd96558c36ec3d9d0de4a6ecea" - dependencies: - mime-types "~2.1.6" - negotiator "0.5.3" - -accepts@~1.3.0: - version "1.3.3" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca" - dependencies: - mime-types "~2.1.11" - negotiator "0.6.1" - acorn-jsx@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" @@ -77,12 +63,6 @@ ansi-align@^1.1.0: dependencies: string-width "^1.0.1" -ansi-align@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-2.0.0.tgz#c36aeccba563b89ceb556f3690f0b1d9e3547f7f" - dependencies: - string-width "^2.0.0" - ansi-escapes@^1.1.0: version "1.4.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" @@ -139,10 +119,6 @@ array-differ@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-1.0.0.tgz#eff52e3758249d33be402b8bb8e564bb2b5d4031" -array-find-index@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" - array-union@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" @@ -203,12 +179,6 @@ axe-core@3.0.0-beta.2: version "3.0.0-beta.2" resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-3.0.0-beta.2.tgz#82a13d371268034352bba2bcb263c5625b3e4a09" -babar@0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/babar/-/babar-0.0.3.tgz#2f394d4a5918f7e1ae9e5408e9a96f3f935ee1e2" - dependencies: - colors "~0.6.2" - babel-code-frame@^6.16.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.22.0.tgz#027620bee567a88c32561574e7fd0801d33118e4" @@ -225,30 +195,10 @@ balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" -base64-url@1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/base64-url/-/base64-url-1.2.1.tgz#199fd661702a0e7b7dcae6e0698bb089c52f6d78" - -base64-url@1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/base64-url/-/base64-url-1.3.3.tgz#f8b6c537f09a4fc58c99cb86e0b0e9c61461a20f" - base64url@2.0.0, base64url@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/base64url/-/base64url-2.0.0.tgz#eac16e03ea1438eff9423d69baa36262ed1f70bb" -basic-auth-connect@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/basic-auth-connect/-/basic-auth-connect-1.0.0.tgz#fdb0b43962ca7b40456a7c2bb48fe173da2d2122" - -basic-auth@~1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-1.0.4.tgz#030935b01de7c9b94a824b29f3fccb750d3a5290" - -batch@0.5.3: - version "0.5.3" - resolved "https://registry.yarnpkg.com/batch/-/batch-0.5.3.tgz#3f3414f380321743bfc1042f9a83ff1d5824d464" - bcrypt-pbkdf@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" @@ -259,36 +209,6 @@ beeper@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/beeper/-/beeper-1.1.1.tgz#e6d5ea8c5dad001304a70b22638447f69cb2f809" -body-parser@~1.13.3: - version "1.13.3" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.13.3.tgz#c08cf330c3358e151016a05746f13f029c97fa97" - dependencies: - bytes "2.1.0" - content-type "~1.0.1" - debug "~2.2.0" - depd "~1.0.1" - http-errors "~1.3.1" - iconv-lite "0.4.11" - on-finished "~2.3.0" - qs "4.0.0" - raw-body "~2.1.2" - type-is "~1.6.6" - -body-parser@~1.14.0: - version "1.14.2" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.14.2.tgz#1015cb1fe2c443858259581db53332f8d0cf50f9" - dependencies: - bytes "2.2.0" - content-type "~1.0.1" - debug "~2.2.0" - depd "~1.1.0" - http-errors "~1.3.1" - iconv-lite "0.4.13" - on-finished "~2.3.0" - qs "5.2.0" - raw-body "~2.1.5" - type-is "~1.6.10" - boom@2.x.x: version "2.10.1" resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" @@ -307,18 +227,6 @@ boxen@^1.0.0: term-size "^0.1.0" widest-line "^1.0.0" -boxen@^1.2.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.3.0.tgz#55c6c39a8ba58d9c61ad22cd877532deb665a20b" - dependencies: - ansi-align "^2.0.0" - camelcase "^4.0.0" - chalk "^2.0.1" - cli-boxes "^1.0.0" - string-width "^2.0.0" - term-size "^1.2.0" - widest-line "^2.0.0" - brace-expansion@^1.0.0: version "1.1.6" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9" @@ -357,18 +265,6 @@ builtin-modules@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" -bytes@2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.1.0.tgz#ac93c410e2ffc9cc7cf4b464b38289067f5e47b4" - -bytes@2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.2.0.tgz#fd35464a403f6f9117c2de3609ecff9cae000588" - -bytes@2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.4.0.tgz#7d97196f9d5baf7f6935e25985549edd2a6c2339" - caller-path@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" @@ -379,14 +275,7 @@ callsites@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" -camelcase-keys@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" - dependencies: - camelcase "^2.0.0" - map-obj "^1.0.0" - -camelcase@^2.0.0, camelcase@^2.0.1: +camelcase@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" @@ -432,7 +321,7 @@ chalk@^2.0.0: escape-string-regexp "^1.0.5" supports-color "^4.0.0" -chalk@^2.0.1, chalk@^2.3.2: +chalk@^2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.2.tgz#250dc96b07491bfd601e648d66ddf5f60c7a5c65" dependencies: @@ -465,10 +354,6 @@ chrome-launcher@^0.10.2: mkdirp "0.5.1" rimraf "^2.6.1" -ci-info@^1.0.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.1.3.tgz#710193264bb05c77b8c90d02f5aaf22216a667b2" - circular-json@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.1.tgz#be8b36aefccde8b3ca7aa2d6afc07a37242c0d2d" @@ -531,10 +416,6 @@ color-name@^1.1.1: version "1.1.3" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" -colors@~0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/colors/-/colors-0.6.2.tgz#2423fe6678ac0c5dae8852e5d0e5be08c997abcc" - combined-stream@^1.0.5, combined-stream@~1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" @@ -547,23 +428,6 @@ commander@2.9.0, commander@^2.9.0: dependencies: graceful-readlink ">= 1.0.0" -compressible@~2.0.5: - version "2.0.9" - resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.9.tgz#6daab4e2b599c2770dd9e21e7a891b1c5a755425" - dependencies: - mime-db ">= 1.24.0 < 2" - -compression@~1.5.2: - version "1.5.2" - resolved "https://registry.yarnpkg.com/compression/-/compression-1.5.2.tgz#b03b8d86e6f8ad29683cba8df91ddc6ffc77b395" - dependencies: - accepts "~1.2.12" - bytes "2.1.0" - compressible "~2.0.5" - debug "~2.2.0" - on-headers "~1.0.0" - vary "~1.0.1" - concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -598,74 +462,6 @@ configstore@^3.1.1: write-file-atomic "^2.0.0" xdg-basedir "^3.0.0" -connect-livereload@^0.5.4: - version "0.5.4" - resolved "https://registry.yarnpkg.com/connect-livereload/-/connect-livereload-0.5.4.tgz#80157d1371c9f37cc14039ab1895970d119dc3bc" - -connect-timeout@~1.6.2: - version "1.6.2" - resolved "https://registry.yarnpkg.com/connect-timeout/-/connect-timeout-1.6.2.tgz#de9a5ec61e33a12b6edaab7b5f062e98c599b88e" - dependencies: - debug "~2.2.0" - http-errors "~1.3.1" - ms "0.7.1" - on-headers "~1.0.0" - -connect@^2.30.0: - version "2.30.2" - resolved "https://registry.yarnpkg.com/connect/-/connect-2.30.2.tgz#8da9bcbe8a054d3d318d74dfec903b5c39a1b609" - dependencies: - basic-auth-connect "1.0.0" - body-parser "~1.13.3" - bytes "2.1.0" - compression "~1.5.2" - connect-timeout "~1.6.2" - content-type "~1.0.1" - cookie "0.1.3" - cookie-parser "~1.3.5" - cookie-signature "1.0.6" - csurf "~1.8.3" - debug "~2.2.0" - depd "~1.0.1" - errorhandler "~1.4.2" - express-session "~1.11.3" - finalhandler "0.4.0" - fresh "0.3.0" - http-errors "~1.3.1" - method-override "~2.3.5" - morgan "~1.6.1" - multiparty "3.3.2" - on-headers "~1.0.0" - parseurl "~1.3.0" - pause "0.1.0" - qs "4.0.0" - response-time "~2.3.1" - serve-favicon "~2.3.0" - serve-index "~1.7.2" - serve-static "~1.10.0" - type-is "~1.6.6" - utils-merge "1.0.0" - vhost "~3.0.1" - -content-type@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.2.tgz#b7d113aee7a8dd27bd21133c4dc2529df1721eed" - -cookie-parser@~1.3.5: - version "1.3.5" - resolved "https://registry.yarnpkg.com/cookie-parser/-/cookie-parser-1.3.5.tgz#9d755570fb5d17890771227a02314d9be7cf8356" - dependencies: - cookie "0.1.3" - cookie-signature "1.0.6" - -cookie-signature@1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" - -cookie@0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.1.3.tgz#e734a5c1417fce472d5aef82c381cabb64d1a435" - cookie@0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" @@ -674,10 +470,6 @@ core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" -crc@3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/crc/-/crc-3.3.0.tgz#fa622e1bc388bf257309082d6b65200ce67090ba" - create-error-class@^3.0.0: version "3.0.2" resolved "https://registry.yarnpkg.com/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6" @@ -691,14 +483,6 @@ cross-spawn-async@^2.1.1: lru-cache "^4.0.0" which "^1.2.8" -cross-spawn@^5.0.1, cross-spawn@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" - dependencies: - lru-cache "^4.0.1" - shebang-command "^1.2.0" - which "^1.2.9" - cryptiles@2.x.x: version "2.0.5" resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" @@ -709,30 +493,6 @@ crypto-random-string@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" -csrf@~3.0.0: - version "3.0.4" - resolved "https://registry.yarnpkg.com/csrf/-/csrf-3.0.4.tgz#ba01423e5b5bea7b655e38b0bdd1323954cbdaa5" - dependencies: - base64-url "1.3.3" - rndm "1.2.0" - tsscmp "1.0.5" - uid-safe "2.1.3" - -csurf@~1.8.3: - version "1.8.3" - resolved "https://registry.yarnpkg.com/csurf/-/csurf-1.8.3.tgz#23f2a13bf1d8fce1d0c996588394442cba86a56a" - dependencies: - cookie "0.1.3" - cookie-signature "1.0.6" - csrf "~3.0.0" - http-errors "~1.3.1" - -currently-unhandled@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" - dependencies: - array-find-index "^1.0.1" - d@^0.1.1, d@~0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/d/-/d-0.1.1.tgz#da184c535d18d8ee7ba2aa229b914009fae11309" @@ -749,25 +509,19 @@ dateformat@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-2.0.0.tgz#2743e3abb5c3fc2462e527dca445e04e9f4dee17" -debug@2.2.0, debug@^2.1.1, debug@~2.2.0: +debug@2.2.0, debug@^2.1.1: version "2.2.0" resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" dependencies: ms "0.7.1" -debug@2.3.3: - version "2.3.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.3.3.tgz#40c453e67e6e13c901ddec317af8986cda9eff8c" - dependencies: - ms "0.7.2" - debug@^2.6.8: version "2.6.8" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc" dependencies: ms "2.0.0" -decamelize@^1.1.1, decamelize@^1.1.2: +decamelize@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -807,28 +561,20 @@ delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" -depd@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.0.1.tgz#80aec64c9d6d97e65cc2a9caa93c0aa6abf73aaa" - -depd@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.0.tgz#e1bd82c6aab6ced965b97b88b17ed3e528ca18c3" - deprecated@^0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/deprecated/-/deprecated-0.0.1.tgz#f9c9af5464afa1e7a971458a8bdef2aa94d5bb19" -destroy@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" - detect-file@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-0.1.0.tgz#4935dedfd9488648e006b0129566e9386711ea63" dependencies: fs-exists-sync "^0.1.0" +devtools-protocol@^0.0.589586: + version "0.0.589586" + resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.589586.tgz#150c451ff828600c495ae5ba82bbd4bfc7a86893" + devtools-timeline-model@1.1.6: version "1.1.6" resolved "https://registry.yarnpkg.com/devtools-timeline-model/-/devtools-timeline-model-1.1.6.tgz#7be51a73b55d727b597bb30dd1ed2e8e210639a5" @@ -863,10 +609,6 @@ duplexer3@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" -duplexer@~0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" - ecc-jsbn@~0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" @@ -880,10 +622,6 @@ ecdsa-sig-formatter@1.0.9: base64url "^2.0.0" safe-buffer "^5.0.1" -ee-first@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - end-of-stream@~0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-0.1.5.tgz#8e177206c3c80837d85632e8b9359dfe8b2f6eaf" @@ -896,13 +634,6 @@ error-ex@^1.2.0: dependencies: is-arrayish "^0.2.1" -errorhandler@~1.4.2: - version "1.4.3" - resolved "https://registry.yarnpkg.com/errorhandler/-/errorhandler-1.4.3.tgz#b7b70ed8f359e9db88092f2d20c0f831420ad83f" - dependencies: - accepts "~1.3.0" - escape-html "~1.0.3" - es5-ext@^0.10.7, es5-ext@^0.10.8, es5-ext@~0.10.11, es5-ext@~0.10.2, es5-ext@~0.10.7: version "0.10.12" resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.12.tgz#aa84641d4db76b62abba5e45fd805ecbab140047" @@ -955,14 +686,6 @@ es6-weak-map@^2.0.1: es6-iterator "2" es6-symbol "3" -escape-html@1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.2.tgz#d77d32fa98e38c2f41ae85e9278e0e0e6ba1022c" - -escape-html@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" - escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" @@ -1030,9 +753,9 @@ esprima@^3.1.1: version "3.1.3" resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" -esprima@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" +esprima@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" esrecurse@^4.1.0: version "4.1.0" @@ -1053,10 +776,6 @@ esutils@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" -etag@~1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/etag/-/etag-1.7.0.tgz#03d30b5f67dd6e632d2945d30d6652731a34d5d8" - event-emitter@~0.3.4: version "0.3.4" resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.4.tgz#8d63ddfb4cfe1fae3b32ca265c4c720222080bb5" @@ -1064,18 +783,6 @@ event-emitter@~0.3.4: d "~0.1.1" es5-ext "~0.10.7" -event-stream@^3.3.2: - version "3.3.4" - resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571" - dependencies: - duplexer "~0.1.1" - from "~0" - map-stream "~0.1.0" - pause-stream "0.0.11" - split "0.3" - stream-combiner "~0.0.4" - through "~2.3.1" - execa@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/execa/-/execa-0.4.0.tgz#4eb6467a36a095fabb2970ff9d5e3fb7bce6ebc3" @@ -1087,18 +794,6 @@ execa@^0.4.0: path-key "^1.0.0" strip-eof "^1.0.0" -execa@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" - dependencies: - cross-spawn "^5.0.1" - get-stream "^3.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - exit-hook@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" @@ -1121,20 +816,6 @@ expand-tilde@^1.2.1, expand-tilde@^1.2.2: dependencies: os-homedir "^1.0.1" -express-session@~1.11.3: - version "1.11.3" - resolved "https://registry.yarnpkg.com/express-session/-/express-session-1.11.3.tgz#5cc98f3f5ff84ed835f91cbf0aabd0c7107400af" - dependencies: - cookie "0.1.3" - cookie-signature "1.0.6" - crc "3.3.0" - debug "~2.2.0" - depd "~1.0.1" - on-headers "~1.0.0" - parseurl "~1.3.0" - uid-safe "~2.0.0" - utils-merge "1.0.0" - extend@^3.0.0, extend@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4" @@ -1168,12 +849,6 @@ fast-levenshtein@~2.0.4: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" -faye-websocket@~0.10.0: - version "0.10.0" - resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" - dependencies: - websocket-driver ">=0.5.1" - figures@^1.3.5: version "1.7.0" resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" @@ -1208,15 +883,6 @@ fill-range@^2.1.0: repeat-element "^1.1.2" repeat-string "^1.5.2" -finalhandler@0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-0.4.0.tgz#965a52d9e8d05d2b857548541fb89b53a2497d9b" - dependencies: - debug "~2.2.0" - escape-html "1.0.2" - on-finished "~2.3.0" - unpipe "~1.0.0" - find-index@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/find-index/-/find-index-0.1.1.tgz#675d358b2ca3892d795a1ab47232f8b6e2e0dde4" @@ -1294,26 +960,10 @@ formatio@1.1.1: dependencies: samsam "~1.1" -fresh@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.3.0.tgz#651f838e22424e7566de161d8358caa199f83d4f" - -from@~0: - version "0.1.3" - resolved "https://registry.yarnpkg.com/from/-/from-0.1.3.tgz#ef63ac2062ac32acf7862e0d40b44b896f22f3bc" - fs-exists-sync@^0.1.0: version "0.1.0" resolved "http://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add" -fs-extra@^4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94" - dependencies: - graceful-fs "^4.1.2" - jsonfile "^4.0.0" - universalify "^0.1.0" - fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -1338,10 +988,6 @@ get-caller-file@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" -get-stdin@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" - get-stream@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" @@ -1427,12 +1073,6 @@ glob@~3.1.21: inherits "1" minimatch "~0.2.11" -global-dirs@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445" - dependencies: - ini "^1.3.4" - global-modules@^0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-0.2.3.tgz#ea5a3bed42c6d6ce995a4f8a1269b5dae223828d" @@ -1523,7 +1163,7 @@ graceful-fs@^3.0.0: dependencies: natives "^1.1.0" -graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6: +graceful-fs@^4.1.11, graceful-fs@^4.1.2: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" @@ -1548,17 +1188,7 @@ gtoken@^1.2.1: mime "^1.2.11" request "^2.72.0" -gulp-connect@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/gulp-connect/-/gulp-connect-5.0.0.tgz#f2fdf306ae911468368c2285f2d782f13eddaf4e" - dependencies: - connect "^2.30.0" - connect-livereload "^0.5.4" - event-stream "^3.3.2" - gulp-util "^3.0.6" - tiny-lr "^0.2.1" - -gulp-util@^3.0.0, gulp-util@^3.0.6: +gulp-util@^3.0.0: version "3.0.8" resolved "https://registry.yarnpkg.com/gulp-util/-/gulp-util-3.0.8.tgz#0054e1e744502e27c04c187c3ecc505dd54bbb4f" dependencies: @@ -1661,13 +1291,6 @@ hosted-git-info@^2.1.4: version "2.2.0" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.2.0.tgz#7a0d097863d886c0fabbdcd37bf1758d8becf8a5" -http-errors@~1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.3.1.tgz#197e22cdebd4198585e8694ef6786197b91ed942" - dependencies: - inherits "~2.0.1" - statuses "1" - http-link-header@^0.8.0: version "0.8.0" resolved "https://registry.yarnpkg.com/http-link-header/-/http-link-header-0.8.0.tgz#a22b41a0c9b1e2d8fac1bf1b697c6bd532d5f5e4" @@ -1680,14 +1303,6 @@ http-signature@~1.1.0: jsprim "^1.2.2" sshpk "^1.7.0" -iconv-lite@0.4.11: - version "0.4.11" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.11.tgz#2ecb42fd294744922209a2e7c404dac8793d8ade" - -iconv-lite@0.4.13: - version "0.4.13" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2" - iconv-lite@^0.4.17: version "0.4.19" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" @@ -1700,20 +1315,10 @@ image-ssim@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/image-ssim/-/image-ssim-0.2.0.tgz#83b42c7a2e6e4b85505477fe6917f5dbc56420e5" -import-lazy@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" - imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" -indent-string@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" - dependencies: - repeating "^2.0.0" - inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" @@ -1778,6 +1383,16 @@ interpret@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.1.tgz#d579fb7f693b858004947af39fa0db49f795602c" +intl-messageformat-parser@1.4.0, intl-messageformat-parser@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/intl-messageformat-parser/-/intl-messageformat-parser-1.4.0.tgz#b43d45a97468cadbe44331d74bb1e8dea44fc075" + +intl-messageformat@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-2.2.0.tgz#345bcd46de630b7683330c2e52177ff5eab484fc" + dependencies: + intl-messageformat-parser "1.4.0" + invert-kv@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" @@ -1803,12 +1418,6 @@ is-builtin-module@^1.0.0: dependencies: builtin-modules "^1.0.0" -is-ci@^1.0.10: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.1.0.tgz#247e4162e7860cebbdaf30b774d6b0ac7dcfe7a5" - dependencies: - ci-info "^1.0.0" - is-dotfile@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d" @@ -1827,12 +1436,6 @@ is-extglob@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" -is-finite@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" - dependencies: - number-is-nan "^1.0.0" - is-fullwidth-code-point@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" @@ -1849,13 +1452,6 @@ is-glob@^2.0.0, is-glob@^2.0.1: dependencies: is-extglob "^1.0.0" -is-installed-globally@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.1.0.tgz#0dfd98f5a9111716dd535dda6492f67bf3d25a80" - dependencies: - global-dirs "^0.1.0" - is-path-inside "^1.0.0" - is-my-json-valid@^2.10.0, is-my-json-valid@^2.12.4: version "2.15.0" resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.15.0.tgz#936edda3ca3c211fd98f3b2d3e08da43f7b2915b" @@ -1969,10 +1565,6 @@ isexe@^1.1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/isexe/-/isexe-1.1.2.tgz#36f3e22e60750920f5e7241a476a8c6a42275ad0" -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - isobject@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" @@ -2030,12 +1622,6 @@ json3@3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" -jsonfile@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" - optionalDependencies: - graceful-fs "^4.1.6" - jsonify@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" @@ -2118,42 +1704,39 @@ lighthouse-logger@^1.0.0: dependencies: debug "^2.6.8" -lighthouse@^2.9.4: - version "2.9.4" - resolved "https://registry.yarnpkg.com/lighthouse/-/lighthouse-2.9.4.tgz#01aa469abaad1cfc06814293b3f6b6ba8971320f" +lighthouse@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lighthouse/-/lighthouse-3.1.1.tgz#6af0489b3bca190cfd6a714dd48681adc19149e6" dependencies: axe-core "3.0.0-beta.2" chrome-devtools-frontend "1.0.422034" chrome-launcher "^0.10.2" configstore "^3.1.1" devtools-timeline-model "1.1.6" - esprima "^4.0.0" + esprima "^4.0.1" http-link-header "^0.8.0" inquirer "^3.3.0" + intl-messageformat "^2.2.0" + intl-messageformat-parser "^1.4.0" jpeg-js "0.1.2" js-library-detector "^4.3.1" lighthouse-logger "^1.0.0" lodash.isequal "^4.5.0" + lookup-closest-locale "6.0.4" metaviewport-parser "0.2.0" mkdirp "0.5.1" opn "4.0.2" parse-cache-control "1.0.1" - patch-package "^5.1.1" raven "^2.2.1" rimraf "^2.6.1" - robots-parser "^1.0.2" + robots-parser "^2.0.1" semver "^5.3.0" - speedline "1.3.0" + speedline-core "1.4.0" update-notifier "^2.1.0" - whatwg-url "^6.3.0" ws "3.3.2" yargs "3.32.0" yargs-parser "7.0.0" -livereload-js@^2.2.0: - version "2.2.2" - resolved "https://registry.yarnpkg.com/livereload-js/-/livereload-js-2.2.2.tgz#6c87257e648ab475bc24ea257457edcc1f8d0bc2" - load-json-file@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" @@ -2277,10 +1860,6 @@ lodash.restparam@^3.0.0: version "3.6.1" resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" -lodash.sortby@^4.7.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" - lodash.template@^3.0.0: version "3.6.2" resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-3.6.2.tgz#f8cdecc6169a255be9098ae8b0c53d378931d14f" @@ -2314,12 +1893,9 @@ lolex@1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/lolex/-/lolex-1.3.2.tgz#7c3da62ffcb30f0f5a80a2566ca24e45d8a01f31" -loud-rejection@^1.0.0, loud-rejection@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" - dependencies: - currently-unhandled "^0.4.1" - signal-exit "^3.0.0" +lookup-closest-locale@6.0.4: + version "6.0.4" + resolved "https://registry.yarnpkg.com/lookup-closest-locale/-/lookup-closest-locale-6.0.4.tgz#1279fed7546a601647bbc980f64423ee990a8590" lowercase-keys@^1.0.0: version "1.0.0" @@ -2336,13 +1912,6 @@ lru-cache@^4.0.0: pseudomap "^1.0.1" yallist "^2.0.0" -lru-cache@^4.0.1: - version "4.1.2" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.2.tgz#45234b2e6e2f2b33da125624c4664929a0224c3f" - dependencies: - pseudomap "^1.0.2" - yallist "^2.1.2" - lsmod@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/lsmod/-/lsmod-1.0.0.tgz#9a00f76dca36eb23fa05350afe1b585d4299e64b" @@ -2357,50 +1926,10 @@ map-cache@^0.2.0: version "0.2.2" resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" -map-obj@^1.0.0, map-obj@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" - -map-stream@~0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.1.0.tgz#e56aa94c4c8055a16404a0674b78f215f7c8e194" - -media-typer@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" - -meow@^3.7.0: - version "3.7.0" - resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" - dependencies: - camelcase-keys "^2.0.0" - decamelize "^1.1.2" - loud-rejection "^1.0.0" - map-obj "^1.0.1" - minimist "^1.1.3" - normalize-package-data "^2.3.4" - object-assign "^4.0.1" - read-pkg-up "^1.0.1" - redent "^1.0.0" - trim-newlines "^1.0.0" - metaviewport-parser@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/metaviewport-parser/-/metaviewport-parser-0.2.0.tgz#535c3ce1ccf6223a5025fddc6a1c36505f7e7db1" -method-override@~2.3.5: - version "2.3.7" - resolved "https://registry.yarnpkg.com/method-override/-/method-override-2.3.7.tgz#8e1d47ac480fb0cd8777083f11c896901166b2e5" - dependencies: - debug "2.3.3" - methods "~1.1.2" - parseurl "~1.3.1" - vary "~1.1.0" - -methods@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" - micro-promisify@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/micro-promisify/-/micro-promisify-0.1.1.tgz#071da590b4956560dedf4aae7044729c1a28902d" @@ -2423,17 +1952,17 @@ micromatch@^2.3.7: parse-glob "^3.0.4" regex-cache "^0.4.2" -"mime-db@>= 1.24.0 < 2", mime-db@~1.26.0: +mime-db@~1.26.0: version "1.26.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.26.0.tgz#eaffcd0e4fc6935cf8134da246e2e6c35305adff" -mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.13, mime-types@~2.1.6, mime-types@~2.1.7, mime-types@~2.1.9: +mime-types@^2.1.12, mime-types@~2.1.7: version "2.1.14" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.14.tgz#f7ef7d97583fcaf3b7d282b6f8b5679dab1e94ee" dependencies: mime-db "~1.26.0" -mime@1.3.4, mime@^1.2.11: +mime@^1.2.11: version "1.3.4" resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" @@ -2470,7 +1999,7 @@ minimist@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" -minimist@^1.1.0, minimist@^1.1.3, minimist@^1.2.0: +minimist@^1.1.0, minimist@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" @@ -2496,16 +2025,6 @@ mocha@^3.2.0: mkdirp "0.5.1" supports-color "3.1.2" -morgan@~1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.6.1.tgz#5fd818398c6819cba28a7cd6664f292fe1c0bbf2" - dependencies: - basic-auth "~1.0.3" - debug "~2.2.0" - depd "~1.0.1" - on-finished "~2.3.0" - on-headers "~1.0.0" - mri@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/mri/-/mri-1.1.0.tgz#5c0a3f29c8ccffbbb1ec941dcec09d71fa32f36a" @@ -2514,21 +2033,10 @@ ms@0.7.1: version "0.7.1" resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" -ms@0.7.2: - version "0.7.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" - ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" -multiparty@3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/multiparty/-/multiparty-3.3.2.tgz#35de6804dc19643e5249f3d3e3bdc6c8ce301d3f" - dependencies: - readable-stream "~1.1.9" - stream-counter "~0.2.0" - multipipe@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/multipipe/-/multipipe-0.1.2.tgz#2a8f2ddf70eed564dff2d57f1e1a137d9f05078b" @@ -2551,19 +2059,11 @@ natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" -negotiator@0.5.3: - version "0.5.3" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.5.3.tgz#269d5c476810ec92edbe7b6c2f28316384f9a7e8" - -negotiator@0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" - node-forge@^0.6.46: version "0.6.49" resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.6.49.tgz#f1ee95d5d74623938fe19d698aa5a26d54d2f60f" -normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: +normalize-package-data@^2.3.2: version "2.3.5" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.3.5.tgz#8d924f142960e1777e7ffe170543631cc7cb02df" dependencies: @@ -2582,12 +2082,6 @@ npm-run-path@^1.0.0: dependencies: path-key "^1.0.0" -npm-run-path@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" - dependencies: - path-key "^2.0.0" - number-is-nan@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" @@ -2615,16 +2109,6 @@ object.omit@^2.0.0: for-own "^0.1.4" is-extendable "^0.1.1" -on-finished@~2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" - dependencies: - ee-first "1.1.1" - -on-headers@~1.0.0, on-headers@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" - once@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -2687,14 +2171,10 @@ os-locale@^1.4.0: dependencies: lcid "^1.0.0" -os-tmpdir@~1.0.1, os-tmpdir@~1.0.2: +os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" -p-finally@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" - package-json@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/package-json/-/package-json-4.0.1.tgz#8869a0401253661c4c4ca3da6c2121ed555f5eed" @@ -2741,23 +2221,6 @@ parse-passwd@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" -parseurl@~1.3.0, parseurl@~1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.1.tgz#c8ab8c9223ba34888aa64a297b28853bec18da56" - -patch-package@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/patch-package/-/patch-package-5.1.1.tgz#e5e82fe08bed760b773b8eb73a7bcb7c1634f802" - dependencies: - chalk "^1.1.3" - cross-spawn "^5.1.0" - fs-extra "^4.0.1" - minimist "^1.2.0" - rimraf "^2.6.1" - slash "^1.0.0" - tmp "^0.0.31" - update-notifier "^2.2.0" - path-exists@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" @@ -2776,10 +2239,6 @@ path-key@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/path-key/-/path-key-1.0.0.tgz#5d53d578019646c0d68800db4e146e6bdc2ac7af" -path-key@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - path-root-regex@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/path-root-regex/-/path-root-regex-0.1.2.tgz#bfccdc8df5b12dc52c8b43ec38d18d72c04ba96d" @@ -2798,16 +2257,6 @@ path-type@^1.0.0: pify "^2.0.0" pinkie-promise "^2.0.0" -pause-stream@0.0.11: - version "0.0.11" - resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445" - dependencies: - through "~2.3" - -pause@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/pause/-/pause-0.1.0.tgz#ebc8a4a8619ff0b8a81ac1513c3434ff469fdb74" - pify@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" @@ -2854,7 +2303,7 @@ progress@^1.1.8: version "1.1.8" resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" -pseudomap@^1.0.1, pseudomap@^1.0.2: +pseudomap@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" @@ -2862,30 +2311,10 @@ punycode@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" -punycode@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.0.tgz#5f863edc89b96db09074bad7947bf09056ca4e7d" - -qs@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-4.0.0.tgz#c31d9b74ec27df75e543a86c78728ed8d4623607" - -qs@5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-5.2.0.tgz#a9f31142af468cb72b25b30136ba2456834916be" - -qs@~5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-5.1.0.tgz#4d932e5c7ea411cca76a312d39a606200fd50cd9" - qs@~6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.0.tgz#f403b264f23bc01228c74131b407f18d5ea5d442" -random-bytes@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/random-bytes/-/random-bytes-1.0.0.tgz#4f68a1dc0ae58bd3fb95848c30324db75d64360b" - randomatic@^1.1.3: version "1.1.6" resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.6.tgz#110dcabff397e9dcff7c0789ccc0a49adf1ec5bb" @@ -2897,10 +2326,6 @@ randomcolor@^0.5.3: version "0.5.3" resolved "https://registry.yarnpkg.com/randomcolor/-/randomcolor-0.5.3.tgz#7f90f2f2a7f6d5a52232161eeaeeaea9ac3b5815" -range-parser@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.0.3.tgz#6872823535c692e2c2a0103826afd82c2e0ff175" - raven@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/raven/-/raven-2.2.1.tgz#57c7fbe68a80147ec527def3d7c01575cf948fe3" @@ -2911,14 +2336,6 @@ raven@^2.2.1: timed-out "4.0.1" uuid "3.0.0" -raw-body@~2.1.2, raw-body@~2.1.5: - version "2.1.7" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.1.7.tgz#adfeace2e4fb3098058014d08c072dcc59758774" - dependencies: - bytes "2.4.0" - iconv-lite "0.4.13" - unpipe "1.0.0" - rc@^1.0.1, rc@^1.1.6: version "1.2.1" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.1.tgz#2e03e8e42ee450b8cb3dce65be1bf8974e1dfd95" @@ -2964,7 +2381,7 @@ readable-stream@^2.1.5, readable-stream@^2.2.2: string_decoder "~0.10.x" util-deprecate "~1.0.1" -readable-stream@~1.1.8, readable-stream@~1.1.9: +readable-stream@~1.1.9: version "1.1.14" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" dependencies: @@ -2991,13 +2408,6 @@ rechoir@^0.6.2: dependencies: resolve "^1.1.6" -redent@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" - dependencies: - indent-string "^2.1.0" - strip-indent "^1.0.1" - regex-cache@^0.4.2: version "0.4.3" resolved "http://registry.npmjs.org/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145" @@ -3025,12 +2435,6 @@ repeat-string@^1.5.2: version "1.6.1" resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" -repeating@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" - dependencies: - is-finite "^1.0.0" - replace-ext@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-0.0.1.tgz#29bbd92078a739f0bcce2b4ee41e837953522924" @@ -3090,13 +2494,6 @@ resolve@1.1.7, resolve@^1.1.6, resolve@^1.1.7: version "1.1.7" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" -response-time@~2.3.1: - version "2.3.2" - resolved "https://registry.yarnpkg.com/response-time/-/response-time-2.3.2.tgz#ffa71bab952d62f7c1d49b7434355fbc68dffc5a" - dependencies: - depd "~1.1.0" - on-headers "~1.0.1" - restore-cursor@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" @@ -3121,13 +2518,9 @@ rimraf@^2.6.1: dependencies: glob "^7.0.5" -rndm@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/rndm/-/rndm-1.2.0.tgz#f33fe9cfb52bbfd520aa18323bc65db110a1b76c" - -robots-parser@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/robots-parser/-/robots-parser-1.0.2.tgz#9ebe25b1a2c52773cbe6f1dbe90ebc9518089009" +robots-parser@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/robots-parser/-/robots-parser-2.1.0.tgz#d16b78ce34e861ab6afbbf0aac65974dbe01566e" run-async@^0.1.0: version "0.1.0" @@ -3185,70 +2578,14 @@ semver@^5.3.0: version "5.4.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" -send@0.13.2: - version "0.13.2" - resolved "https://registry.yarnpkg.com/send/-/send-0.13.2.tgz#765e7607c8055452bba6f0b052595350986036de" - dependencies: - debug "~2.2.0" - depd "~1.1.0" - destroy "~1.0.4" - escape-html "~1.0.3" - etag "~1.7.0" - fresh "0.3.0" - http-errors "~1.3.1" - mime "1.3.4" - ms "0.7.1" - on-finished "~2.3.0" - range-parser "~1.0.3" - statuses "~1.2.1" - sequencify@~0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/sequencify/-/sequencify-0.0.7.tgz#90cff19d02e07027fd767f5ead3e7b95d1e7380c" -serve-favicon@~2.3.0: - version "2.3.2" - resolved "https://registry.yarnpkg.com/serve-favicon/-/serve-favicon-2.3.2.tgz#dd419e268de012ab72b319d337f2105013f9381f" - dependencies: - etag "~1.7.0" - fresh "0.3.0" - ms "0.7.2" - parseurl "~1.3.1" - -serve-index@~1.7.2: - version "1.7.3" - resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.7.3.tgz#7a057fc6ee28dc63f64566e5fa57b111a86aecd2" - dependencies: - accepts "~1.2.13" - batch "0.5.3" - debug "~2.2.0" - escape-html "~1.0.3" - http-errors "~1.3.1" - mime-types "~2.1.9" - parseurl "~1.3.1" - -serve-static@~1.10.0: - version "1.10.3" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.10.3.tgz#ce5a6ecd3101fed5ec09827dac22a9c29bfb0535" - dependencies: - escape-html "~1.0.3" - parseurl "~1.3.1" - send "0.13.2" - set-blocking@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" -shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - dependencies: - shebang-regex "^1.0.0" - -shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - shelljs@^0.7.5: version "0.7.7" resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.7.tgz#b2f5c77ef97148f4b4f6e22682e10bba8667cff1" @@ -3261,7 +2598,7 @@ sigmund@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" -signal-exit@^3.0.0, signal-exit@^3.0.2: +signal-exit@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" @@ -3278,10 +2615,6 @@ sinon@^1.17.7: samsam "1.1.2" util ">=0.10.3 <1" -slash@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" - slice-ansi@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" @@ -3314,21 +2647,13 @@ spdx-license-ids@^1.0.2: version "1.2.2" resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" -speedline@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/speedline/-/speedline-1.3.0.tgz#201c458ca7aba2ac847fe5860c1a92966aaed3a9" +speedline-core@1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/speedline-core/-/speedline-core-1.4.0.tgz#884831eaef66ddc928dd7d4c9e844c5d28bad7db" dependencies: - babar "0.0.3" + "@types/node" "*" image-ssim "^0.2.0" jpeg-js "^0.1.2" - loud-rejection "^1.6.0" - meow "^3.7.0" - -split@0.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/split/-/split-0.3.3.tgz#cd0eea5e63a211dfff7eb0f091c4133e2d0dd28f" - dependencies: - through "2" sprintf-js@~1.0.2: version "1.0.3" @@ -3353,30 +2678,10 @@ stack-trace@0.0.9: version "0.0.9" resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.9.tgz#a8f6eaeca90674c333e7c43953f275b451510695" -statuses@1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" - -statuses@~1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.2.1.tgz#dded45cc18256d51ed40aec142489d5c61026d28" - -stream-combiner@~0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.0.4.tgz#4d5e433c185261dde623ca3f44c586bcf5c4ad14" - dependencies: - duplexer "~0.1.1" - stream-consume@~0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/stream-consume/-/stream-consume-0.1.0.tgz#a41ead1a6d6081ceb79f65b061901b6d8f3d1d0f" -stream-counter@~0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/stream-counter/-/stream-counter-0.2.0.tgz#ded266556319c8b0e222812b9cf3b26fa7d947de" - dependencies: - readable-stream "~1.1.8" - string-template@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/string-template/-/string-template-1.0.0.tgz#9e9f2233dc00f218718ec379a28a5673ecca8b96" @@ -3396,7 +2701,7 @@ string-width@^2.0.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^3.0.0" -string-width@^2.1.0, string-width@^2.1.1: +string-width@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" dependencies: @@ -3444,12 +2749,6 @@ strip-eof@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" -strip-indent@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" - dependencies: - get-stdin "^4.0.1" - strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" @@ -3493,12 +2792,6 @@ term-size@^0.1.0: dependencies: execa "^0.4.0" -term-size@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/term-size/-/term-size-1.2.0.tgz#458b83887f288fc56d6fffbfad262e26638efa69" - dependencies: - execa "^0.7.0" - text-table@~0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" @@ -3517,7 +2810,7 @@ through2@^2.0.0: readable-stream "^2.1.5" xtend "~4.0.1" -through@2, through@^2.3.6, through@~2.3, through@~2.3.1: +through@^2.3.6: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" @@ -3535,23 +2828,6 @@ timed-out@4.0.1, timed-out@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" -tiny-lr@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/tiny-lr/-/tiny-lr-0.2.1.tgz#b3fdba802e5d56a33c2f6f10794b32e477ac729d" - dependencies: - body-parser "~1.14.0" - debug "~2.2.0" - faye-websocket "~0.10.0" - livereload-js "^2.2.0" - parseurl "~1.3.0" - qs "~5.1.0" - -tmp@^0.0.31: - version "0.0.31" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.31.tgz#8f38ab9438e17315e5dbd8b3657e8bfb277ae4a7" - dependencies: - os-tmpdir "~1.0.1" - tmp@^0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" @@ -3564,24 +2840,10 @@ tough-cookie@~2.3.0: dependencies: punycode "^1.4.1" -tr46@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" - dependencies: - punycode "^2.1.0" - -trim-newlines@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" - tryit@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb" -tsscmp@1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/tsscmp/-/tsscmp-1.0.5.tgz#7dc4a33af71581ab4337da91d85ca5427ebd9a97" - tunnel-agent@~0.4.1: version "0.4.3" resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" @@ -3604,33 +2866,13 @@ type-detect@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-1.0.0.tgz#762217cc06db258ec48908a1298e8b95121e8ea2" -type-is@~1.6.10, type-is@~1.6.6: - version "1.6.14" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.14.tgz#e219639c17ded1ca0789092dd54a03826b817cb2" - dependencies: - media-typer "0.3.0" - mime-types "~2.1.13" - typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" -typescript@^2.0.3: - version "2.3.0" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.3.0.tgz#2e63e09284392bc8158a2444c33e2093795c0418" - -uid-safe@2.1.3: - version "2.1.3" - resolved "https://registry.yarnpkg.com/uid-safe/-/uid-safe-2.1.3.tgz#077e264a00b3187936b270bb7376a26473631071" - dependencies: - base64-url "1.3.3" - random-bytes "~1.0.0" - -uid-safe@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/uid-safe/-/uid-safe-2.0.0.tgz#a7f3c6ca64a1f6a5d04ec0ef3e4c3d5367317137" - dependencies: - base64-url "1.2.1" +typescript@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.0.1.tgz#43738f29585d3a87575520a4b93ab6026ef11fdb" ultron@~1.1.0: version "1.1.1" @@ -3650,14 +2892,6 @@ unique-string@^1.0.0: dependencies: crypto-random-string "^1.0.0" -universalify@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.1.tgz#fa71badd4437af4c148841e3b3b165f9e9e590b7" - -unpipe@1.0.0, unpipe@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" - unzip-response@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97" @@ -3675,21 +2909,6 @@ update-notifier@^2.1.0: semver-diff "^2.0.0" xdg-basedir "^3.0.0" -update-notifier@^2.2.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-2.4.0.tgz#f9b4c700fbfd4ec12c811587258777d563d8c866" - dependencies: - boxen "^1.2.1" - chalk "^2.0.1" - configstore "^3.0.0" - import-lazy "^2.1.0" - is-ci "^1.0.10" - is-installed-globally "^0.1.0" - is-npm "^1.0.0" - latest-version "^3.0.0" - semver-diff "^2.0.0" - xdg-basedir "^3.0.0" - url-parse-lax@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" @@ -3716,10 +2935,6 @@ util-deprecate@~1.0.1: dependencies: inherits "2.0.1" -utils-merge@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8" - uuid@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.0.tgz#6728fc0459c450d796a99c31837569bdf672d728" @@ -3741,24 +2956,12 @@ validate-npm-package-license@^3.0.1: spdx-correct "~1.0.0" spdx-expression-parse "~1.0.0" -vary@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/vary/-/vary-1.0.1.tgz#99e4981566a286118dfb2b817357df7993376d10" - -vary@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.0.tgz#e1e5affbbd16ae768dd2674394b9ad3022653140" - verror@1.3.6: version "1.3.6" resolved "https://registry.yarnpkg.com/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c" dependencies: extsprintf "1.0.2" -vhost@~3.0.1: - version "3.0.2" - resolved "https://registry.yarnpkg.com/vhost/-/vhost-3.0.2.tgz#2fb1decd4c466aa88b0f9341af33dc1aff2478d5" - vinyl-fs@^0.3.0: version "0.3.14" resolved "https://registry.yarnpkg.com/vinyl-fs/-/vinyl-fs-0.3.14.tgz#9a6851ce1cac1c1cea5fe86c0931d620c2cfa9e6" @@ -3793,28 +2996,6 @@ wcwidth@^1.0.1: dependencies: defaults "^1.0.3" -webidl-conversions@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" - -websocket-driver@>=0.5.1: - version "0.6.5" - resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.6.5.tgz#5cb2556ceb85f4373c6d8238aa691c8454e13a36" - dependencies: - websocket-extensions ">=0.1.1" - -websocket-extensions@>=0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.1.tgz#76899499c184b6ef754377c2dbb0cd6cb55d29e7" - -whatwg-url@^6.3.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-6.4.0.tgz#08fdf2b9e872783a7a1f6216260a1d66cc722e08" - dependencies: - lodash.sortby "^4.7.0" - tr46 "^1.0.0" - webidl-conversions "^4.0.1" - which-module@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" @@ -3825,24 +3006,12 @@ which@^1.2.12, which@^1.2.8: dependencies: isexe "^1.1.1" -which@^1.2.9: - version "1.3.0" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a" - dependencies: - isexe "^2.0.0" - widest-line@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-1.0.0.tgz#0c09c85c2a94683d0d7eaf8ee097d564bf0e105c" dependencies: string-width "^1.0.1" -widest-line@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-2.0.0.tgz#0142a4e8a243f8882c0233aa0e0281aa76152273" - dependencies: - string-width "^2.1.1" - window-size@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.4.tgz#f8e1aa1ee5a53ec5bf151ffa09742a6ad7697876" @@ -3904,7 +3073,7 @@ y18n@^3.2.0, y18n@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" -yallist@^2.0.0, yallist@^2.1.2: +yallist@^2.0.0: version "2.1.2" resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"